diff options
author | Anton Tananaev <anton@traccar.org> | 2022-05-22 10:55:48 -0700 |
---|---|---|
committer | Anton Tananaev <anton@traccar.org> | 2022-05-22 10:55:48 -0700 |
commit | 9f8a78e5b7afddc6ccb0a54f4b3e59e1395de8eb (patch) | |
tree | 26356ca17e21d626843671aac23bf775c6451359 /src/main/java/org/traccar/api | |
parent | d9f51795058399e85ae83a8e308a0c2bc1d13e4b (diff) | |
parent | 9c9f5d66147cfa428ea18dd29103b9c82e529dca (diff) | |
download | trackermap-server-9f8a78e5b7afddc6ccb0a54f4b3e59e1395de8eb.tar.gz trackermap-server-9f8a78e5b7afddc6ccb0a54f4b3e59e1395de8eb.tar.bz2 trackermap-server-9f8a78e5b7afddc6ccb0a54f4b3e59e1395de8eb.zip |
Merge branch 'storage'
Diffstat (limited to 'src/main/java/org/traccar/api')
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"); + } + } + } + +} |