aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/traccar/api')
-rw-r--r--src/main/java/org/traccar/api/BaseObjectResource.java105
-rw-r--r--src/main/java/org/traccar/api/BaseResource.java12
-rw-r--r--src/main/java/org/traccar/api/ExtendedObjectResource.java55
-rw-r--r--src/main/java/org/traccar/api/MediaFilter.java6
-rw-r--r--src/main/java/org/traccar/api/SimpleObjectResource.java36
-rw-r--r--src/main/java/org/traccar/api/resource/AttributeResource.java68
-rw-r--r--src/main/java/org/traccar/api/resource/DeviceResource.java4
-rw-r--r--src/main/java/org/traccar/api/resource/EventResource.java18
-rw-r--r--src/main/java/org/traccar/api/resource/NotificationResource.java3
-rw-r--r--src/main/java/org/traccar/api/resource/PositionResource.java2
-rw-r--r--src/main/java/org/traccar/api/resource/ReportResource.java20
-rw-r--r--src/main/java/org/traccar/api/security/PermissionsService.java146
12 files changed, 297 insertions, 178 deletions
diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java
index 22756f62a..07c74449c 100644
--- a/src/main/java/org/traccar/api/BaseObjectResource.java
+++ b/src/main/java/org/traccar/api/BaseObjectResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,70 +16,44 @@
*/
package org.traccar.api;
-import java.sql.SQLException;
-import java.util.Set;
-
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.core.Response;
-
import org.traccar.Context;
import org.traccar.database.BaseObjectManager;
import org.traccar.database.ExtendedObjectManager;
-import org.traccar.database.ManagableObjects;
import org.traccar.database.SimpleObjectManager;
import org.traccar.helper.LogAction;
import org.traccar.model.BaseModel;
import org.traccar.model.Calendar;
-import org.traccar.model.Command;
import org.traccar.model.Device;
import org.traccar.model.Group;
-import org.traccar.model.GroupedModel;
-import org.traccar.model.ScheduledModel;
+import org.traccar.model.Permission;
import org.traccar.model.User;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.Response;
public abstract class BaseObjectResource<T extends BaseModel> extends BaseResource {
- private final Class<T> baseClass;
+ protected final Class<T> baseClass;
public BaseObjectResource(Class<T> baseClass) {
this.baseClass = baseClass;
}
- protected final Class<T> getBaseClass() {
- return baseClass;
- }
-
- protected final Set<Long> getSimpleManagerItems(BaseObjectManager<T> manager, boolean all, long userId) {
- Set<Long> result;
- if (all) {
- if (Context.getPermissionsManager().getUserAdmin(getUserId())) {
- result = manager.getAllItems();
- } else {
- Context.getPermissionsManager().checkManager(getUserId());
- result = ((ManagableObjects) manager).getManagedItems(getUserId());
- }
- } else {
- if (userId == 0) {
- userId = getUserId();
- }
- Context.getPermissionsManager().checkUser(getUserId(), userId);
- result = ((ManagableObjects) manager).getUserItems(userId);
- }
- return result;
- }
-
@Path("{id}")
@GET
- public Response getSingle(@PathParam("id") long id) throws SQLException {
- Context.getPermissionsManager().checkPermission(baseClass, getUserId(), id);
- BaseObjectManager<T> manager = Context.getManager(baseClass);
- T entity = manager.getById(id);
+ public Response getSingle(@PathParam("id") long id) throws StorageException {
+ permissionsService.checkPermission(baseClass, getUserId(), id);
+ T entity = storage.getObject(baseClass, new Request(
+ new Columns.All(), new Condition.Equals("id", "id", id)));
if (entity != null) {
return Response.ok(entity).build();
} else {
@@ -89,25 +63,13 @@ public abstract class BaseObjectResource<T extends BaseModel> extends BaseResour
@POST
public Response add(T entity) throws StorageException {
- Context.getPermissionsManager().checkReadonly(getUserId());
- if (baseClass.equals(Device.class)) {
- Context.getPermissionsManager().checkDeviceReadonly(getUserId());
- Context.getPermissionsManager().checkDeviceLimit(getUserId());
- } else if (baseClass.equals(Command.class)) {
- Context.getPermissionsManager().checkLimitCommands(getUserId());
- } else if (entity instanceof GroupedModel && ((GroupedModel) entity).getGroupId() != 0) {
- Context.getPermissionsManager().checkPermission(
- Group.class, getUserId(), ((GroupedModel) entity).getGroupId());
- } else if (entity instanceof ScheduledModel && ((ScheduledModel) entity).getCalendarId() != 0) {
- Context.getPermissionsManager().checkPermission(
- Calendar.class, getUserId(), ((ScheduledModel) entity).getCalendarId());
- }
+ permissionsService.checkEdit(getUserId(), entity, true);
BaseObjectManager<T> manager = Context.getManager(baseClass);
manager.addItem(entity);
LogAction.create(getUserId(), entity);
- Context.getDataManager().linkObject(User.class, getUserId(), baseClass, entity.getId(), true);
+ storage.addPermission(new Permission(User.class, getUserId(), baseClass, entity.getId()));
LogAction.link(getUserId(), User.class, getUserId(), baseClass, entity.getId());
if (manager instanceof SimpleObjectManager) {
@@ -122,22 +84,8 @@ public abstract class BaseObjectResource<T extends BaseModel> extends BaseResour
@Path("{id}")
@PUT
public Response update(T entity) throws StorageException {
- Context.getPermissionsManager().checkReadonly(getUserId());
- if (baseClass.equals(Device.class)) {
- Context.getPermissionsManager().checkDeviceReadonly(getUserId());
- } else if (baseClass.equals(User.class)) {
- User before = Context.getPermissionsManager().getUser(entity.getId());
- Context.getPermissionsManager().checkUserUpdate(getUserId(), before, (User) entity);
- } else if (baseClass.equals(Command.class)) {
- Context.getPermissionsManager().checkLimitCommands(getUserId());
- } else if (entity instanceof GroupedModel && ((GroupedModel) entity).getGroupId() != 0) {
- Context.getPermissionsManager().checkPermission(
- Group.class, getUserId(), ((GroupedModel) entity).getGroupId());
- } else if (entity instanceof ScheduledModel && ((ScheduledModel) entity).getCalendarId() != 0) {
- Context.getPermissionsManager().checkPermission(
- Calendar.class, getUserId(), ((ScheduledModel) entity).getCalendarId());
- }
- Context.getPermissionsManager().checkPermission(baseClass, getUserId(), entity.getId());
+ permissionsService.checkEdit(getUserId(), entity, false);
+ permissionsService.checkPermission(baseClass, getUserId(), entity.getId());
Context.getManager(baseClass).updateItem(entity);
LogAction.edit(getUserId(), entity);
@@ -152,13 +100,8 @@ public abstract class BaseObjectResource<T extends BaseModel> extends BaseResour
@Path("{id}")
@DELETE
public Response remove(@PathParam("id") long id) throws StorageException {
- Context.getPermissionsManager().checkReadonly(getUserId());
- if (baseClass.equals(Device.class)) {
- Context.getPermissionsManager().checkDeviceReadonly(getUserId());
- } else if (baseClass.equals(Command.class)) {
- Context.getPermissionsManager().checkLimitCommands(getUserId());
- }
- Context.getPermissionsManager().checkPermission(baseClass, getUserId(), id);
+ permissionsService.checkEdit(getUserId(), baseClass, false);
+ permissionsService.checkPermission(baseClass, getUserId(), id);
BaseObjectManager<T> manager = Context.getManager(baseClass);
manager.removeItem(id);
diff --git a/src/main/java/org/traccar/api/BaseResource.java b/src/main/java/org/traccar/api/BaseResource.java
index 6dff8c8c3..33abe73fa 100644
--- a/src/main/java/org/traccar/api/BaseResource.java
+++ b/src/main/java/org/traccar/api/BaseResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,8 +15,11 @@
*/
package org.traccar.api;
+import org.traccar.api.security.PermissionsService;
import org.traccar.api.security.UserPrincipal;
+import org.traccar.storage.Storage;
+import javax.inject.Inject;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;
@@ -25,6 +28,12 @@ public class BaseResource {
@Context
private SecurityContext securityContext;
+ @Inject
+ protected Storage storage;
+
+ @Inject
+ protected PermissionsService permissionsService;
+
protected long getUserId() {
UserPrincipal principal = (UserPrincipal) securityContext.getUserPrincipal();
if (principal != null) {
@@ -32,4 +41,5 @@ public class BaseResource {
}
return 0;
}
+
}
diff --git a/src/main/java/org/traccar/api/ExtendedObjectResource.java b/src/main/java/org/traccar/api/ExtendedObjectResource.java
index 9e554217e..40d679ded 100644
--- a/src/main/java/org/traccar/api/ExtendedObjectResource.java
+++ b/src/main/java/org/traccar/api/ExtendedObjectResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,19 @@
*/
package org.traccar.api;
-import java.sql.SQLException;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
+import org.traccar.model.BaseModel;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.model.User;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
import javax.ws.rs.GET;
import javax.ws.rs.QueryParam;
-
-import org.traccar.Context;
-import org.traccar.database.ExtendedObjectManager;
-import org.traccar.model.BaseModel;
+import java.util.Collection;
+import java.util.LinkedList;
public class ExtendedObjectResource<T extends BaseModel> extends BaseObjectResource<T> {
@@ -36,27 +38,32 @@ public class ExtendedObjectResource<T extends BaseModel> extends BaseObjectResou
@GET
public Collection<T> get(
- @QueryParam("all") boolean all, @QueryParam("userId") long userId, @QueryParam("groupId") long groupId,
- @QueryParam("deviceId") long deviceId, @QueryParam("refresh") boolean refresh) throws SQLException {
-
- ExtendedObjectManager<T> manager = (ExtendedObjectManager<T>) Context.getManager(getBaseClass());
- if (refresh) {
- manager.refreshItems();
- }
+ @QueryParam("all") boolean all, @QueryParam("userId") long userId,
+ @QueryParam("groupId") long groupId, @QueryParam("deviceId") long deviceId) throws StorageException {
- Set<Long> result = new HashSet<>(getSimpleManagerItems(manager, all, userId));
+ var conditions = new LinkedList<Condition>();
- if (groupId != 0) {
- Context.getPermissionsManager().checkGroup(getUserId(), groupId);
- result.retainAll(manager.getGroupItems(groupId));
+ if (all) {
+ permissionsService.checkAdmin(getUserId());
+ } else {
+ if (userId == 0) {
+ userId = getUserId();
+ } else {
+ permissionsService.checkUser(getUserId(), userId);
+ }
+ conditions.add(new Condition.Permission(User.class, userId, baseClass));
}
- if (deviceId != 0) {
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
- result.retainAll(manager.getDeviceItems(deviceId));
+ if (groupId > 0) {
+ permissionsService.checkPermission(Group.class, getUserId(), groupId);
+ conditions.add(new Condition.Permission(Group.class, groupId, baseClass));
+ }
+ if (deviceId > 0) {
+ permissionsService.checkPermission(Device.class, getUserId(), deviceId);
+ conditions.add(new Condition.Permission(Device.class, deviceId, baseClass));
}
- return manager.getItems(result);
+ return storage.getObjects(baseClass, new Request(new Columns.All(), Condition.merge(conditions)));
}
}
diff --git a/src/main/java/org/traccar/api/MediaFilter.java b/src/main/java/org/traccar/api/MediaFilter.java
index 77731a810..0433147f8 100644
--- a/src/main/java/org/traccar/api/MediaFilter.java
+++ b/src/main/java/org/traccar/api/MediaFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,6 @@
package org.traccar.api;
import java.io.IOException;
-import java.sql.SQLException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
@@ -76,9 +75,6 @@ public class MediaFilter implements Filter {
} catch (SecurityException e) {
httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
httpResponse.getWriter().println(Log.exceptionStack(e));
- } catch (SQLException e) {
- httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
- httpResponse.getWriter().println(Log.exceptionStack(e));
}
}
diff --git a/src/main/java/org/traccar/api/SimpleObjectResource.java b/src/main/java/org/traccar/api/SimpleObjectResource.java
index a7fcae0e7..c61101077 100644
--- a/src/main/java/org/traccar/api/SimpleObjectResource.java
+++ b/src/main/java/org/traccar/api/SimpleObjectResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,17 @@
*/
package org.traccar.api;
-import java.sql.SQLException;
-import java.util.Collection;
+import org.traccar.model.BaseModel;
+import org.traccar.model.User;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
import javax.ws.rs.GET;
import javax.ws.rs.QueryParam;
-
-import org.traccar.Context;
-import org.traccar.database.BaseObjectManager;
-import org.traccar.model.BaseModel;
+import java.util.Collection;
+import java.util.LinkedList;
public class SimpleObjectResource<T extends BaseModel> extends BaseObjectResource<T> {
@@ -34,10 +36,22 @@ public class SimpleObjectResource<T extends BaseModel> extends BaseObjectResourc
@GET
public Collection<T> get(
- @QueryParam("all") boolean all, @QueryParam("userId") long userId) throws SQLException {
-
- BaseObjectManager<T> manager = Context.getManager(getBaseClass());
- return manager.getItems(getSimpleManagerItems(manager, all, userId));
+ @QueryParam("all") boolean all, @QueryParam("userId") long userId) throws StorageException {
+
+ var conditions = new LinkedList<Condition>();
+
+ if (all) {
+ permissionsService.checkAdmin(getUserId());
+ } else {
+ if (userId == 0) {
+ userId = getUserId();
+ } else {
+ permissionsService.checkUser(getUserId(), userId);
+ }
+ conditions.add(new Condition.Permission(User.class, userId, baseClass));
+ }
+
+ return storage.getObjects(baseClass, new Request(new Columns.All(), Condition.merge(conditions)));
}
}
diff --git a/src/main/java/org/traccar/api/resource/AttributeResource.java b/src/main/java/org/traccar/api/resource/AttributeResource.java
index d2dc28903..478b7acfd 100644
--- a/src/main/java/org/traccar/api/resource/AttributeResource.java
+++ b/src/main/java/org/traccar/api/resource/AttributeResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,9 +30,13 @@ import javax.ws.rs.core.Response;
import org.traccar.Context;
import org.traccar.api.ExtendedObjectResource;
import org.traccar.model.Attribute;
+import org.traccar.model.Device;
import org.traccar.model.Position;
import org.traccar.handler.ComputedAttributesHandler;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
@Path("attributes/computed")
@Produces(MediaType.APPLICATION_JSON)
@@ -45,51 +49,61 @@ public class AttributeResource extends ExtendedObjectResource<Attribute> {
@POST
@Path("test")
- public Response test(@QueryParam("deviceId") long deviceId, Attribute entity) {
- Context.getPermissionsManager().checkAdmin(getUserId());
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
- Position last = Context.getIdentityManager().getLastPosition(deviceId);
- if (last != null) {
- Object result = new ComputedAttributesHandler(
- Context.getConfig(),
- Context.getIdentityManager(),
- Context.getAttributesManager()).computeAttribute(entity, last);
- if (result != null) {
- switch (entity.getType()) {
- case "number":
- Number numberValue = (Number) result;
- return Response.ok(numberValue).build();
- case "boolean":
- Boolean booleanValue = (Boolean) result;
- return Response.ok(booleanValue).build();
- default:
- return Response.ok(result.toString()).build();
- }
- } else {
- return Response.noContent().build();
+ public Response test(@QueryParam("deviceId") long deviceId, Attribute entity) throws StorageException {
+ permissionsService.checkAdmin(getUserId());
+ permissionsService.checkPermission(Device.class, getUserId(), deviceId);
+
+ Device device = storage.getObject(Device.class, new Request(
+ new Columns.All(),
+ new Condition.Equals("id", "id", deviceId)));
+ if (device == null) {
+ throw new IllegalArgumentException("Device not found");
+ }
+
+ Position last = storage.getObject(Position.class, new Request(
+ new Columns.All(),
+ new Condition.Equals("id", "id", device.getPositionId())));
+ if (last == null) {
+ throw new IllegalArgumentException("Device has no last position");
+ }
+
+ Object result = new ComputedAttributesHandler(
+ Context.getConfig(),
+ Context.getIdentityManager(),
+ Context.getAttributesManager()).computeAttribute(entity, last);
+ if (result != null) {
+ switch (entity.getType()) {
+ case "number":
+ Number numberValue = (Number) result;
+ return Response.ok(numberValue).build();
+ case "boolean":
+ Boolean booleanValue = (Boolean) result;
+ return Response.ok(booleanValue).build();
+ default:
+ return Response.ok(result.toString()).build();
}
} else {
- throw new IllegalArgumentException("Device has no last position");
+ return Response.noContent().build();
}
}
@POST
public Response add(Attribute entity) throws StorageException {
- Context.getPermissionsManager().checkAdmin(getUserId());
+ permissionsService.checkAdmin(getUserId());
return super.add(entity);
}
@Path("{id}")
@PUT
public Response update(Attribute entity) throws StorageException {
- Context.getPermissionsManager().checkAdmin(getUserId());
+ permissionsService.checkAdmin(getUserId());
return super.update(entity);
}
@Path("{id}")
@DELETE
public Response remove(@PathParam("id") long id) throws StorageException {
- Context.getPermissionsManager().checkAdmin(getUserId());
+ permissionsService.checkAdmin(getUserId());
return super.remove(id);
}
diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java
index 9436b59f6..309308e75 100644
--- a/src/main/java/org/traccar/api/resource/DeviceResource.java
+++ b/src/main/java/org/traccar/api/resource/DeviceResource.java
@@ -31,8 +31,6 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-
-import java.sql.SQLException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
@@ -51,7 +49,7 @@ public class DeviceResource extends BaseObjectResource<Device> {
public Collection<Device> get(
@QueryParam("all") boolean all, @QueryParam("userId") long userId,
@QueryParam("uniqueId") List<String> uniqueIds,
- @QueryParam("id") List<Long> deviceIds) throws SQLException {
+ @QueryParam("id") List<Long> deviceIds) {
DeviceManager deviceManager = Context.getDeviceManager();
Set<Long> result;
if (all) {
diff --git a/src/main/java/org/traccar/api/resource/EventResource.java b/src/main/java/org/traccar/api/resource/EventResource.java
index 354d96e4f..38b101b25 100644
--- a/src/main/java/org/traccar/api/resource/EventResource.java
+++ b/src/main/java/org/traccar/api/resource/EventResource.java
@@ -15,6 +15,11 @@
*/
package org.traccar.api.resource;
+import org.traccar.Context;
+import org.traccar.api.BaseResource;
+import org.traccar.model.Event;
+import org.traccar.storage.StorageException;
+
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@@ -24,13 +29,6 @@ import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-import org.traccar.Context;
-import org.traccar.api.BaseResource;
-import org.traccar.model.Event;
-import org.traccar.model.Geofence;
-import org.traccar.model.Maintenance;
-import org.traccar.storage.StorageException;
-
@Path("events")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@@ -44,12 +42,6 @@ public class EventResource extends BaseResource {
throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
}
Context.getPermissionsManager().checkDevice(getUserId(), event.getDeviceId());
- if (event.getGeofenceId() != 0) {
- Context.getPermissionsManager().checkPermission(Geofence.class, getUserId(), event.getGeofenceId());
- }
- if (event.getMaintenanceId() != 0) {
- Context.getPermissionsManager().checkPermission(Maintenance.class, getUserId(), event.getMaintenanceId());
- }
return event;
}
diff --git a/src/main/java/org/traccar/api/resource/NotificationResource.java b/src/main/java/org/traccar/api/resource/NotificationResource.java
index 9631a52b7..cf4b66fa1 100644
--- a/src/main/java/org/traccar/api/resource/NotificationResource.java
+++ b/src/main/java/org/traccar/api/resource/NotificationResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,7 +33,6 @@ import org.traccar.model.Notification;
import org.traccar.model.Typed;
import org.traccar.notification.MessageException;
-
@Path("notifications")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java
index 511032402..941417231 100644
--- a/src/main/java/org/traccar/api/resource/PositionResource.java
+++ b/src/main/java/org/traccar/api/resource/PositionResource.java
@@ -55,7 +55,7 @@ public class PositionResource extends BaseResource {
} else {
Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
if (from != null && to != null) {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ permissionsService.checkReports(getUserId());
return Context.getDataManager().getPositions(deviceId, from, to);
} else {
return Collections.singleton(Context.getDeviceManager().getLastPosition(deviceId));
diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java
index 03df0d03a..901385d0d 100644
--- a/src/main/java/org/traccar/api/resource/ReportResource.java
+++ b/src/main/java/org/traccar/api/resource/ReportResource.java
@@ -99,7 +99,7 @@ public class ReportResource extends BaseResource {
public Collection<Position> getRoute(
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ permissionsService.checkReports(getUserId());
LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds);
return Route.getObjects(getUserId(), deviceIds, groupIds, from, to);
}
@@ -111,7 +111,7 @@ public class ReportResource extends BaseResource {
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail)
throws StorageException, IOException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ permissionsService.checkReports(getUserId());
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds);
Route.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
@@ -124,7 +124,7 @@ public class ReportResource extends BaseResource {
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("type") final List<String> types,
@QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ permissionsService.checkReports(getUserId());
LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds);
return Events.getObjects(getUserId(), deviceIds, groupIds, types, from, to);
}
@@ -137,7 +137,7 @@ public class ReportResource extends BaseResource {
@QueryParam("type") final List<String> types,
@QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail)
throws StorageException, IOException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ permissionsService.checkReports(getUserId());
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds);
Events.getExcel(stream, getUserId(), deviceIds, groupIds, types, from, to);
@@ -150,7 +150,7 @@ public class ReportResource extends BaseResource {
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("daily") boolean daily)
throws StorageException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ permissionsService.checkReports(getUserId());
LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds);
return Summary.getObjects(getUserId(), deviceIds, groupIds, from, to, daily);
}
@@ -163,7 +163,7 @@ public class ReportResource extends BaseResource {
@QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("daily") boolean daily,
@QueryParam("mail") boolean mail)
throws StorageException, IOException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ permissionsService.checkReports(getUserId());
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds);
Summary.getExcel(stream, getUserId(), deviceIds, groupIds, from, to, daily);
@@ -176,7 +176,7 @@ public class ReportResource extends BaseResource {
public Collection<TripReport> getTrips(
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ permissionsService.checkReports(getUserId());
LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds);
return Trips.getObjects(getUserId(), deviceIds, groupIds, from, to);
}
@@ -188,7 +188,7 @@ public class ReportResource extends BaseResource {
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail)
throws StorageException, IOException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ permissionsService.checkReports(getUserId());
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds);
Trips.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
@@ -201,7 +201,7 @@ public class ReportResource extends BaseResource {
public Collection<StopReport> getStops(
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ permissionsService.checkReports(getUserId());
LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds);
return Stops.getObjects(getUserId(), deviceIds, groupIds, from, to);
}
@@ -213,7 +213,7 @@ public class ReportResource extends BaseResource {
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail)
throws StorageException, IOException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ permissionsService.checkReports(getUserId());
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds);
Stops.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java
new file mode 100644
index 000000000..c640f8d74
--- /dev/null
+++ b/src/main/java/org/traccar/api/security/PermissionsService.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2022 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.security;
+
+import org.traccar.model.BaseModel;
+import org.traccar.model.Calendar;
+import org.traccar.model.Command;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.model.GroupedModel;
+import org.traccar.model.ScheduledModel;
+import org.traccar.model.Server;
+import org.traccar.model.User;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import javax.inject.Inject;
+
+public class PermissionsService {
+
+ private final Storage storage;
+
+ private Server server;
+ private User user;
+
+ @Inject
+ public PermissionsService(Storage storage) {
+ this.storage = storage;
+ }
+
+ private Server getServer() throws StorageException {
+ if (server == null) {
+ server = storage.getObject(
+ Server.class, new Request(new Columns.All()));
+ }
+ return server;
+ }
+
+ private User getUser(long userId) throws StorageException {
+ if (user == null) {
+ user = storage.getObject(
+ User.class, new Request(new Columns.All(), new Condition.Equals("id", "id", userId)));
+ }
+ return user;
+ }
+
+ public void checkAdmin(long userId) throws StorageException, SecurityException {
+ if (!getUser(userId).getAdministrator()) {
+ throw new SecurityException("Account is readonly");
+ }
+ }
+
+ public void checkReports(long userId) throws StorageException, SecurityException {
+ if (!getUser(userId).getAdministrator()
+ && (server.getDisableReports() || getUser(userId).getDisableReports())) {
+ throw new SecurityException("Reports are disabled");
+ }
+ }
+
+ public void checkEdit(long userId, Class<?> clazz, boolean addition) throws StorageException, SecurityException {
+ if (!getUser(userId).getAdministrator()) {
+ boolean denied = false;
+ if (getServer().getReadonly() || getUser(userId).getReadonly()) {
+ denied = true;
+ } else if (clazz.equals(Device.class)) {
+ denied = getServer().getDeviceReadonly() || getUser(userId).getDeviceReadonly();
+ if (addition) {
+ int deviceCount = storage.getPermissions(User.class, userId, Device.class).size();
+ denied = deviceCount >= getUser(userId).getDeviceLimit();
+ }
+ } else if (clazz.equals(Command.class)) {
+ denied = getServer().getLimitCommands() || getUser(userId).getLimitCommands();
+ }
+ if (denied) {
+ throw new SecurityException("Write access denied");
+ }
+ }
+ }
+
+ public void checkEdit(long userId, Object object, boolean addition) throws StorageException, SecurityException {
+ if (!getUser(userId).getAdministrator()) {
+ checkEdit(userId, object.getClass(), addition);
+ boolean denied = false;
+ if (object instanceof GroupedModel) {
+ long groupId = ((GroupedModel) object).getGroupId();
+ if (groupId > 0) {
+ checkPermission(Group.class, userId, groupId);
+ }
+ }
+ if (object instanceof ScheduledModel) {
+ long calendarId = ((ScheduledModel) object).getCalendarId();
+ if (calendarId > 0) {
+ denied = storage.getPermissions(User.class, userId, Calendar.class, calendarId).isEmpty();
+ }
+ }
+ if (denied) {
+ throw new SecurityException("Write access denied");
+ }
+ }
+ }
+
+ public void checkUser(long userId, long managedUserId) throws StorageException, SecurityException {
+ if (userId != managedUserId && !getUser(userId).getAdministrator()) {
+ if (!getUser(userId).getManager()
+ || storage.getPermissions(User.class, userId, User.class, managedUserId).isEmpty()) {
+ throw new SecurityException("User access denied");
+ }
+ }
+ }
+
+ public <T extends BaseModel> void checkPermission(
+ Class<T> clazz, long userId, long objectId) throws StorageException, SecurityException {
+ if (!getUser(userId).getAdministrator()) {
+ var objects = storage.getObjects(clazz, new Request(
+ new Columns.Include("id"),
+ new Condition.Permission(User.class, userId, clazz)));
+ boolean found = false;
+ for (var object : objects) {
+ if (object.getId() == objectId) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ throw new SecurityException(clazz.getSimpleName() + " access denied");
+ }
+ }
+ }
+
+}