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/AsyncSocketServlet.java30
-rw-r--r--src/main/java/org/traccar/api/resource/CommandResource.java3
-rw-r--r--src/main/java/org/traccar/api/resource/DeviceResource.java8
-rw-r--r--src/main/java/org/traccar/api/resource/NotificationResource.java15
-rw-r--r--src/main/java/org/traccar/api/resource/ReportResource.java24
-rw-r--r--src/main/java/org/traccar/api/resource/ServerResource.java7
-rw-r--r--src/main/java/org/traccar/api/security/LoginService.java18
-rw-r--r--src/main/java/org/traccar/api/security/SecurityRequestFilter.java22
8 files changed, 80 insertions, 47 deletions
diff --git a/src/main/java/org/traccar/api/AsyncSocketServlet.java b/src/main/java/org/traccar/api/AsyncSocketServlet.java
index cd2c1639e..e1e7ee977 100644
--- a/src/main/java/org/traccar/api/AsyncSocketServlet.java
+++ b/src/main/java/org/traccar/api/AsyncSocketServlet.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2024 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.
@@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.jetty.websocket.server.JettyWebSocketServlet;
import org.eclipse.jetty.websocket.server.JettyWebSocketServletFactory;
import org.traccar.api.resource.SessionResource;
+import org.traccar.api.security.LoginService;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.session.ConnectionManager;
@@ -27,7 +28,12 @@ import org.traccar.storage.Storage;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import jakarta.servlet.http.HttpSession;
+import org.traccar.storage.StorageException;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
import java.time.Duration;
+import java.util.List;
@Singleton
public class AsyncSocketServlet extends JettyWebSocketServlet {
@@ -36,25 +42,37 @@ public class AsyncSocketServlet extends JettyWebSocketServlet {
private final ObjectMapper objectMapper;
private final ConnectionManager connectionManager;
private final Storage storage;
+ private final LoginService loginService;
@Inject
public AsyncSocketServlet(
- Config config, ObjectMapper objectMapper, ConnectionManager connectionManager, Storage storage) {
+ Config config, ObjectMapper objectMapper, ConnectionManager connectionManager, Storage storage,
+ LoginService loginService) {
this.config = config;
this.objectMapper = objectMapper;
this.connectionManager = connectionManager;
this.storage = storage;
+ this.loginService = loginService;
}
@Override
public void configure(JettyWebSocketServletFactory factory) {
factory.setIdleTimeout(Duration.ofMillis(config.getLong(Keys.WEB_TIMEOUT)));
factory.setCreator((req, resp) -> {
- if (req.getSession() != null) {
- Long userId = (Long) ((HttpSession) req.getSession()).getAttribute(SessionResource.USER_ID_KEY);
- if (userId != null) {
- return new AsyncSocket(objectMapper, connectionManager, storage, userId);
+ Long userId = null;
+ List<String> tokens = req.getParameterMap().get("token");
+ if (tokens != null && !tokens.isEmpty()) {
+ String token = tokens.iterator().next();
+ try {
+ userId = loginService.login(token).getUser().getId();
+ } catch (StorageException | GeneralSecurityException | IOException e) {
+ throw new RuntimeException(e);
}
+ } else if (req.getSession() != null) {
+ userId = (Long) ((HttpSession) req.getSession()).getAttribute(SessionResource.USER_ID_KEY);
+ }
+ if (userId != null) {
+ return new AsyncSocket(objectMapper, connectionManager, storage, userId);
}
return null;
});
diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java
index c23d91e77..66ec0f8a3 100644
--- a/src/main/java/org/traccar/api/resource/CommandResource.java
+++ b/src/main/java/org/traccar/api/resource/CommandResource.java
@@ -23,6 +23,7 @@ import org.traccar.BaseProtocol;
import org.traccar.ServerManager;
import org.traccar.api.ExtendedObjectResource;
import org.traccar.database.CommandsManager;
+import org.traccar.helper.LogAction;
import org.traccar.helper.model.DeviceUtil;
import org.traccar.model.Command;
import org.traccar.model.Device;
@@ -140,6 +141,8 @@ public class CommandResource extends ExtendedObjectResource<Command> {
return Response.accepted(queuedCommand).build();
}
}
+
+ LogAction.command(getUserId(), groupId, entity.getDeviceId(), entity.getType());
return Response.ok(entity).build();
}
diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java
index 56253152f..971c29c60 100644
--- a/src/main/java/org/traccar/api/resource/DeviceResource.java
+++ b/src/main/java/org/traccar/api/resource/DeviceResource.java
@@ -137,10 +137,8 @@ public class DeviceResource extends BaseObjectResource<Device> {
@Path("{id}/accumulators")
@PUT
public Response updateAccumulators(DeviceAccumulators entity) throws Exception {
- if (permissionsService.notAdmin(getUserId())) {
- permissionsService.checkManager(getUserId());
- permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId());
- }
+ permissionsService.checkEdit(getUserId(), Device.class, false);
+ permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId());
Position position = storage.getObject(Position.class, new Request(
new Columns.All(), new Condition.LatestPositions(entity.getDeviceId())));
@@ -171,7 +169,7 @@ public class DeviceResource extends BaseObjectResource<Device> {
throw new IllegalArgumentException();
}
- LogAction.resetDeviceAccumulators(getUserId(), entity.getDeviceId());
+ LogAction.resetAccumulators(getUserId(), entity.getDeviceId());
return Response.noContent().build();
}
diff --git a/src/main/java/org/traccar/api/resource/NotificationResource.java b/src/main/java/org/traccar/api/resource/NotificationResource.java
index 43dc1fa98..a41d00cf3 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 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2024 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.
@@ -46,6 +46,8 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
@Path("notifications")
@Produces(MediaType.APPLICATION_JSON)
@@ -80,8 +82,11 @@ public class NotificationResource extends ExtendedObjectResource<Notification> {
@GET
@Path("notificators")
- public Collection<Typed> getNotificators() {
- return notificatorManager.getAllNotificatorTypes();
+ public Collection<Typed> getNotificators(@QueryParam("announcement") boolean announcement) {
+ Set<String> announcementsUnsupported = Set.of("command", "web");
+ return notificatorManager.getAllNotificatorTypes().stream()
+ .filter(typed -> !announcement || !announcementsUnsupported.contains(typed.getType()))
+ .collect(Collectors.toUnmodifiableSet());
}
@POST
@@ -120,7 +125,9 @@ public class NotificationResource extends ExtendedObjectResource<Notification> {
}
}
for (User user : users) {
- notificatorManager.getNotificator(notificator).send(user, message, null, null);
+ if (!user.getTemporary()) {
+ notificatorManager.getNotificator(notificator).send(user, message, null, null);
+ }
}
return Response.noContent().build();
}
diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java
index 55a96fa90..81f409c0f 100644
--- a/src/main/java/org/traccar/api/resource/ReportResource.java
+++ b/src/main/java/org/traccar/api/resource/ReportResource.java
@@ -113,7 +113,7 @@ public class ReportResource extends SimpleObjectResource<Report> {
@QueryParam("from") Date from,
@QueryParam("to") Date to) throws StorageException {
permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
- LogAction.logReport(getUserId(), "combined", from, to, deviceIds, groupIds);
+ LogAction.report(getUserId(), false, "combined", from, to, deviceIds, groupIds);
return combinedReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to);
}
@@ -125,7 +125,7 @@ public class ReportResource extends SimpleObjectResource<Report> {
@QueryParam("from") Date from,
@QueryParam("to") Date to) throws StorageException {
permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
- LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds);
+ LogAction.report(getUserId(), false, "route", from, to, deviceIds, groupIds);
return routeReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to);
}
@@ -140,7 +140,7 @@ public class ReportResource extends SimpleObjectResource<Report> {
@QueryParam("mail") boolean mail) throws StorageException {
permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
- LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds);
+ LogAction.report(getUserId(), false, "route", from, to, deviceIds, groupIds);
routeReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
});
}
@@ -166,7 +166,7 @@ public class ReportResource extends SimpleObjectResource<Report> {
@QueryParam("from") Date from,
@QueryParam("to") Date to) throws StorageException {
permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
- LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds);
+ LogAction.report(getUserId(), false, "events", from, to, deviceIds, groupIds);
return eventsReportProvider.getObjects(getUserId(), deviceIds, groupIds, types, from, to);
}
@@ -182,7 +182,7 @@ public class ReportResource extends SimpleObjectResource<Report> {
@QueryParam("mail") boolean mail) throws StorageException {
permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
- LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds);
+ LogAction.report(getUserId(), false, "events", from, to, deviceIds, groupIds);
eventsReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, types, from, to);
});
}
@@ -209,7 +209,7 @@ public class ReportResource extends SimpleObjectResource<Report> {
@QueryParam("to") Date to,
@QueryParam("daily") boolean daily) throws StorageException {
permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
- LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds);
+ LogAction.report(getUserId(), false, "summary", from, to, deviceIds, groupIds);
return summaryReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to, daily);
}
@@ -225,7 +225,7 @@ public class ReportResource extends SimpleObjectResource<Report> {
@QueryParam("mail") boolean mail) throws StorageException {
permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
- LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds);
+ LogAction.report(getUserId(), false, "summary", from, to, deviceIds, groupIds);
summaryReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to, daily);
});
}
@@ -251,7 +251,7 @@ public class ReportResource extends SimpleObjectResource<Report> {
@QueryParam("from") Date from,
@QueryParam("to") Date to) throws StorageException {
permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
- LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds);
+ LogAction.report(getUserId(), false, "trips", from, to, deviceIds, groupIds);
return tripsReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to);
}
@@ -266,7 +266,7 @@ public class ReportResource extends SimpleObjectResource<Report> {
@QueryParam("mail") boolean mail) throws StorageException {
permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
- LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds);
+ LogAction.report(getUserId(), false, "trips", from, to, deviceIds, groupIds);
tripsReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
});
}
@@ -291,7 +291,7 @@ public class ReportResource extends SimpleObjectResource<Report> {
@QueryParam("from") Date from,
@QueryParam("to") Date to) throws StorageException {
permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
- LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds);
+ LogAction.report(getUserId(), false, "stops", from, to, deviceIds, groupIds);
return stopsReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to);
}
@@ -306,7 +306,7 @@ public class ReportResource extends SimpleObjectResource<Report> {
@QueryParam("mail") boolean mail) throws StorageException {
permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
- LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds);
+ LogAction.report(getUserId(), false, "stops", from, to, deviceIds, groupIds);
stopsReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
});
}
@@ -326,7 +326,7 @@ public class ReportResource extends SimpleObjectResource<Report> {
@Path("devices/{type:xlsx|mail}")
@GET
@Produces(EXCEL)
- public Response geDevicesExcel(
+ public Response getDevicesExcel(
@PathParam("type") String type) throws StorageException {
permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), type.equals("mail"), stream -> {
diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java
index 2a72d2773..eb10ac763 100644
--- a/src/main/java/org/traccar/api/resource/ServerResource.java
+++ b/src/main/java/org/traccar/api/resource/ServerResource.java
@@ -161,4 +161,11 @@ public class ServerResource extends BaseResource {
return cacheManager.toString();
}
+ @Path("reboot")
+ @POST
+ public void reboot() throws StorageException {
+ permissionsService.checkAdmin(getUserId());
+ System.exit(130);
+ }
+
}
diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java
index 930c4fa46..507288c31 100644
--- a/src/main/java/org/traccar/api/security/LoginService.java
+++ b/src/main/java/org/traccar/api/security/LoginService.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2022 - 2024 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.
@@ -20,6 +20,7 @@ import org.traccar.api.signature.TokenManager;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.database.LdapProvider;
+import org.traccar.helper.DataConverter;
import org.traccar.helper.model.UserUtil;
import org.traccar.model.User;
import org.traccar.storage.Storage;
@@ -32,6 +33,7 @@ import jakarta.annotation.Nullable;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
@Singleton
@@ -58,6 +60,20 @@ public class LoginService {
forceOpenId = config.getBoolean(Keys.OPENID_FORCE);
}
+ public LoginResult login(
+ String scheme, String credentials) throws StorageException, GeneralSecurityException, IOException {
+ switch (scheme.toLowerCase()) {
+ case "bearer":
+ return login(credentials);
+ case "basic":
+ byte[] decodedBytes = DataConverter.parseBase64(credentials);
+ String[] auth = new String(decodedBytes, StandardCharsets.US_ASCII).split(":", 2);
+ return login(auth[0], auth[1], null);
+ default:
+ throw new SecurityException("Unsupported authorization scheme");
+ }
+ }
+
public LoginResult login(String token) throws StorageException, GeneralSecurityException, IOException {
if (serviceAccountToken != null && serviceAccountToken.equals(token)) {
return new LoginResult(new ServiceAccountUser());
diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java
index 12a5dbecf..07083e7a8 100644
--- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java
+++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2024 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.
@@ -20,7 +20,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.api.resource.SessionResource;
import org.traccar.database.StatisticsManager;
-import org.traccar.helper.DataConverter;
import org.traccar.model.User;
import org.traccar.storage.StorageException;
@@ -36,7 +35,6 @@ import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
import java.io.IOException;
import java.lang.reflect.Method;
-import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Date;
@@ -44,15 +42,6 @@ public class SecurityRequestFilter implements ContainerRequestFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(SecurityRequestFilter.class);
- public static String[] decodeBasicAuth(String auth) {
- auth = auth.replaceFirst("[B|b]asic ", "");
- byte[] decodedBytes = DataConverter.parseBase64(auth);
- if (decodedBytes != null && decodedBytes.length > 0) {
- return new String(decodedBytes, StandardCharsets.US_ASCII).split(":", 2);
- }
- return null;
- }
-
@Context
private HttpServletRequest request;
@@ -83,13 +72,8 @@ public class SecurityRequestFilter implements ContainerRequestFilter {
if (authHeader != null) {
try {
- LoginResult loginResult;
- if (authHeader.startsWith("Bearer ")) {
- loginResult = loginService.login(authHeader.substring(7));
- } else {
- String[] auth = decodeBasicAuth(authHeader);
- loginResult = loginService.login(auth[0], auth[1], null);
- }
+ String[] auth = authHeader.split(" ");
+ LoginResult loginResult = loginService.login(auth[0], auth[1]);
if (loginResult != null) {
User user = loginResult.getUser();
statisticsManager.registerRequest(user.getId());