From f5a266953e53a7f1785bcb584759582621ec9de3 Mon Sep 17 00:00:00 2001 From: Rafael Guterres Date: Sat, 21 Nov 2015 01:57:46 -0200 Subject: Add support to generic resources and refactor in classes to support types and commandpattern. --- src/org/traccar/database/DataManager.java | 39 ++++++ src/org/traccar/database/PermissionsManager.java | 12 +- src/org/traccar/helper/Clazz.java | 105 ++++++++++++++ src/org/traccar/helper/CommandCall.java | 51 +++++++ src/org/traccar/web/BaseServlet.java | 36 ++--- src/org/traccar/web/BaseServletResource.java | 169 +++++++++++++++++++++++ src/org/traccar/web/CommandServlet.java | 9 +- src/org/traccar/web/DeviceServlet.java | 67 ++++++--- src/org/traccar/web/JsonConverter.java | 13 +- src/org/traccar/web/MainServlet.java | 8 +- src/org/traccar/web/PositionServlet.java | 10 +- src/org/traccar/web/ServerServlet.java | 27 ++-- src/org/traccar/web/UserServlet.java | 77 +++++++---- src/org/traccar/web/WebServer.java | 5 + 14 files changed, 520 insertions(+), 108 deletions(-) create mode 100644 src/org/traccar/helper/Clazz.java create mode 100644 src/org/traccar/helper/CommandCall.java create mode 100644 src/org/traccar/web/BaseServletResource.java (limited to 'src/org/traccar') diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java index 24a07a05c..767582604 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -379,4 +379,43 @@ public class DataManager implements IdentityManager { .executeUpdate(); } + public void add(Object entity) throws SQLException { + if (entity instanceof User) { + addUser((User) entity); + } else if (entity instanceof Device) { + addDevice((Device) entity); + } else if (entity instanceof Position) { + addPosition((Position) entity); + } + } + + public void update(Object entity) throws SQLException { + if (entity instanceof User) { + updateUser((User) entity); + } else if (entity instanceof Device) { + updateDevice((Device) entity); + } else if (entity instanceof Server) { + updateServer((Server) entity); + } + } + + public void remove(Object entity) throws SQLException { + if (entity instanceof User) { + removeUser((User) entity); + } else if (entity instanceof Device) { + removeDevice((Device) entity); + } + } + + public void link(Class clazz, long userId, long entityId) throws SQLException { + if (clazz.equals(Device.class)) { + linkDevice(userId, entityId); + } + } + + public void unlink(Class clazz, long userId, long entityId) throws SQLException { + if (clazz.equals(Device.class)) { + unlinkDevice(userId, entityId); + } + } } diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java index a38a29c32..138641973 100644 --- a/src/org/traccar/database/PermissionsManager.java +++ b/src/org/traccar/database/PermissionsManager.java @@ -22,6 +22,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; import org.traccar.helper.Log; +import org.traccar.model.Device; import org.traccar.model.Permission; import org.traccar.model.User; @@ -66,7 +67,7 @@ public class PermissionsManager { } } - public void checkUser(long userId, long otherUserId) throws SecurityException { + private void checkUser(long userId, long otherUserId) throws SecurityException { if (userId != otherUserId) { checkAdmin(userId); } @@ -76,10 +77,17 @@ public class PermissionsManager { return getNotNull(userId); } - public void checkDevice(long userId, long deviceId) throws SecurityException { + private void checkDevice(long userId, long deviceId) throws SecurityException { if (!getNotNull(userId).contains(deviceId)) { throw new SecurityException("Device access denied"); } } + public void check(Class clazz, long userId, long entityId) throws SecurityException { + if (clazz.equals(User.class)) { + checkUser(userId, entityId); + } else if (clazz.equals(Device.class)) { + checkDevice(userId, entityId); + } + } } diff --git a/src/org/traccar/helper/Clazz.java b/src/org/traccar/helper/Clazz.java new file mode 100644 index 000000000..bdde940a0 --- /dev/null +++ b/src/org/traccar/helper/Clazz.java @@ -0,0 +1,105 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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.helper; + +import java.beans.Introspector; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +public final class Clazz { + + private Clazz() { + } + + public static Class getGenericArgumentType(Class currentClass, Class genericSuperClass) { + return getGenericArgumentType(currentClass, genericSuperClass, 0); + } + + public static Class getGenericArgumentType(Class currentClass, int argumentIndex) { + return getGenericArgumentType(currentClass, null, argumentIndex); + } + + public static Class getGenericArgumentType(Class currentClass) { + return getGenericArgumentType(currentClass, null, 0); + } + + public static Class getGenericArgumentType(Class currentClass, Class genericSuperClass, int argumentIndex) { + Type superType = currentClass.getGenericSuperclass(); + if (superType == null) { + throw new IllegalArgumentException(); + } + if (!(superType instanceof ParameterizedType) + || genericSuperClass != null + && ((ParameterizedType) superType).getRawType() != genericSuperClass) { + return getGenericArgumentType(currentClass.getSuperclass(), genericSuperClass, argumentIndex); + } + Object[] args = ((ParameterizedType) superType).getActualTypeArguments(); + if (argumentIndex >= args.length) { + throw new IllegalArgumentException(); + } + return cast(Class.class, args[argumentIndex]); + } + + public static T newInstance(Class clazz) { + try { + return clazz.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalArgumentException(); + } + } + + public static T cast(Class classe, Object objeto) { + if (classe.isAssignableFrom(objeto.getClass())) { + return classe.cast(objeto); + } + throw new ClassCastException(); + } + + public static Class forName(String className) { + try { + return Class.forName(className, false, Thread.currentThread().getContextClassLoader()); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException(e); + } + } + + public static long getId(Object entity) throws Exception { + Method[] methods = entity.getClass().getMethods(); + for (final Method method : methods) { + if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { + final String name = Introspector.decapitalize(method.getName().substring(3)); + if (name.equals("id")) { + return Long.parseLong(method.invoke(entity).toString()); + } + } + } + throw new IllegalArgumentException(); + } + + public static void setId(Object entity, long id) throws Exception { + Method[] methods = entity.getClass().getMethods(); + for (final Method method : methods) { + if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) { + final String name = Introspector.decapitalize(method.getName().substring(3)); + if (name.equals("id")) { + method.invoke(entity, id); + break; + } + } + } + } +} diff --git a/src/org/traccar/helper/CommandCall.java b/src/org/traccar/helper/CommandCall.java new file mode 100644 index 000000000..d5da79348 --- /dev/null +++ b/src/org/traccar/helper/CommandCall.java @@ -0,0 +1,51 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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.helper; + +public abstract class CommandCall { + + private long userId; + private T entity; + + public void before() throws Exception { + //Do nothing. + } + + public void check() throws Exception { + //Do nothing. + } + + public void after() throws Exception { + //Do nothing. + } + + public long getUserId() { + return userId; + } + + public void setUserId(long userId) { + this.userId = userId; + } + + public T getEntity() { + return entity; + } + + public void setEntity(T entity) { + this.entity = entity; + } + +} diff --git a/src/org/traccar/web/BaseServlet.java b/src/org/traccar/web/BaseServlet.java index 283edf1e5..916eb6a18 100644 --- a/src/org/traccar/web/BaseServlet.java +++ b/src/org/traccar/web/BaseServlet.java @@ -37,15 +37,11 @@ import org.traccar.model.User; public abstract class BaseServlet extends HttpServlet { - public static final String USER_KEY = "user"; + public static final String USER_ID_KEY = "user"; public static final String ALLOW_ORIGIN_VALUE = "*"; public static final String ALLOW_HEADERS_VALUE = "Origin, X-Requested-With, Content-Type, Accept"; public static final String ALLOW_METHODS_VALUE = "GET, POST, PUT, DELETE"; public static final String APPLICATION_JSON = "application/json"; - public static final String GET = "GET"; - public static final String POST = "POST"; - public static final String PUT = "PUT"; - public static final String DELETE = "DELETE"; @Override protected final void service( @@ -82,6 +78,10 @@ public abstract class BaseServlet extends HttpServlet { String command, HttpServletRequest req, HttpServletResponse resp) throws Exception; public long getUserId(HttpServletRequest req) throws Exception { + Object userId = req.getSession().getAttribute(USER_ID_KEY); + if (userId != null) { + return (Long) userId; + } String authorization = req.getHeader(HttpHeaders.Names.AUTHORIZATION); if (authorization != null && !authorization.isEmpty()) { Map authMap = Authorization.parse(authorization); @@ -92,11 +92,7 @@ public abstract class BaseServlet extends HttpServlet { return user.getId(); } } - Long userId = (Long) req.getSession().getAttribute(USER_KEY); - if (userId == null) { - throw new AccessControlException("User not logged in"); - } - return userId; + throw new AccessControlException("User not logged in"); } public void sendResponse(Writer writer, boolean success) throws IOException { @@ -129,26 +125,12 @@ public abstract class BaseServlet extends HttpServlet { writer.write(result.build().toString()); } - private String getCommand(HttpServletRequest req) { + protected String getCommand(HttpServletRequest req) { String command = req.getPathInfo(); if (command == null) { - switch (req.getMethod()) { - case GET: - command = "/get"; - break; - case POST: - command = "/add"; - break; - case PUT: - command = "/update"; - break; - case DELETE: - command = "/remove"; - break; - default: - command = ""; - } + command = ""; } return command; } + } diff --git a/src/org/traccar/web/BaseServletResource.java b/src/org/traccar/web/BaseServletResource.java new file mode 100644 index 000000000..318f0d7b6 --- /dev/null +++ b/src/org/traccar/web/BaseServletResource.java @@ -0,0 +1,169 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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.web; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.traccar.Context; +import org.traccar.helper.CommandCall; +import org.traccar.helper.Clazz; + +/** + * + * @author Rafael + */ +public abstract class BaseServletResource extends BaseServlet { + + private final Class clazz = Clazz.getGenericArgumentType(getClass()); + + public static final String GET = "GET"; + public static final String POST = "POST"; + public static final String PUT = "PUT"; + public static final String DELETE = "DELETE"; + + public static final String PATH_PARAM_ID = "/\\d"; + public static final String SLASH = "/"; + public static final String VOID = ""; + + @Override + protected String getCommand(HttpServletRequest req) { + String command = req.getPathInfo(); + if (command == null || command.matches(PATH_PARAM_ID)) { + switch (req.getMethod()) { + case GET: + command = "/get"; + break; + case POST: + command = "/add"; + break; + case PUT: + command = "/update"; + break; + case DELETE: + command = "/remove"; + break; + default: + command = ""; + } + } + return command; + } + + protected String getPathParamId(String pathInfo) { + if (pathInfo != null && pathInfo.matches(PATH_PARAM_ID)) { + return pathInfo.replaceAll(SLASH, VOID); + } + return null; + } + + protected abstract void get(HttpServletRequest req, HttpServletResponse resp) throws Exception; + + protected void add(HttpServletRequest req, HttpServletResponse resp) throws Exception { + add(req, resp, null); + } + + protected void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { + update(req, resp, null); + } + + protected void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception { + remove(req, resp, null); + } + + protected void add(HttpServletRequest req, HttpServletResponse resp, CommandCall commandCall) throws Exception { + if (commandCall != null) { + commandCall.before(); + } + + T entity = JsonConverter.objectFromJson(req.getReader(), this.clazz); + long userId = getUserId(req); + if (commandCall != null) { + commandCall.setUserId(userId); + commandCall.setEntity(entity); + commandCall.check(); + } + + Context.getDataManager().add(entity); + + long entityId = Clazz.getId(entity); + Context.getDataManager().link(this.clazz, userId, entityId); + + if (commandCall != null) { + commandCall.after(); + } + + sendResponse(resp.getWriter(), JsonConverter.objectToJson(entity)); + } + + protected void update(HttpServletRequest req, HttpServletResponse resp, + CommandCall commandCall) throws Exception { + if (commandCall != null) { + commandCall.before(); + } + + T entity = JsonConverter.objectFromJson(req.getReader(), this.clazz); + String entityId = getPathParamId(req.getPathInfo()); + if (entityId != null) { + Clazz.setId(entity, Long.parseLong(entityId)); + } + long userId = getUserId(req); + + if (commandCall != null) { + commandCall.setUserId(userId); + commandCall.setEntity(entity); + commandCall.check(); + } + + Context.getDataManager().update(entity); + + if (commandCall != null) { + commandCall.after(); + } + + sendResponse(resp.getWriter(), true); + } + + protected void remove(HttpServletRequest req, HttpServletResponse resp, + CommandCall commandCall) throws Exception { + if (commandCall != null) { + commandCall.before(); + } + + T entity = Clazz.newInstance(this.clazz); + String entityId = getPathParamId(req.getPathInfo()); + if (entityId != null) { + Clazz.setId(entity, Long.parseLong(entityId)); + } else { + entity = JsonConverter.objectFromJson(req.getReader(), this.clazz); + } + long userId = getUserId(req); + + if (commandCall != null) { + commandCall.setUserId(userId); + commandCall.setEntity(entity); + commandCall.check(); + } + + Context.getDataManager().remove(entity); + + if (commandCall != null) { + commandCall.after(); + } + + sendResponse(resp.getWriter(), true); + } + +} diff --git a/src/org/traccar/web/CommandServlet.java b/src/org/traccar/web/CommandServlet.java index 958f1a888..be2d50ccc 100644 --- a/src/org/traccar/web/CommandServlet.java +++ b/src/org/traccar/web/CommandServlet.java @@ -7,6 +7,7 @@ import javax.servlet.http.HttpServletResponse; import org.traccar.Context; import org.traccar.database.ActiveDevice; import org.traccar.model.Command; +import org.traccar.model.Device; public class CommandServlet extends BaseServlet { @@ -34,19 +35,17 @@ public class CommandServlet extends BaseServlet { } private void send(HttpServletRequest req, HttpServletResponse resp) throws Exception { - - Command command = JsonConverter.objectFromJson(req.getReader(), new Command()); - Context.getPermissionsManager().checkDevice(getUserId(req), command.getDeviceId()); + Command command = JsonConverter.objectFromJson(req.getReader(), Command.class); + Context.getPermissionsManager().check(Device.class, getUserId(req), command.getDeviceId()); getActiveDevice(command.getDeviceId()).sendCommand(command); sendResponse(resp.getWriter(), true); } private void raw(HttpServletRequest req, HttpServletResponse resp) throws Exception { - JsonObject json = Json.createReader(req.getReader()).readObject(); long deviceId = json.getJsonNumber("deviceId").longValue(); String command = json.getString("command"); - Context.getPermissionsManager().checkDevice(getUserId(req), deviceId); + Context.getPermissionsManager().check(Device.class, getUserId(req), deviceId); getActiveDevice(deviceId).write(command); sendResponse(resp.getWriter(), true); } diff --git a/src/org/traccar/web/DeviceServlet.java b/src/org/traccar/web/DeviceServlet.java index 8f983ad78..7900538bb 100644 --- a/src/org/traccar/web/DeviceServlet.java +++ b/src/org/traccar/web/DeviceServlet.java @@ -18,9 +18,11 @@ package org.traccar.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.traccar.Context; +import org.traccar.helper.CommandCall; import org.traccar.model.Device; +import org.traccar.model.User; -public class DeviceServlet extends BaseServlet { +public class DeviceServlet extends BaseServletResource { @Override protected boolean handle(String command, HttpServletRequest req, HttpServletResponse resp) throws Exception { @@ -50,7 +52,8 @@ public class DeviceServlet extends BaseServlet { return true; } - private void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { + @Override + protected void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { if (Boolean.parseBoolean(req.getParameter("all"))) { Context.getPermissionsManager().checkAdmin(getUserId(req)); sendResponse(resp.getWriter(), JsonConverter.arrayToJson( @@ -63,39 +66,57 @@ public class DeviceServlet extends BaseServlet { } else { userId = getUserId(req); } - Context.getPermissionsManager().checkUser(getUserId(req), userId); + Context.getPermissionsManager().check(User.class, getUserId(req), userId); sendResponse(resp.getWriter(), JsonConverter.arrayToJson( Context.getDataManager().getDevices(userId))); } } - private void add(HttpServletRequest req, HttpServletResponse resp) throws Exception { - Device device = JsonConverter.objectFromJson(req.getReader(), new Device()); - long userId = getUserId(req); - Context.getDataManager().addDevice(device); - Context.getDataManager().linkDevice(userId, device.getId()); - Context.getPermissionsManager().refresh(); - sendResponse(resp.getWriter(), JsonConverter.objectToJson(device)); + @Override + protected void add(HttpServletRequest req, HttpServletResponse resp) throws Exception { + super.add(req, resp, new CommandCall() { + + @Override + public void after() throws Exception { + Context.getDataManager().link(Device.class, getUserId(), getEntity().getId()); + Context.getPermissionsManager().refresh(); + } + + }); } - private void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { - Device device = JsonConverter.objectFromJson(req.getReader(), new Device()); - Context.getPermissionsManager().checkDevice(getUserId(req), device.getId()); - Context.getDataManager().updateDevice(device); - sendResponse(resp.getWriter(), true); + @Override + protected void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { + super.update(req, resp, new CommandCall() { + + @Override + public void check() throws Exception { + Context.getPermissionsManager().check(Device.class, getUserId(), getEntity().getId()); + } + + }); } - private void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception { - Device device = JsonConverter.objectFromJson(req.getReader(), new Device()); - Context.getPermissionsManager().checkDevice(getUserId(req), device.getId()); - Context.getDataManager().removeDevice(device); - Context.getPermissionsManager().refresh(); - sendResponse(resp.getWriter(), true); + @Override + protected void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception { + super.remove(req, resp, new CommandCall() { + + @Override + public void check() throws Exception { + Context.getPermissionsManager().check(Device.class, getUserId(), getEntity().getId()); + } + + @Override + public void after() throws Exception { + Context.getPermissionsManager().refresh(); + } + + }); } private void link(HttpServletRequest req, HttpServletResponse resp) throws Exception { Context.getPermissionsManager().checkAdmin(getUserId(req)); - Context.getDataManager().linkDevice( + Context.getDataManager().link(Device.class, Long.parseLong(req.getParameter("userId")), Long.parseLong(req.getParameter("deviceId"))); Context.getPermissionsManager().refresh(); @@ -104,7 +125,7 @@ public class DeviceServlet extends BaseServlet { private void unlink(HttpServletRequest req, HttpServletResponse resp) throws Exception { Context.getPermissionsManager().checkAdmin(getUserId(req)); - Context.getDataManager().unlinkDevice( + Context.getDataManager().unlink(Device.class, Long.parseLong(req.getParameter("userId")), Long.parseLong(req.getParameter("deviceId"))); Context.getPermissionsManager().refresh(); diff --git a/src/org/traccar/web/JsonConverter.java b/src/org/traccar/web/JsonConverter.java index b19894dd6..d39e6b488 100644 --- a/src/org/traccar/web/JsonConverter.java +++ b/src/org/traccar/web/JsonConverter.java @@ -34,8 +34,8 @@ import javax.json.JsonValue; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; +import org.traccar.helper.Clazz; import org.traccar.helper.Log; -import org.traccar.model.Factory; import org.traccar.model.MiscFormatter; public final class JsonConverter { @@ -49,17 +49,15 @@ public final class JsonConverter { return DATE_FORMAT.parseDateTime(value).toDate(); } - public static T objectFromJson(Reader reader, T prototype) throws ParseException { + public static T objectFromJson(Reader reader, Class clazz) throws ParseException { try (JsonReader jsonReader = Json.createReader(reader)) { - return objectFromJson(jsonReader.readObject(), prototype); + return objectFromJson(jsonReader.readObject(), clazz); } } - public static T objectFromJson(JsonObject json, T prototype) { - T object = (T) prototype.create(); - + public static T objectFromJson(JsonObject json, Class clazz) { + T object = Clazz.newInstance(clazz); Method[] methods = object.getClass().getMethods(); - for (final Method method : methods) { if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) { @@ -91,7 +89,6 @@ public final class JsonConverter { } } } - return object; } diff --git a/src/org/traccar/web/MainServlet.java b/src/org/traccar/web/MainServlet.java index 63ff27813..40bfcddb5 100644 --- a/src/org/traccar/web/MainServlet.java +++ b/src/org/traccar/web/MainServlet.java @@ -45,7 +45,7 @@ public class MainServlet extends BaseServlet { } private void session(HttpServletRequest req, HttpServletResponse resp) throws Exception { - Long userId = (Long) req.getSession().getAttribute(USER_KEY); + Long userId = (Long) req.getSession().getAttribute(USER_ID_KEY); if (userId != null) { sendResponse(resp.getWriter(), JsonConverter.objectToJson( Context.getDataManager().getUser(userId))); @@ -58,7 +58,7 @@ public class MainServlet extends BaseServlet { User user = Context.getDataManager().login( req.getParameter("email"), req.getParameter("password")); if (user != null) { - req.getSession().setAttribute(USER_KEY, user.getId()); + req.getSession().setAttribute(USER_ID_KEY, user.getId()); sendResponse(resp.getWriter(), JsonConverter.objectToJson(user)); } else { sendResponse(resp.getWriter(), false); @@ -66,12 +66,12 @@ public class MainServlet extends BaseServlet { } private void logout(HttpServletRequest req, HttpServletResponse resp) throws Exception { - req.getSession().removeAttribute(USER_KEY); + req.getSession().removeAttribute(USER_ID_KEY); sendResponse(resp.getWriter(), true); } private void register(HttpServletRequest req, HttpServletResponse resp) throws Exception { - User user = JsonConverter.objectFromJson(req.getReader(), new User()); + User user = JsonConverter.objectFromJson(req.getReader(), User.class); Context.getDataManager().addUser(user); sendResponse(resp.getWriter(), true); } diff --git a/src/org/traccar/web/PositionServlet.java b/src/org/traccar/web/PositionServlet.java index 796d6a81f..c63968251 100644 --- a/src/org/traccar/web/PositionServlet.java +++ b/src/org/traccar/web/PositionServlet.java @@ -23,8 +23,9 @@ import org.traccar.model.Position; import java.util.HashMap; import java.util.Map; +import org.traccar.model.Device; -public class PositionServlet extends BaseServlet { +public class PositionServlet extends BaseServletResource { @Override protected boolean handle(String command, HttpServletRequest req, HttpServletResponse resp) throws Exception { @@ -42,9 +43,10 @@ public class PositionServlet extends BaseServlet { return true; } - private void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { + @Override + protected void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { long deviceId = Long.parseLong(req.getParameter("deviceId")); - Context.getPermissionsManager().checkDevice(getUserId(req), deviceId); + Context.getPermissionsManager().check(Device.class, getUserId(req), deviceId); sendResponse(resp.getWriter(), JsonConverter.arrayToJson( Context.getDataManager().getPositions( getUserId(req), deviceId, @@ -59,7 +61,7 @@ public class PositionServlet extends BaseServlet { for (String deviceIdString : req.getParameterValues("devicesId")) { Long deviceId = Long.parseLong(deviceIdString); - Context.getPermissionsManager().checkDevice(userId, deviceId); + Context.getPermissionsManager().check(Device.class, userId, deviceId); Position position = Context.getConnectionManager().getLastPosition(deviceId); positions.put(deviceId.toString(), position); diff --git a/src/org/traccar/web/ServerServlet.java b/src/org/traccar/web/ServerServlet.java index 7ed096bc6..312876f36 100644 --- a/src/org/traccar/web/ServerServlet.java +++ b/src/org/traccar/web/ServerServlet.java @@ -18,16 +18,17 @@ package org.traccar.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.traccar.Context; +import org.traccar.helper.CommandCall; import org.traccar.model.Server; -public class ServerServlet extends BaseServlet { +public class ServerServlet extends BaseServletResource { @Override protected boolean handle(String command, HttpServletRequest req, HttpServletResponse resp) throws Exception { switch (command) { case "/get": - get(resp); + get(req, resp); break; case "/update": update(req, resp); @@ -38,16 +39,22 @@ public class ServerServlet extends BaseServlet { return true; } - private void get(HttpServletResponse resp) throws Exception { - sendResponse(resp.getWriter(), JsonConverter.objectToJson( - Context.getDataManager().getServer())); + @Override + protected void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { + super.update(req, resp, new CommandCall() { + + @Override + public void check() { + Context.getPermissionsManager().checkAdmin(getUserId()); + } + + }); } - private void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { - Server server = JsonConverter.objectFromJson(req.getReader(), new Server()); - Context.getPermissionsManager().checkAdmin(getUserId(req)); - Context.getDataManager().updateServer(server); - sendResponse(resp.getWriter(), true); + @Override + protected void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { + sendResponse(resp.getWriter(), JsonConverter.objectToJson( + Context.getDataManager().getServer())); } } diff --git a/src/org/traccar/web/UserServlet.java b/src/org/traccar/web/UserServlet.java index 6bd870d4d..f7ae19fa9 100644 --- a/src/org/traccar/web/UserServlet.java +++ b/src/org/traccar/web/UserServlet.java @@ -18,9 +18,10 @@ package org.traccar.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.traccar.Context; +import org.traccar.helper.CommandCall; import org.traccar.model.User; -public class UserServlet extends BaseServlet { +public class UserServlet extends BaseServletResource { @Override protected boolean handle(String command, HttpServletRequest req, HttpServletResponse resp) throws Exception { @@ -44,38 +45,64 @@ public class UserServlet extends BaseServlet { return true; } - private void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { + @Override + protected void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { Context.getPermissionsManager().checkAdmin(getUserId(req)); sendResponse(resp.getWriter(), JsonConverter.arrayToJson( Context.getDataManager().getUsers())); } - private void add(HttpServletRequest req, HttpServletResponse resp) throws Exception { - User user = JsonConverter.objectFromJson(req.getReader(), new User()); - Context.getPermissionsManager().checkUser(getUserId(req), user.getId()); - Context.getDataManager().addUser(user); - Context.getPermissionsManager().refresh(); - sendResponse(resp.getWriter(), JsonConverter.objectToJson(user)); - } + @Override + protected void add(HttpServletRequest req, HttpServletResponse resp) throws Exception { + super.add(req, resp, new CommandCall() { - private void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { - User user = JsonConverter.objectFromJson(req.getReader(), new User()); - if (user.getAdmin()) { - Context.getPermissionsManager().checkAdmin(getUserId(req)); - } else { - Context.getPermissionsManager().checkUser(getUserId(req), user.getId()); - } - Context.getDataManager().updateUser(user); - Context.getPermissionsManager().refresh(); - sendResponse(resp.getWriter(), true); + @Override + public void check() throws Exception { + Context.getPermissionsManager().check(User.class, getUserId(), getEntity().getId()); + } + + @Override + public void after() throws Exception { + Context.getPermissionsManager().refresh(); + } + }); } - private void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception { - User user = JsonConverter.objectFromJson(req.getReader(), new User()); - Context.getPermissionsManager().checkUser(getUserId(req), user.getId()); - Context.getDataManager().removeUser(user); - Context.getPermissionsManager().refresh(); - sendResponse(resp.getWriter(), true); + @Override + protected void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { + super.update(req, resp, new CommandCall() { + + @Override + public void check() { + if (getEntity().getAdmin()) { + Context.getPermissionsManager().checkAdmin(getUserId()); + } else { + Context.getPermissionsManager().check(User.class, getUserId(), getEntity().getId()); + } + } + + @Override + public void after() { + Context.getPermissionsManager().refresh(); + } + + }); } + @Override + protected void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception { + super.remove(req, resp, new CommandCall() { + + @Override + public void check() throws Exception { + Context.getPermissionsManager().check(User.class, getUserId(), getEntity().getId()); + } + + @Override + public void after() throws Exception { + Context.getPermissionsManager().refresh(); + } + + }); + } } diff --git a/src/org/traccar/web/WebServer.java b/src/org/traccar/web/WebServer.java index 36c43736d..2e7e1a31b 100644 --- a/src/org/traccar/web/WebServer.java +++ b/src/org/traccar/web/WebServer.java @@ -102,10 +102,15 @@ public class WebServer { servletHandler.setContextPath("/api"); servletHandler.addServlet(new ServletHolder(new AsyncServlet()), "/async/*"); servletHandler.addServlet(new ServletHolder(new ServerServlet()), "/server/*"); + servletHandler.addServlet(new ServletHolder(new ServerServlet()), "/servers/*"); servletHandler.addServlet(new ServletHolder(new UserServlet()), "/user/*"); + servletHandler.addServlet(new ServletHolder(new UserServlet()), "/users/*"); servletHandler.addServlet(new ServletHolder(new DeviceServlet()), "/device/*"); + servletHandler.addServlet(new ServletHolder(new DeviceServlet()), "/devices/*"); servletHandler.addServlet(new ServletHolder(new PositionServlet()), "/position/*"); + servletHandler.addServlet(new ServletHolder(new PositionServlet()), "/positions/*"); servletHandler.addServlet(new ServletHolder(new CommandServlet()), "/command/*"); + servletHandler.addServlet(new ServletHolder(new CommandServlet()), "/commands/*"); servletHandler.addServlet(new ServletHolder(new MainServlet()), "/*"); handlers.addHandler(servletHandler); } -- cgit v1.2.3 From c57bd2d472467b1b3a45aee1b97c9a0aeef5958a Mon Sep 17 00:00:00 2001 From: Rafael Guterres Date: Fri, 27 Nov 2015 03:32:59 -0200 Subject: Initial implementation of new api with jax-rs. Revert servlets to old api and remove plurals. Fix findbugs for header origin. --- pom.xml | 15 +- src/org/traccar/api/ApplicationRole.java | 25 ++++ src/org/traccar/api/AuthorizationBasic.java | 98 +++++++++++++ src/org/traccar/api/BaseResource.java | 99 +++++++++++++ src/org/traccar/api/CORSResponseFilter.java | 54 ++++++++ src/org/traccar/api/ResponseBuilder.java | 129 +++++++++++++++++ src/org/traccar/api/SecurityContextApi.java | 55 ++++++++ src/org/traccar/api/SecurityRequestFilter.java | 82 +++++++++++ src/org/traccar/api/UserPrincipal.java | 74 ++++++++++ src/org/traccar/api/resource/DeviceResource.java | 77 +++++++++++ src/org/traccar/api/resource/UserResource.java | 77 +++++++++++ src/org/traccar/database/DataManager.java | 19 +++ src/org/traccar/database/PermissionsManager.java | 4 +- src/org/traccar/helper/Authorization.java | 49 ------- src/org/traccar/helper/Clazz.java | 9 +- src/org/traccar/web/BaseServlet.java | 19 +-- src/org/traccar/web/BaseServletResource.java | 169 ----------------------- src/org/traccar/web/DeviceServlet.java | 67 +++------ src/org/traccar/web/JsonConverter.java | 17 +++ src/org/traccar/web/PositionServlet.java | 10 +- src/org/traccar/web/ServerServlet.java | 27 ++-- src/org/traccar/web/UserServlet.java | 77 ++++------- src/org/traccar/web/WebServer.java | 22 ++- 23 files changed, 910 insertions(+), 364 deletions(-) create mode 100644 src/org/traccar/api/ApplicationRole.java create mode 100644 src/org/traccar/api/AuthorizationBasic.java create mode 100644 src/org/traccar/api/BaseResource.java create mode 100644 src/org/traccar/api/CORSResponseFilter.java create mode 100644 src/org/traccar/api/ResponseBuilder.java create mode 100644 src/org/traccar/api/SecurityContextApi.java create mode 100644 src/org/traccar/api/SecurityRequestFilter.java create mode 100644 src/org/traccar/api/UserPrincipal.java create mode 100644 src/org/traccar/api/resource/DeviceResource.java create mode 100644 src/org/traccar/api/resource/UserResource.java delete mode 100644 src/org/traccar/helper/Authorization.java delete mode 100644 src/org/traccar/web/BaseServletResource.java (limited to 'src/org/traccar') diff --git a/pom.xml b/pom.xml index 5403f40c1..98807bfbe 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,5 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 org.traccar @@ -12,6 +12,7 @@ UTF-8 9.2.14.v20151106 + 2.22.1 @@ -91,6 +92,16 @@ jetty-jndi ${jetty.version} + + org.glassfish.jersey.containers + jersey-container-servlet + ${jersey.version} + + + org.glassfish.jersey.media + jersey-media-moxy + ${jersey.version} + @@ -183,7 +194,7 @@ maven-project-info-reports-plugin 2.8.1 - false + false diff --git a/src/org/traccar/api/ApplicationRole.java b/src/org/traccar/api/ApplicationRole.java new file mode 100644 index 000000000..4da5f6708 --- /dev/null +++ b/src/org/traccar/api/ApplicationRole.java @@ -0,0 +1,25 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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; + +public final class ApplicationRole { + + public static final String USER = "USER"; + public static final String ADMIN = "ADMIN"; + + private ApplicationRole() { + } +} diff --git a/src/org/traccar/api/AuthorizationBasic.java b/src/org/traccar/api/AuthorizationBasic.java new file mode 100644 index 000000000..807320940 --- /dev/null +++ b/src/org/traccar/api/AuthorizationBasic.java @@ -0,0 +1,98 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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; + +import java.sql.SQLException; +import java.util.List; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeSet; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.core.MultivaluedMap; +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.handler.codec.base64.Base64; +import org.jboss.netty.util.CharsetUtil; +import org.traccar.Context; +import org.traccar.model.User; + +public final class AuthorizationBasic { + + private AuthorizationBasic() { + } + + public static final String AUTHORIZATION_HEADER = "Authorization"; + public static final String AUTHORIZATION_SCHEME_VALUE = "Basic"; + public static final String REGEX = AUTHORIZATION_SCHEME_VALUE + " "; + public static final String REPLACEMENT = ""; + public static final String TOKENIZER = ":"; + public static final String USERNAME = "username"; + public static final String PASSWORD = "password"; + public static final String WWW_AUTHENTICATE_VALUE = "Basic realm=\"api\""; + + public static UserPrincipal getUserPrincipal(ContainerRequestContext requestContext) { + final MultivaluedMap headers = requestContext.getHeaders(); + final List authorization = headers.get(AUTHORIZATION_HEADER); + if (authorization == null || authorization.isEmpty()) { + return null; + } + final String encodedUsernameAndPassword = authorization.get(0).replaceFirst(REGEX, REPLACEMENT); + ChannelBuffer buffer = ChannelBuffers.copiedBuffer(encodedUsernameAndPassword, CharsetUtil.UTF_8); + String usernameAndPassword = Base64.decode(buffer).toString(CharsetUtil.UTF_8); + final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, TOKENIZER); + String username = tokenizer.nextToken(); + String password = tokenizer.nextToken(); + Set roles = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + UserPrincipal userPrincipal = new UserPrincipal(username, password, roles); + return userPrincipal; + } + + public static boolean isAuthenticatedUser(UserPrincipal userPrincipal) { + if (userPrincipal.getName() != null && userPrincipal.getPassword() != null) { + User user; + try { + user = Context.getDataManager().login(userPrincipal.getName(), userPrincipal.getPassword()); + } catch (SQLException e) { + return false; + } + if (user != null) { + userPrincipal.setId(user.getId()); + /* + for (Role role : user.getRoles()) { + userPrincipal.getRoles().add(role.getName()); + } + */ + + //Temporary solution + userPrincipal.getRoles().add(ApplicationRole.USER); + if (user.getAdmin()) { + userPrincipal.getRoles().add(ApplicationRole.ADMIN); + } + return true; + } + } + return false; + } + + public static boolean isAuthorizedUser(UserPrincipal userPrincipal, Set roles) { + for (String role : roles) { + if (userPrincipal.getRoles().contains(role)) { + return true; + } + } + return false; + } +} diff --git a/src/org/traccar/api/BaseResource.java b/src/org/traccar/api/BaseResource.java new file mode 100644 index 000000000..54d606ab6 --- /dev/null +++ b/src/org/traccar/api/BaseResource.java @@ -0,0 +1,99 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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; + +import java.sql.SQLException; +import java.util.Collection; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; +import org.traccar.Context; +import org.traccar.helper.Clazz; + +public class BaseResource { + + private final Class clazz = Clazz.getGenericArgumentType(getClass()); + + @javax.ws.rs.core.Context + private SecurityContext securityContext; + + public Collection getEntities() { + Collection collection; + try { + collection = Context.getDataManager().get(clazz); + } catch (SQLException e) { + throw new WebApplicationException(ResponseBuilder.badRequest(e)); + } + if (collection == null || collection.isEmpty()) { + throw new WebApplicationException(ResponseBuilder.notFound()); + } else { + return collection; + } + } + + public T getEntity(I id) { + validateSecurityContext(ApplicationRole.USER, id); + T entity = Clazz.newInstance(clazz); + try { + Clazz.setId(entity, id); + entity = Context.getDataManager().get(entity); + } catch (Exception e) { + throw new WebApplicationException(ResponseBuilder.badRequest(e)); + } + if (entity == null) { + throw new WebApplicationException(ResponseBuilder.notFound()); + } else { + return entity; + } + } + + public Response postEntity(T entity) { + try { + Context.getDataManager().add(entity); + return ResponseBuilder.ok(entity); + } catch (Exception e) { + return ResponseBuilder.badRequest(e); + } + } + + public Response putEntity(I id, T entity) { + try { + Clazz.setId(entity, id); + Context.getDataManager().update(entity); + return ResponseBuilder.ok(entity); + } catch (Exception e) { + return ResponseBuilder.badRequest(e); + } + } + + public Response deleteEntity(I id) { + try { + T entity = Clazz.newInstance(clazz); + Clazz.setId(entity, id); + Context.getDataManager().remove(entity); + return ResponseBuilder.deleted(); + } catch (Exception e) { + return ResponseBuilder.badRequest(e); + } + } + + private void validateSecurityContext(String role, I id) { + UserPrincipal userPrincipal = (UserPrincipal) securityContext.getUserPrincipal(); + if (!securityContext.isUserInRole(role) && !userPrincipal.getId().equals(id)) { + throw new WebApplicationException(ResponseBuilder.forbidden()); + } + } +} diff --git a/src/org/traccar/api/CORSResponseFilter.java b/src/org/traccar/api/CORSResponseFilter.java new file mode 100644 index 000000000..039a749c4 --- /dev/null +++ b/src/org/traccar/api/CORSResponseFilter.java @@ -0,0 +1,54 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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; + +import java.io.IOException; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.ext.Provider; + +@Provider +public class CORSResponseFilter implements ContainerResponseFilter { + + public static final String ACCESS_CONTROL_ALLOW_ORIGIN_KEY = "Access-Control-Allow-Origin"; + public static final String ACCESS_CONTROL_ALLOW_ORIGIN_VALUE = "*"; + + public static final String ACCESS_CONTROL_ALLOW_HEADERS_KEY = "Access-Control-Allow-Headers"; + public static final String ACCESS_CONTROL_ALLOW_HEADERS_VALUE = "origin, content-type, accept, authorization"; + + public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_KEY = "Access-Control-Allow-Credentials"; + public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE = "true"; + + public static final String ACCESS_CONTROL_ALLOW_METHODS_KEY = "Access-Control-Allow-Methods"; + public static final String ACCESS_CONTROL_ALLOW_METHODS_VALUE = "GET, POST, PUT, DELETE"; + + @Override + public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException { + if (!response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN_KEY)) { + response.getHeaders().add(ACCESS_CONTROL_ALLOW_ORIGIN_KEY, ACCESS_CONTROL_ALLOW_ORIGIN_VALUE); + } + if (!response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_HEADERS_KEY)) { + response.getHeaders().add(ACCESS_CONTROL_ALLOW_HEADERS_KEY, ACCESS_CONTROL_ALLOW_HEADERS_VALUE); + } + if (!response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_CREDENTIALS_KEY)) { + response.getHeaders().add(ACCESS_CONTROL_ALLOW_CREDENTIALS_KEY, ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE); + } + if (!response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_METHODS_KEY)) { + response.getHeaders().add(ACCESS_CONTROL_ALLOW_METHODS_KEY, ACCESS_CONTROL_ALLOW_METHODS_VALUE); + } + } +} diff --git a/src/org/traccar/api/ResponseBuilder.java b/src/org/traccar/api/ResponseBuilder.java new file mode 100644 index 000000000..195cb1923 --- /dev/null +++ b/src/org/traccar/api/ResponseBuilder.java @@ -0,0 +1,129 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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; + +import java.io.Serializable; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; +import javax.ws.rs.core.Response; + +public final class ResponseBuilder implements Serializable { + + private static final long serialVersionUID = -2348334499023022836L; + + private static final String WWW_AUTHENTICATE = "WWW-Authenticate"; + private static final String BASIC_REALM = "Basic realm=\"api\""; + private static final String ERROR = "error"; + + private ResponseBuilder() { + } + + public static Response ok() { + return Response.status(Response.Status.OK).build(); + } + + public static Response ok(T entity) { + return Response.status(Response.Status.OK).entity(entity).build(); + } + + public static Response ok(Collection entities) { + return Response.ok(entities).build(); + } + + public static Response created() { + return Response.status(Response.Status.CREATED).build(); + } + + public static Response created(T entity) { + return Response.status(Response.Status.CREATED).entity(entity).build(); + } + + public static Response accepted() { + return Response.status(Response.Status.ACCEPTED).build(); + } + + public static Response accepted(T entity) { + return Response.status(Response.Status.ACCEPTED).entity(entity).build(); + } + + public static Response deleted() { + return Response.status(Response.Status.NO_CONTENT).build(); + } + + public static Response notModified() { + return Response.status(Response.Status.NOT_MODIFIED).build(); + } + + public static Response badRequest() { + return Response.status(Response.Status.BAD_REQUEST).build(); + } + + public static Response badRequest(Exception e) { + return Response.status(Response.Status.BAD_REQUEST).entity(getError(e)).build(); + } + + public static Response unauthorized() { + return Response.status(Response.Status.UNAUTHORIZED).header(WWW_AUTHENTICATE, BASIC_REALM).build(); + } + + public static Response forbidden() { + return Response.status(Response.Status.FORBIDDEN).entity(getError(Response.Status.FORBIDDEN.name())).build(); + } + + public static Response notFound() { + return Response.status(Response.Status.NOT_FOUND).build(); + } + + public static Response timeout() { + return Response.status(Response.Status.REQUEST_TIMEOUT).build(); + } + + public static Response conflict() { + return Response.status(Response.Status.CONFLICT).build(); + } + + public static Response conflict(Exception e) { + return Response.status(Response.Status.CONFLICT).entity(getError(e)).build(); + } + + public static Response notImplemented() { + return Response.status(Response.Status.NOT_IMPLEMENTED).build(); + } + + public static Response redirect(String uri) { + try { + return Response.seeOther(new URI(uri)).build(); + } catch (URISyntaxException e) { + Logger.getAnonymousLogger().warning(e.getMessage()); + return null; + } + } + + private static Map getError(Exception e) { + return getError(e.getMessage()); + } + + private static Map getError(String message) { + Map error = new HashMap<>(); + error.put(ERROR, message); + return error; + } + +} diff --git a/src/org/traccar/api/SecurityContextApi.java b/src/org/traccar/api/SecurityContextApi.java new file mode 100644 index 000000000..df10340c5 --- /dev/null +++ b/src/org/traccar/api/SecurityContextApi.java @@ -0,0 +1,55 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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; + +import java.security.Principal; +import javax.ws.rs.core.SecurityContext; + +public class SecurityContextApi implements SecurityContext { + + private static final String AUTHENTICATION_SCHEME = "BASIC"; + private static final boolean IS_SECURE = true; + + private Principal userPrincipal; + + public SecurityContextApi(Principal userPrincipal) { + this.userPrincipal = userPrincipal; + } + + public SecurityContextApi() { + } + + @Override + public Principal getUserPrincipal() { + return userPrincipal; + } + + @Override + public boolean isUserInRole(String role) { + UserPrincipal user = (UserPrincipal) userPrincipal; + return user.getRoles().contains(role); + } + + @Override + public boolean isSecure() { + return IS_SECURE; + } + + @Override + public String getAuthenticationScheme() { + return AUTHENTICATION_SCHEME; + } +} diff --git a/src/org/traccar/api/SecurityRequestFilter.java b/src/org/traccar/api/SecurityRequestFilter.java new file mode 100644 index 000000000..9d59cdc01 --- /dev/null +++ b/src/org/traccar/api/SecurityRequestFilter.java @@ -0,0 +1,82 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import javax.annotation.security.DenyAll; +import javax.annotation.security.PermitAll; +import javax.annotation.security.RolesAllowed; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.ResourceInfo; +import javax.ws.rs.ext.Provider; + +@Provider +public class SecurityRequestFilter implements ContainerRequestFilter { + + @javax.ws.rs.core.Context + private ResourceInfo resourceInfo; + + @Override + public void filter(ContainerRequestContext requestContext) { + Method method = resourceInfo.getResourceMethod(); + + //@PermitAll + if (method.isAnnotationPresent(PermitAll.class)) { + return; + } + + //@DenyAll + if (method.isAnnotationPresent(DenyAll.class)) { + requestContext.abortWith(ResponseBuilder.forbidden()); + return; + } + + //AuthorizationBasic + UserPrincipal userPrincipal = AuthorizationBasic.getUserPrincipal(requestContext); + if (userPrincipal == null + || userPrincipal.getName() == null + || userPrincipal.getPassword() == null + || !isAuthenticatedUser(userPrincipal)) { + requestContext.abortWith(ResponseBuilder.unauthorized()); + return; + } + + //@RolesAllowed + if (method.isAnnotationPresent(RolesAllowed.class)) { + RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class); + Set roles = new HashSet<>(Arrays.asList(rolesAnnotation.value())); + if (!isAuthorizedUser(userPrincipal, roles)) { + requestContext.abortWith(ResponseBuilder.forbidden()); + return; + } + } + + //SecurityContext + requestContext.setSecurityContext(new SecurityContextApi(userPrincipal)); + } + + private boolean isAuthenticatedUser(UserPrincipal principal) { + return AuthorizationBasic.isAuthenticatedUser(principal); + } + + private boolean isAuthorizedUser(UserPrincipal userPrincipal, Set roles) { + return AuthorizationBasic.isAuthorizedUser(userPrincipal, roles); + } +} diff --git a/src/org/traccar/api/UserPrincipal.java b/src/org/traccar/api/UserPrincipal.java new file mode 100644 index 000000000..387b7627c --- /dev/null +++ b/src/org/traccar/api/UserPrincipal.java @@ -0,0 +1,74 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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; + +import java.security.Principal; +import java.util.Set; + +public class UserPrincipal implements Principal { + + private Long id; + private String username; + private String password; + private Set roles; + + public UserPrincipal(String username, String password, Set roles) { + this.username = username; + this.password = password; + this.roles = roles; + } + + public UserPrincipal(String username, Set roles) { + this.username = username; + this.roles = roles; + } + + public UserPrincipal(String username) { + this.username = username; + } + + public UserPrincipal() { + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + @Override + public String getName() { + return username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Set getRoles() { + return roles; + } + + public void setRoles(Set roles) { + this.roles = roles; + } +} diff --git a/src/org/traccar/api/resource/DeviceResource.java b/src/org/traccar/api/resource/DeviceResource.java new file mode 100644 index 000000000..4152bcf81 --- /dev/null +++ b/src/org/traccar/api/resource/DeviceResource.java @@ -0,0 +1,77 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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.resource; + +import org.traccar.api.BaseResource; +import java.util.Collection; +import javax.annotation.security.RolesAllowed; +import javax.ws.rs.Consumes; +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.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.traccar.api.ApplicationRole; +import org.traccar.model.Device; + +@Path("devices") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class DeviceResource extends BaseResource { + + @GET + @RolesAllowed(ApplicationRole.ADMIN) + @Override + public Collection getEntities() { + return super.getEntities(); + } + + @GET + @Path("{id}") + @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @Override + public Device getEntity(@PathParam("id") Long id) { + return super.getEntity(id); + } + + @POST + @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @Override + public Response postEntity(Device entity) { + return super.postEntity(entity); + } + + @PUT + @Path("{id}") + @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @Override + public Response putEntity(@PathParam("id") Long id, Device entity) { + return super.putEntity(id, entity); + } + + @DELETE + @Path("{id}") + @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @Override + public Response deleteEntity(@PathParam("id") Long id) { + return super.deleteEntity(id); + } + +} diff --git a/src/org/traccar/api/resource/UserResource.java b/src/org/traccar/api/resource/UserResource.java new file mode 100644 index 000000000..da615e052 --- /dev/null +++ b/src/org/traccar/api/resource/UserResource.java @@ -0,0 +1,77 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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.resource; + +import java.util.Collection; +import javax.annotation.security.RolesAllowed; +import javax.ws.rs.Consumes; +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.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.traccar.api.ApplicationRole; +import org.traccar.api.BaseResource; +import org.traccar.model.User; + +@Path("users") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class UserResource extends BaseResource { + + @GET + @RolesAllowed(ApplicationRole.ADMIN) + @Override + public Collection getEntities() { + return super.getEntities(); + } + + @GET + @Path("{id}") + @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @Override + public User getEntity(@PathParam("id") Long id) { + return super.getEntity(id); + } + + @POST + @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @Override + public Response postEntity(User entity) { + return super.postEntity(entity); + } + + @PUT + @Path("{id}") + @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @Override + public Response putEntity(@PathParam("id") Long id, User entity) { + return super.putEntity(id, entity); + } + + @DELETE + @Path("{id}") + @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @Override + public Response deleteEntity(@PathParam("id") Long id) { + return super.deleteEntity(id); + } + +} diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java index 530ec1779..c98a5ede7 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -31,6 +31,7 @@ import java.util.Map; import javax.naming.InitialContext; import javax.sql.DataSource; import org.traccar.Config; +import org.traccar.helper.Clazz; import org.traccar.helper.DriverDelegate; import org.traccar.helper.Log; import org.traccar.model.Device; @@ -385,6 +386,24 @@ public class DataManager implements IdentityManager { .executeUpdate(); } + public Collection get(Class clazz) throws SQLException { + if (clazz.equals(User.class)) { + return (Collection) getUsers(); + } else if (clazz.equals(Device.class)) { + return (Collection) getAllDevices(); + } + return null; + } + + public T get(T entity) throws Exception { + if (entity instanceof User) { + return (T) getUser(Clazz.getId(entity)); + } else if (entity instanceof Device) { + return (T) getDeviceById(Clazz.getId(entity)); + } + return null; + } + public void add(Object entity) throws SQLException { if (entity instanceof User) { addUser((User) entity); diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java index 138641973..0a43f4ff4 100644 --- a/src/org/traccar/database/PermissionsManager.java +++ b/src/org/traccar/database/PermissionsManager.java @@ -67,7 +67,7 @@ public class PermissionsManager { } } - private void checkUser(long userId, long otherUserId) throws SecurityException { + public void checkUser(long userId, long otherUserId) throws SecurityException { if (userId != otherUserId) { checkAdmin(userId); } @@ -77,7 +77,7 @@ public class PermissionsManager { return getNotNull(userId); } - private void checkDevice(long userId, long deviceId) throws SecurityException { + public void checkDevice(long userId, long deviceId) throws SecurityException { if (!getNotNull(userId).contains(deviceId)) { throw new SecurityException("Device access denied"); } diff --git a/src/org/traccar/helper/Authorization.java b/src/org/traccar/helper/Authorization.java deleted file mode 100644 index d0877630d..000000000 --- a/src/org/traccar/helper/Authorization.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * 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.helper; - -import java.util.HashMap; -import java.util.Map; -import java.util.StringTokenizer; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.handler.codec.base64.Base64; -import org.jboss.netty.util.CharsetUtil; - -public final class Authorization { - - private Authorization() { - } - - public static final String AUTHORIAZTION_SCHEME_VALUE = "Basic"; - public static final String REGEX = AUTHORIAZTION_SCHEME_VALUE + " "; - public static final String REPLACEMENT = ""; - public static final String TOKENIZER = ":"; - public static final String USERNAME = "username"; - public static final String PASSWORD = "password"; - public static final String WWW_AUTHENTICATE_VALUE = "Basic realm=\"api\""; - - public static Map parse(String authorization) { - Map authMap = new HashMap<>(); - final String encodedUsernameAndPassword = authorization.replaceFirst(REGEX, REPLACEMENT); - ChannelBuffer buffer = ChannelBuffers.copiedBuffer(encodedUsernameAndPassword, CharsetUtil.UTF_8); - String usernameAndPassword = Base64.decode(buffer).toString(CharsetUtil.UTF_8); - final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, TOKENIZER); - authMap.put(USERNAME, tokenizer.nextToken()); - authMap.put(PASSWORD, tokenizer.nextToken()); - return authMap; - } -} diff --git a/src/org/traccar/helper/Clazz.java b/src/org/traccar/helper/Clazz.java index bdde940a0..ba4c4fded 100644 --- a/src/org/traccar/helper/Clazz.java +++ b/src/org/traccar/helper/Clazz.java @@ -16,11 +16,14 @@ package org.traccar.helper; import java.beans.Introspector; +import java.io.Serializable; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -public final class Clazz { +public final class Clazz implements Serializable { + + private static final long serialVersionUID = 4983299355055144885L; private Clazz() { } @@ -77,7 +80,7 @@ public final class Clazz { } } - public static long getId(Object entity) throws Exception { + public static long getId(T entity) throws Exception { Method[] methods = entity.getClass().getMethods(); for (final Method method : methods) { if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { @@ -90,7 +93,7 @@ public final class Clazz { throw new IllegalArgumentException(); } - public static void setId(Object entity, long id) throws Exception { + public static void setId(T entity, I id) throws Exception { Method[] methods = entity.getClass().getMethods(); for (final Method method : methods) { if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) { diff --git a/src/org/traccar/web/BaseServlet.java b/src/org/traccar/web/BaseServlet.java index 916eb6a18..d215c62d0 100644 --- a/src/org/traccar/web/BaseServlet.java +++ b/src/org/traccar/web/BaseServlet.java @@ -19,9 +19,10 @@ import org.traccar.helper.Log; import java.io.IOException; import java.io.Writer; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.security.AccessControlException; import java.util.Collection; -import java.util.Map; import javax.json.Json; import javax.json.JsonObjectBuilder; import javax.json.JsonStructure; @@ -32,8 +33,6 @@ import javax.servlet.http.HttpServletResponse; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.util.CharsetUtil; import org.traccar.Context; -import org.traccar.helper.Authorization; -import org.traccar.model.User; public abstract class BaseServlet extends HttpServlet { @@ -57,7 +56,8 @@ public abstract class BaseServlet extends HttpServlet { if (allowed == null) { resp.setHeader(HttpHeaders.Names.ACCESS_CONTROL_ALLOW_ORIGIN, ALLOW_ORIGIN_VALUE); } else if (allowed.contains(origin)) { - resp.setHeader(HttpHeaders.Names.ACCESS_CONTROL_ALLOW_ORIGIN, origin); + String originSafe = URLEncoder.encode(origin, StandardCharsets.UTF_8.displayName()); + resp.setHeader(HttpHeaders.Names.ACCESS_CONTROL_ALLOW_ORIGIN, originSafe); } if (!handle(getCommand(req), req, resp)) { @@ -66,7 +66,6 @@ public abstract class BaseServlet extends HttpServlet { } catch (Exception error) { if (error instanceof AccessControlException) { resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - resp.addHeader(HttpHeaders.Names.WWW_AUTHENTICATE, Authorization.WWW_AUTHENTICATE_VALUE); } else if (error instanceof SecurityException) { resp.setStatus(HttpServletResponse.SC_FORBIDDEN); } @@ -82,16 +81,6 @@ public abstract class BaseServlet extends HttpServlet { if (userId != null) { return (Long) userId; } - String authorization = req.getHeader(HttpHeaders.Names.AUTHORIZATION); - if (authorization != null && !authorization.isEmpty()) { - Map authMap = Authorization.parse(authorization); - String username = authMap.get(Authorization.USERNAME); - String password = authMap.get(Authorization.PASSWORD); - User user = Context.getDataManager().login(username, password); - if (user != null) { - return user.getId(); - } - } throw new AccessControlException("User not logged in"); } diff --git a/src/org/traccar/web/BaseServletResource.java b/src/org/traccar/web/BaseServletResource.java deleted file mode 100644 index 318f0d7b6..000000000 --- a/src/org/traccar/web/BaseServletResource.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * 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.web; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.traccar.Context; -import org.traccar.helper.CommandCall; -import org.traccar.helper.Clazz; - -/** - * - * @author Rafael - */ -public abstract class BaseServletResource extends BaseServlet { - - private final Class clazz = Clazz.getGenericArgumentType(getClass()); - - public static final String GET = "GET"; - public static final String POST = "POST"; - public static final String PUT = "PUT"; - public static final String DELETE = "DELETE"; - - public static final String PATH_PARAM_ID = "/\\d"; - public static final String SLASH = "/"; - public static final String VOID = ""; - - @Override - protected String getCommand(HttpServletRequest req) { - String command = req.getPathInfo(); - if (command == null || command.matches(PATH_PARAM_ID)) { - switch (req.getMethod()) { - case GET: - command = "/get"; - break; - case POST: - command = "/add"; - break; - case PUT: - command = "/update"; - break; - case DELETE: - command = "/remove"; - break; - default: - command = ""; - } - } - return command; - } - - protected String getPathParamId(String pathInfo) { - if (pathInfo != null && pathInfo.matches(PATH_PARAM_ID)) { - return pathInfo.replaceAll(SLASH, VOID); - } - return null; - } - - protected abstract void get(HttpServletRequest req, HttpServletResponse resp) throws Exception; - - protected void add(HttpServletRequest req, HttpServletResponse resp) throws Exception { - add(req, resp, null); - } - - protected void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { - update(req, resp, null); - } - - protected void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception { - remove(req, resp, null); - } - - protected void add(HttpServletRequest req, HttpServletResponse resp, CommandCall commandCall) throws Exception { - if (commandCall != null) { - commandCall.before(); - } - - T entity = JsonConverter.objectFromJson(req.getReader(), this.clazz); - long userId = getUserId(req); - if (commandCall != null) { - commandCall.setUserId(userId); - commandCall.setEntity(entity); - commandCall.check(); - } - - Context.getDataManager().add(entity); - - long entityId = Clazz.getId(entity); - Context.getDataManager().link(this.clazz, userId, entityId); - - if (commandCall != null) { - commandCall.after(); - } - - sendResponse(resp.getWriter(), JsonConverter.objectToJson(entity)); - } - - protected void update(HttpServletRequest req, HttpServletResponse resp, - CommandCall commandCall) throws Exception { - if (commandCall != null) { - commandCall.before(); - } - - T entity = JsonConverter.objectFromJson(req.getReader(), this.clazz); - String entityId = getPathParamId(req.getPathInfo()); - if (entityId != null) { - Clazz.setId(entity, Long.parseLong(entityId)); - } - long userId = getUserId(req); - - if (commandCall != null) { - commandCall.setUserId(userId); - commandCall.setEntity(entity); - commandCall.check(); - } - - Context.getDataManager().update(entity); - - if (commandCall != null) { - commandCall.after(); - } - - sendResponse(resp.getWriter(), true); - } - - protected void remove(HttpServletRequest req, HttpServletResponse resp, - CommandCall commandCall) throws Exception { - if (commandCall != null) { - commandCall.before(); - } - - T entity = Clazz.newInstance(this.clazz); - String entityId = getPathParamId(req.getPathInfo()); - if (entityId != null) { - Clazz.setId(entity, Long.parseLong(entityId)); - } else { - entity = JsonConverter.objectFromJson(req.getReader(), this.clazz); - } - long userId = getUserId(req); - - if (commandCall != null) { - commandCall.setUserId(userId); - commandCall.setEntity(entity); - commandCall.check(); - } - - Context.getDataManager().remove(entity); - - if (commandCall != null) { - commandCall.after(); - } - - sendResponse(resp.getWriter(), true); - } - -} diff --git a/src/org/traccar/web/DeviceServlet.java b/src/org/traccar/web/DeviceServlet.java index 7900538bb..8f983ad78 100644 --- a/src/org/traccar/web/DeviceServlet.java +++ b/src/org/traccar/web/DeviceServlet.java @@ -18,11 +18,9 @@ package org.traccar.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.traccar.Context; -import org.traccar.helper.CommandCall; import org.traccar.model.Device; -import org.traccar.model.User; -public class DeviceServlet extends BaseServletResource { +public class DeviceServlet extends BaseServlet { @Override protected boolean handle(String command, HttpServletRequest req, HttpServletResponse resp) throws Exception { @@ -52,8 +50,7 @@ public class DeviceServlet extends BaseServletResource { return true; } - @Override - protected void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { + private void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { if (Boolean.parseBoolean(req.getParameter("all"))) { Context.getPermissionsManager().checkAdmin(getUserId(req)); sendResponse(resp.getWriter(), JsonConverter.arrayToJson( @@ -66,57 +63,39 @@ public class DeviceServlet extends BaseServletResource { } else { userId = getUserId(req); } - Context.getPermissionsManager().check(User.class, getUserId(req), userId); + Context.getPermissionsManager().checkUser(getUserId(req), userId); sendResponse(resp.getWriter(), JsonConverter.arrayToJson( Context.getDataManager().getDevices(userId))); } } - @Override - protected void add(HttpServletRequest req, HttpServletResponse resp) throws Exception { - super.add(req, resp, new CommandCall() { - - @Override - public void after() throws Exception { - Context.getDataManager().link(Device.class, getUserId(), getEntity().getId()); - Context.getPermissionsManager().refresh(); - } - - }); + private void add(HttpServletRequest req, HttpServletResponse resp) throws Exception { + Device device = JsonConverter.objectFromJson(req.getReader(), new Device()); + long userId = getUserId(req); + Context.getDataManager().addDevice(device); + Context.getDataManager().linkDevice(userId, device.getId()); + Context.getPermissionsManager().refresh(); + sendResponse(resp.getWriter(), JsonConverter.objectToJson(device)); } - @Override - protected void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { - super.update(req, resp, new CommandCall() { - - @Override - public void check() throws Exception { - Context.getPermissionsManager().check(Device.class, getUserId(), getEntity().getId()); - } - - }); + private void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { + Device device = JsonConverter.objectFromJson(req.getReader(), new Device()); + Context.getPermissionsManager().checkDevice(getUserId(req), device.getId()); + Context.getDataManager().updateDevice(device); + sendResponse(resp.getWriter(), true); } - @Override - protected void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception { - super.remove(req, resp, new CommandCall() { - - @Override - public void check() throws Exception { - Context.getPermissionsManager().check(Device.class, getUserId(), getEntity().getId()); - } - - @Override - public void after() throws Exception { - Context.getPermissionsManager().refresh(); - } - - }); + private void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception { + Device device = JsonConverter.objectFromJson(req.getReader(), new Device()); + Context.getPermissionsManager().checkDevice(getUserId(req), device.getId()); + Context.getDataManager().removeDevice(device); + Context.getPermissionsManager().refresh(); + sendResponse(resp.getWriter(), true); } private void link(HttpServletRequest req, HttpServletResponse resp) throws Exception { Context.getPermissionsManager().checkAdmin(getUserId(req)); - Context.getDataManager().link(Device.class, + Context.getDataManager().linkDevice( Long.parseLong(req.getParameter("userId")), Long.parseLong(req.getParameter("deviceId"))); Context.getPermissionsManager().refresh(); @@ -125,7 +104,7 @@ public class DeviceServlet extends BaseServletResource { private void unlink(HttpServletRequest req, HttpServletResponse resp) throws Exception { Context.getPermissionsManager().checkAdmin(getUserId(req)); - Context.getDataManager().unlink(Device.class, + Context.getDataManager().unlinkDevice( Long.parseLong(req.getParameter("userId")), Long.parseLong(req.getParameter("deviceId"))); Context.getPermissionsManager().refresh(); diff --git a/src/org/traccar/web/JsonConverter.java b/src/org/traccar/web/JsonConverter.java index a8b68613b..38721db61 100644 --- a/src/org/traccar/web/JsonConverter.java +++ b/src/org/traccar/web/JsonConverter.java @@ -36,6 +36,7 @@ import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; import org.traccar.helper.Clazz; import org.traccar.helper.Log; +import org.traccar.model.Factory; import org.traccar.model.MiscFormatter; public final class JsonConverter { @@ -49,6 +50,18 @@ public final class JsonConverter { return DATE_FORMAT.parseDateTime(value).toDate(); } + public static T objectFromJson(Reader reader, T prototype) throws ParseException { + try (JsonReader jsonReader = Json.createReader(reader)) { + return objectFromJson(jsonReader.readObject(), prototype); + } + } + + public static T objectFromJson(JsonObject json, T prototype) { + T object = (T) prototype.create(); + Method[] methods = object.getClass().getMethods(); + return objectFromJson(json, object, methods); + } + public static T objectFromJson(Reader reader, Class clazz) throws ParseException { try (JsonReader jsonReader = Json.createReader(reader)) { return objectFromJson(jsonReader.readObject(), clazz); @@ -58,6 +71,10 @@ public final class JsonConverter { public static T objectFromJson(JsonObject json, Class clazz) { T object = Clazz.newInstance(clazz); Method[] methods = object.getClass().getMethods(); + return objectFromJson(json, object, methods); + } + + private static T objectFromJson(JsonObject json, T object, Method[] methods) { for (final Method method : methods) { if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) { diff --git a/src/org/traccar/web/PositionServlet.java b/src/org/traccar/web/PositionServlet.java index c63968251..796d6a81f 100644 --- a/src/org/traccar/web/PositionServlet.java +++ b/src/org/traccar/web/PositionServlet.java @@ -23,9 +23,8 @@ import org.traccar.model.Position; import java.util.HashMap; import java.util.Map; -import org.traccar.model.Device; -public class PositionServlet extends BaseServletResource { +public class PositionServlet extends BaseServlet { @Override protected boolean handle(String command, HttpServletRequest req, HttpServletResponse resp) throws Exception { @@ -43,10 +42,9 @@ public class PositionServlet extends BaseServletResource { return true; } - @Override - protected void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { + private void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { long deviceId = Long.parseLong(req.getParameter("deviceId")); - Context.getPermissionsManager().check(Device.class, getUserId(req), deviceId); + Context.getPermissionsManager().checkDevice(getUserId(req), deviceId); sendResponse(resp.getWriter(), JsonConverter.arrayToJson( Context.getDataManager().getPositions( getUserId(req), deviceId, @@ -61,7 +59,7 @@ public class PositionServlet extends BaseServletResource { for (String deviceIdString : req.getParameterValues("devicesId")) { Long deviceId = Long.parseLong(deviceIdString); - Context.getPermissionsManager().check(Device.class, userId, deviceId); + Context.getPermissionsManager().checkDevice(userId, deviceId); Position position = Context.getConnectionManager().getLastPosition(deviceId); positions.put(deviceId.toString(), position); diff --git a/src/org/traccar/web/ServerServlet.java b/src/org/traccar/web/ServerServlet.java index 312876f36..7ed096bc6 100644 --- a/src/org/traccar/web/ServerServlet.java +++ b/src/org/traccar/web/ServerServlet.java @@ -18,17 +18,16 @@ package org.traccar.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.traccar.Context; -import org.traccar.helper.CommandCall; import org.traccar.model.Server; -public class ServerServlet extends BaseServletResource { +public class ServerServlet extends BaseServlet { @Override protected boolean handle(String command, HttpServletRequest req, HttpServletResponse resp) throws Exception { switch (command) { case "/get": - get(req, resp); + get(resp); break; case "/update": update(req, resp); @@ -39,22 +38,16 @@ public class ServerServlet extends BaseServletResource { return true; } - @Override - protected void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { - super.update(req, resp, new CommandCall() { - - @Override - public void check() { - Context.getPermissionsManager().checkAdmin(getUserId()); - } - - }); - } - - @Override - protected void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { + private void get(HttpServletResponse resp) throws Exception { sendResponse(resp.getWriter(), JsonConverter.objectToJson( Context.getDataManager().getServer())); } + private void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { + Server server = JsonConverter.objectFromJson(req.getReader(), new Server()); + Context.getPermissionsManager().checkAdmin(getUserId(req)); + Context.getDataManager().updateServer(server); + sendResponse(resp.getWriter(), true); + } + } diff --git a/src/org/traccar/web/UserServlet.java b/src/org/traccar/web/UserServlet.java index f7ae19fa9..6bd870d4d 100644 --- a/src/org/traccar/web/UserServlet.java +++ b/src/org/traccar/web/UserServlet.java @@ -18,10 +18,9 @@ package org.traccar.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.traccar.Context; -import org.traccar.helper.CommandCall; import org.traccar.model.User; -public class UserServlet extends BaseServletResource { +public class UserServlet extends BaseServlet { @Override protected boolean handle(String command, HttpServletRequest req, HttpServletResponse resp) throws Exception { @@ -45,64 +44,38 @@ public class UserServlet extends BaseServletResource { return true; } - @Override - protected void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { + private void get(HttpServletRequest req, HttpServletResponse resp) throws Exception { Context.getPermissionsManager().checkAdmin(getUserId(req)); sendResponse(resp.getWriter(), JsonConverter.arrayToJson( Context.getDataManager().getUsers())); } - @Override - protected void add(HttpServletRequest req, HttpServletResponse resp) throws Exception { - super.add(req, resp, new CommandCall() { - - @Override - public void check() throws Exception { - Context.getPermissionsManager().check(User.class, getUserId(), getEntity().getId()); - } - - @Override - public void after() throws Exception { - Context.getPermissionsManager().refresh(); - } - }); + private void add(HttpServletRequest req, HttpServletResponse resp) throws Exception { + User user = JsonConverter.objectFromJson(req.getReader(), new User()); + Context.getPermissionsManager().checkUser(getUserId(req), user.getId()); + Context.getDataManager().addUser(user); + Context.getPermissionsManager().refresh(); + sendResponse(resp.getWriter(), JsonConverter.objectToJson(user)); } - @Override - protected void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { - super.update(req, resp, new CommandCall() { - - @Override - public void check() { - if (getEntity().getAdmin()) { - Context.getPermissionsManager().checkAdmin(getUserId()); - } else { - Context.getPermissionsManager().check(User.class, getUserId(), getEntity().getId()); - } - } - - @Override - public void after() { - Context.getPermissionsManager().refresh(); - } - - }); + private void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { + User user = JsonConverter.objectFromJson(req.getReader(), new User()); + if (user.getAdmin()) { + Context.getPermissionsManager().checkAdmin(getUserId(req)); + } else { + Context.getPermissionsManager().checkUser(getUserId(req), user.getId()); + } + Context.getDataManager().updateUser(user); + Context.getPermissionsManager().refresh(); + sendResponse(resp.getWriter(), true); } - @Override - protected void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception { - super.remove(req, resp, new CommandCall() { - - @Override - public void check() throws Exception { - Context.getPermissionsManager().check(User.class, getUserId(), getEntity().getId()); - } - - @Override - public void after() throws Exception { - Context.getPermissionsManager().refresh(); - } - - }); + private void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception { + User user = JsonConverter.objectFromJson(req.getReader(), new User()); + Context.getPermissionsManager().checkUser(getUserId(req), user.getId()); + Context.getDataManager().removeUser(user); + Context.getPermissionsManager().refresh(); + sendResponse(resp.getWriter(), true); } + } diff --git a/src/org/traccar/web/WebServer.java b/src/org/traccar/web/WebServer.java index 2e7e1a31b..146dee613 100644 --- a/src/org/traccar/web/WebServer.java +++ b/src/org/traccar/web/WebServer.java @@ -24,6 +24,8 @@ import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.webapp.WebAppContext; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.servlet.ServletContainer; import org.traccar.Config; import org.traccar.helper.Log; @@ -98,23 +100,33 @@ public class WebServer { } private void initApi() { + initOldApi(); + initRestApi(); + } + + @Deprecated + private void initOldApi() { ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); servletHandler.setContextPath("/api"); servletHandler.addServlet(new ServletHolder(new AsyncServlet()), "/async/*"); servletHandler.addServlet(new ServletHolder(new ServerServlet()), "/server/*"); - servletHandler.addServlet(new ServletHolder(new ServerServlet()), "/servers/*"); servletHandler.addServlet(new ServletHolder(new UserServlet()), "/user/*"); - servletHandler.addServlet(new ServletHolder(new UserServlet()), "/users/*"); servletHandler.addServlet(new ServletHolder(new DeviceServlet()), "/device/*"); - servletHandler.addServlet(new ServletHolder(new DeviceServlet()), "/devices/*"); servletHandler.addServlet(new ServletHolder(new PositionServlet()), "/position/*"); - servletHandler.addServlet(new ServletHolder(new PositionServlet()), "/positions/*"); servletHandler.addServlet(new ServletHolder(new CommandServlet()), "/command/*"); - servletHandler.addServlet(new ServletHolder(new CommandServlet()), "/commands/*"); servletHandler.addServlet(new ServletHolder(new MainServlet()), "/*"); handlers.addHandler(servletHandler); } + private void initRestApi() { + ResourceConfig resourceConfig = new ResourceConfig(); + resourceConfig.packages("org.traccar.api"); + ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS); + ServletHolder servletHolder = new ServletHolder(new ServletContainer(resourceConfig)); + servletHandler.addServlet(servletHolder, "/rest/*"); + handlers.addHandler(servletHandler); + } + public void start() { try { server.start(); -- cgit v1.2.3 From 1a25796d62bdf88f2cba0387a09e2eb71599e588 Mon Sep 17 00:00:00 2001 From: Rafael Guterres Date: Fri, 27 Nov 2015 03:46:47 -0200 Subject: Merge tananaev/master Conflicts: src/org/traccar/web/WebServer.java --- src/org/traccar/web/WebServer.java | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/org/traccar') diff --git a/src/org/traccar/web/WebServer.java b/src/org/traccar/web/WebServer.java index 0f9bf8181..2318c4151 100644 --- a/src/org/traccar/web/WebServer.java +++ b/src/org/traccar/web/WebServer.java @@ -128,6 +128,15 @@ public class WebServer { handlers.addHandler(servletHandler); } + private void initRestApi() { + ResourceConfig resourceConfig = new ResourceConfig(); + resourceConfig.packages("org.traccar.api"); + ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS); + ServletHolder servletHolder = new ServletHolder(new ServletContainer(resourceConfig)); + servletHandler.addServlet(servletHolder, "/rest/*"); + handlers.addHandler(servletHandler); + } + public void start() { try { server.start(); -- cgit v1.2.3 From ed7e73b5af4e4e84f3abd2dde73626f90de911bb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 1 Dec 2015 10:43:42 +1300 Subject: Explicitly register REST filters --- src/org/traccar/api/CORSResponseFilter.java | 2 -- src/org/traccar/api/SecurityRequestFilter.java | 2 -- src/org/traccar/web/WebServer.java | 4 ++++ 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/org/traccar') diff --git a/src/org/traccar/api/CORSResponseFilter.java b/src/org/traccar/api/CORSResponseFilter.java index 039a749c4..89b49fc84 100644 --- a/src/org/traccar/api/CORSResponseFilter.java +++ b/src/org/traccar/api/CORSResponseFilter.java @@ -19,9 +19,7 @@ import java.io.IOException; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; -import javax.ws.rs.ext.Provider; -@Provider public class CORSResponseFilter implements ContainerResponseFilter { public static final String ACCESS_CONTROL_ALLOW_ORIGIN_KEY = "Access-Control-Allow-Origin"; diff --git a/src/org/traccar/api/SecurityRequestFilter.java b/src/org/traccar/api/SecurityRequestFilter.java index 9d59cdc01..e52df661b 100644 --- a/src/org/traccar/api/SecurityRequestFilter.java +++ b/src/org/traccar/api/SecurityRequestFilter.java @@ -25,9 +25,7 @@ import javax.annotation.security.RolesAllowed; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ResourceInfo; -import javax.ws.rs.ext.Provider; -@Provider public class SecurityRequestFilter implements ContainerRequestFilter { @javax.ws.rs.core.Context diff --git a/src/org/traccar/web/WebServer.java b/src/org/traccar/web/WebServer.java index 2318c4151..675f4d489 100644 --- a/src/org/traccar/web/WebServer.java +++ b/src/org/traccar/web/WebServer.java @@ -27,6 +27,8 @@ import org.eclipse.jetty.webapp.WebAppContext; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; import org.traccar.Config; +import org.traccar.api.CORSResponseFilter; +import org.traccar.api.SecurityRequestFilter; import org.traccar.helper.Log; /** @@ -131,6 +133,8 @@ public class WebServer { private void initRestApi() { ResourceConfig resourceConfig = new ResourceConfig(); resourceConfig.packages("org.traccar.api"); + resourceConfig.register(SecurityRequestFilter.class); + resourceConfig.register(CORSResponseFilter.class); ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS); ServletHolder servletHolder = new ServletHolder(new ServletContainer(resourceConfig)); servletHandler.addServlet(servletHolder, "/rest/*"); -- cgit v1.2.3 From 416ea87605b13f329430fbbb6a4aa1c002086514 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 1 Dec 2015 10:48:14 +1300 Subject: Rename CORS response filter --- src/org/traccar/api/CORSResponseFilter.java | 3 ++- src/org/traccar/api/SecurityRequestFilter.java | 6 +----- src/org/traccar/web/WebServer.java | 4 ++-- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'src/org/traccar') diff --git a/src/org/traccar/api/CORSResponseFilter.java b/src/org/traccar/api/CORSResponseFilter.java index 89b49fc84..8aab5ad68 100644 --- a/src/org/traccar/api/CORSResponseFilter.java +++ b/src/org/traccar/api/CORSResponseFilter.java @@ -20,7 +20,7 @@ import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; -public class CORSResponseFilter implements ContainerResponseFilter { +public class CorsResponseFilter implements ContainerResponseFilter { public static final String ACCESS_CONTROL_ALLOW_ORIGIN_KEY = "Access-Control-Allow-Origin"; public static final String ACCESS_CONTROL_ALLOW_ORIGIN_VALUE = "*"; @@ -49,4 +49,5 @@ public class CORSResponseFilter implements ContainerResponseFilter { response.getHeaders().add(ACCESS_CONTROL_ALLOW_METHODS_KEY, ACCESS_CONTROL_ALLOW_METHODS_VALUE); } } + } diff --git a/src/org/traccar/api/SecurityRequestFilter.java b/src/org/traccar/api/SecurityRequestFilter.java index e52df661b..8dbd2bbb0 100644 --- a/src/org/traccar/api/SecurityRequestFilter.java +++ b/src/org/traccar/api/SecurityRequestFilter.java @@ -35,18 +35,15 @@ public class SecurityRequestFilter implements ContainerRequestFilter { public void filter(ContainerRequestContext requestContext) { Method method = resourceInfo.getResourceMethod(); - //@PermitAll if (method.isAnnotationPresent(PermitAll.class)) { return; } - //@DenyAll if (method.isAnnotationPresent(DenyAll.class)) { requestContext.abortWith(ResponseBuilder.forbidden()); return; } - //AuthorizationBasic UserPrincipal userPrincipal = AuthorizationBasic.getUserPrincipal(requestContext); if (userPrincipal == null || userPrincipal.getName() == null @@ -56,7 +53,6 @@ public class SecurityRequestFilter implements ContainerRequestFilter { return; } - //@RolesAllowed if (method.isAnnotationPresent(RolesAllowed.class)) { RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class); Set roles = new HashSet<>(Arrays.asList(rolesAnnotation.value())); @@ -66,7 +62,6 @@ public class SecurityRequestFilter implements ContainerRequestFilter { } } - //SecurityContext requestContext.setSecurityContext(new SecurityContextApi(userPrincipal)); } @@ -77,4 +72,5 @@ public class SecurityRequestFilter implements ContainerRequestFilter { private boolean isAuthorizedUser(UserPrincipal userPrincipal, Set roles) { return AuthorizationBasic.isAuthorizedUser(userPrincipal, roles); } + } diff --git a/src/org/traccar/web/WebServer.java b/src/org/traccar/web/WebServer.java index 675f4d489..5ea31b079 100644 --- a/src/org/traccar/web/WebServer.java +++ b/src/org/traccar/web/WebServer.java @@ -27,7 +27,7 @@ import org.eclipse.jetty.webapp.WebAppContext; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; import org.traccar.Config; -import org.traccar.api.CORSResponseFilter; +import org.traccar.api.CorsResponseFilter; import org.traccar.api.SecurityRequestFilter; import org.traccar.helper.Log; @@ -134,7 +134,7 @@ public class WebServer { ResourceConfig resourceConfig = new ResourceConfig(); resourceConfig.packages("org.traccar.api"); resourceConfig.register(SecurityRequestFilter.class); - resourceConfig.register(CORSResponseFilter.class); + resourceConfig.register(CorsResponseFilter.class); ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS); ServletHolder servletHolder = new ServletHolder(new ServletContainer(resourceConfig)); servletHandler.addServlet(servletHolder, "/rest/*"); -- cgit v1.2.3 From 2ba060bc29ee529c5492b098b21927e15d815cb1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 1 Dec 2015 10:50:18 +1300 Subject: Rename file as well --- src/org/traccar/api/CORSResponseFilter.java | 53 ----------------------------- src/org/traccar/api/CorsResponseFilter.java | 53 +++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 53 deletions(-) delete mode 100644 src/org/traccar/api/CORSResponseFilter.java create mode 100644 src/org/traccar/api/CorsResponseFilter.java (limited to 'src/org/traccar') diff --git a/src/org/traccar/api/CORSResponseFilter.java b/src/org/traccar/api/CORSResponseFilter.java deleted file mode 100644 index 8aab5ad68..000000000 --- a/src/org/traccar/api/CORSResponseFilter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * 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; - -import java.io.IOException; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerResponseContext; -import javax.ws.rs.container.ContainerResponseFilter; - -public class CorsResponseFilter implements ContainerResponseFilter { - - public static final String ACCESS_CONTROL_ALLOW_ORIGIN_KEY = "Access-Control-Allow-Origin"; - public static final String ACCESS_CONTROL_ALLOW_ORIGIN_VALUE = "*"; - - public static final String ACCESS_CONTROL_ALLOW_HEADERS_KEY = "Access-Control-Allow-Headers"; - public static final String ACCESS_CONTROL_ALLOW_HEADERS_VALUE = "origin, content-type, accept, authorization"; - - public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_KEY = "Access-Control-Allow-Credentials"; - public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE = "true"; - - public static final String ACCESS_CONTROL_ALLOW_METHODS_KEY = "Access-Control-Allow-Methods"; - public static final String ACCESS_CONTROL_ALLOW_METHODS_VALUE = "GET, POST, PUT, DELETE"; - - @Override - public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException { - if (!response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN_KEY)) { - response.getHeaders().add(ACCESS_CONTROL_ALLOW_ORIGIN_KEY, ACCESS_CONTROL_ALLOW_ORIGIN_VALUE); - } - if (!response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_HEADERS_KEY)) { - response.getHeaders().add(ACCESS_CONTROL_ALLOW_HEADERS_KEY, ACCESS_CONTROL_ALLOW_HEADERS_VALUE); - } - if (!response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_CREDENTIALS_KEY)) { - response.getHeaders().add(ACCESS_CONTROL_ALLOW_CREDENTIALS_KEY, ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE); - } - if (!response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_METHODS_KEY)) { - response.getHeaders().add(ACCESS_CONTROL_ALLOW_METHODS_KEY, ACCESS_CONTROL_ALLOW_METHODS_VALUE); - } - } - -} diff --git a/src/org/traccar/api/CorsResponseFilter.java b/src/org/traccar/api/CorsResponseFilter.java new file mode 100644 index 000000000..8aab5ad68 --- /dev/null +++ b/src/org/traccar/api/CorsResponseFilter.java @@ -0,0 +1,53 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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; + +import java.io.IOException; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; + +public class CorsResponseFilter implements ContainerResponseFilter { + + public static final String ACCESS_CONTROL_ALLOW_ORIGIN_KEY = "Access-Control-Allow-Origin"; + public static final String ACCESS_CONTROL_ALLOW_ORIGIN_VALUE = "*"; + + public static final String ACCESS_CONTROL_ALLOW_HEADERS_KEY = "Access-Control-Allow-Headers"; + public static final String ACCESS_CONTROL_ALLOW_HEADERS_VALUE = "origin, content-type, accept, authorization"; + + public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_KEY = "Access-Control-Allow-Credentials"; + public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE = "true"; + + public static final String ACCESS_CONTROL_ALLOW_METHODS_KEY = "Access-Control-Allow-Methods"; + public static final String ACCESS_CONTROL_ALLOW_METHODS_VALUE = "GET, POST, PUT, DELETE"; + + @Override + public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException { + if (!response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN_KEY)) { + response.getHeaders().add(ACCESS_CONTROL_ALLOW_ORIGIN_KEY, ACCESS_CONTROL_ALLOW_ORIGIN_VALUE); + } + if (!response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_HEADERS_KEY)) { + response.getHeaders().add(ACCESS_CONTROL_ALLOW_HEADERS_KEY, ACCESS_CONTROL_ALLOW_HEADERS_VALUE); + } + if (!response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_CREDENTIALS_KEY)) { + response.getHeaders().add(ACCESS_CONTROL_ALLOW_CREDENTIALS_KEY, ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE); + } + if (!response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_METHODS_KEY)) { + response.getHeaders().add(ACCESS_CONTROL_ALLOW_METHODS_KEY, ACCESS_CONTROL_ALLOW_METHODS_VALUE); + } + } + +} -- cgit v1.2.3 From 7575edbee87f9fbe4770c988b469f5915d85bb51 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 1 Dec 2015 11:00:17 +1300 Subject: Move role definitions to user model --- src/org/traccar/api/ApplicationRole.java | 25 ------------------------ src/org/traccar/api/AuthorizationBasic.java | 4 ++-- src/org/traccar/api/BaseResource.java | 3 ++- src/org/traccar/api/resource/DeviceResource.java | 12 ++++++------ src/org/traccar/api/resource/UserResource.java | 11 +++++------ src/org/traccar/model/User.java | 3 +++ 6 files changed, 18 insertions(+), 40 deletions(-) delete mode 100644 src/org/traccar/api/ApplicationRole.java (limited to 'src/org/traccar') diff --git a/src/org/traccar/api/ApplicationRole.java b/src/org/traccar/api/ApplicationRole.java deleted file mode 100644 index 4da5f6708..000000000 --- a/src/org/traccar/api/ApplicationRole.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * 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; - -public final class ApplicationRole { - - public static final String USER = "USER"; - public static final String ADMIN = "ADMIN"; - - private ApplicationRole() { - } -} diff --git a/src/org/traccar/api/AuthorizationBasic.java b/src/org/traccar/api/AuthorizationBasic.java index 807320940..291d0e5d6 100644 --- a/src/org/traccar/api/AuthorizationBasic.java +++ b/src/org/traccar/api/AuthorizationBasic.java @@ -77,9 +77,9 @@ public final class AuthorizationBasic { */ //Temporary solution - userPrincipal.getRoles().add(ApplicationRole.USER); + userPrincipal.getRoles().add(User.ROLE_USER); if (user.getAdmin()) { - userPrincipal.getRoles().add(ApplicationRole.ADMIN); + userPrincipal.getRoles().add(User.ROLE_ADMIN); } return true; } diff --git a/src/org/traccar/api/BaseResource.java b/src/org/traccar/api/BaseResource.java index 54d606ab6..6051fdb61 100644 --- a/src/org/traccar/api/BaseResource.java +++ b/src/org/traccar/api/BaseResource.java @@ -22,6 +22,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import org.traccar.Context; import org.traccar.helper.Clazz; +import org.traccar.model.User; public class BaseResource { @@ -45,7 +46,7 @@ public class BaseResource { } public T getEntity(I id) { - validateSecurityContext(ApplicationRole.USER, id); + validateSecurityContext(User.ROLE_USER, id); T entity = Clazz.newInstance(clazz); try { Clazz.setId(entity, id); diff --git a/src/org/traccar/api/resource/DeviceResource.java b/src/org/traccar/api/resource/DeviceResource.java index 4152bcf81..98f1d1cca 100644 --- a/src/org/traccar/api/resource/DeviceResource.java +++ b/src/org/traccar/api/resource/DeviceResource.java @@ -28,8 +28,8 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.traccar.api.ApplicationRole; import org.traccar.model.Device; +import org.traccar.model.User; @Path("devices") @Produces(MediaType.APPLICATION_JSON) @@ -37,7 +37,7 @@ import org.traccar.model.Device; public class DeviceResource extends BaseResource { @GET - @RolesAllowed(ApplicationRole.ADMIN) + @RolesAllowed(User.ROLE_ADMIN) @Override public Collection getEntities() { return super.getEntities(); @@ -45,14 +45,14 @@ public class DeviceResource extends BaseResource { @GET @Path("{id}") - @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @RolesAllowed(User.ROLE_USER) @Override public Device getEntity(@PathParam("id") Long id) { return super.getEntity(id); } @POST - @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @RolesAllowed(User.ROLE_USER) @Override public Response postEntity(Device entity) { return super.postEntity(entity); @@ -60,7 +60,7 @@ public class DeviceResource extends BaseResource { @PUT @Path("{id}") - @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @RolesAllowed(User.ROLE_USER) @Override public Response putEntity(@PathParam("id") Long id, Device entity) { return super.putEntity(id, entity); @@ -68,7 +68,7 @@ public class DeviceResource extends BaseResource { @DELETE @Path("{id}") - @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @RolesAllowed(User.ROLE_USER) @Override public Response deleteEntity(@PathParam("id") Long id) { return super.deleteEntity(id); diff --git a/src/org/traccar/api/resource/UserResource.java b/src/org/traccar/api/resource/UserResource.java index da615e052..d2964c983 100644 --- a/src/org/traccar/api/resource/UserResource.java +++ b/src/org/traccar/api/resource/UserResource.java @@ -27,7 +27,6 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.traccar.api.ApplicationRole; import org.traccar.api.BaseResource; import org.traccar.model.User; @@ -37,7 +36,7 @@ import org.traccar.model.User; public class UserResource extends BaseResource { @GET - @RolesAllowed(ApplicationRole.ADMIN) + @RolesAllowed(User.ROLE_ADMIN) @Override public Collection getEntities() { return super.getEntities(); @@ -45,14 +44,14 @@ public class UserResource extends BaseResource { @GET @Path("{id}") - @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @RolesAllowed(User.ROLE_USER) @Override public User getEntity(@PathParam("id") Long id) { return super.getEntity(id); } @POST - @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @RolesAllowed(User.ROLE_USER) @Override public Response postEntity(User entity) { return super.postEntity(entity); @@ -60,7 +59,7 @@ public class UserResource extends BaseResource { @PUT @Path("{id}") - @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @RolesAllowed(User.ROLE_USER) @Override public Response putEntity(@PathParam("id") Long id, User entity) { return super.putEntity(id, entity); @@ -68,7 +67,7 @@ public class UserResource extends BaseResource { @DELETE @Path("{id}") - @RolesAllowed({ApplicationRole.ADMIN, ApplicationRole.USER}) + @RolesAllowed(User.ROLE_USER) @Override public Response deleteEntity(@PathParam("id") Long id) { return super.deleteEntity(id); diff --git a/src/org/traccar/model/User.java b/src/org/traccar/model/User.java index 8ac9e9d32..1c404c38a 100644 --- a/src/org/traccar/model/User.java +++ b/src/org/traccar/model/User.java @@ -20,6 +20,9 @@ import org.traccar.web.JsonIgnore; public class User implements Factory { + public static final String ROLE_USER = "user"; + public static final String ROLE_ADMIN = "admin"; + @Override public User create() { return new User(); -- cgit v1.2.3 From 6c444343d14bd3158bb27285efbcb17141166bff Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 1 Dec 2015 11:30:03 +1300 Subject: Remove response builder utility class --- src/org/traccar/api/BaseResource.java | 44 +++++--- src/org/traccar/api/ResponseBuilder.java | 129 ----------------------- src/org/traccar/api/SecurityRequestFilter.java | 11 +- src/org/traccar/api/resource/DeviceResource.java | 8 +- src/org/traccar/api/resource/UserResource.java | 8 +- 5 files changed, 44 insertions(+), 156 deletions(-) delete mode 100644 src/org/traccar/api/ResponseBuilder.java (limited to 'src/org/traccar') diff --git a/src/org/traccar/api/BaseResource.java b/src/org/traccar/api/BaseResource.java index 6051fdb61..9b0c2cf79 100644 --- a/src/org/traccar/api/BaseResource.java +++ b/src/org/traccar/api/BaseResource.java @@ -17,6 +17,8 @@ package org.traccar.api; import java.sql.SQLException; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; @@ -24,38 +26,47 @@ import org.traccar.Context; import org.traccar.helper.Clazz; import org.traccar.model.User; -public class BaseResource { +public class BaseResource { + + private static final String ERROR_KEY = "error"; private final Class clazz = Clazz.getGenericArgumentType(getClass()); @javax.ws.rs.core.Context private SecurityContext securityContext; + private static Map getError(Exception e) { + Map error = new HashMap<>(); + error.put(ERROR_KEY, e.getMessage()); + return error; + } + public Collection getEntities() { Collection collection; try { collection = Context.getDataManager().get(clazz); } catch (SQLException e) { - throw new WebApplicationException(ResponseBuilder.badRequest(e)); + throw new WebApplicationException( + Response.status(Response.Status.BAD_REQUEST).entity(getError(e)).build()); } if (collection == null || collection.isEmpty()) { - throw new WebApplicationException(ResponseBuilder.notFound()); + throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); } else { return collection; } } - public T getEntity(I id) { + public T getEntity(long id) { validateSecurityContext(User.ROLE_USER, id); T entity = Clazz.newInstance(clazz); try { Clazz.setId(entity, id); entity = Context.getDataManager().get(entity); } catch (Exception e) { - throw new WebApplicationException(ResponseBuilder.badRequest(e)); + throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(getError(e)).build()); } if (entity == null) { - throw new WebApplicationException(ResponseBuilder.notFound()); + throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); } else { return entity; } @@ -64,37 +75,38 @@ public class BaseResource { public Response postEntity(T entity) { try { Context.getDataManager().add(entity); - return ResponseBuilder.ok(entity); + return Response.status(Response.Status.OK).entity(entity).build(); } catch (Exception e) { - return ResponseBuilder.badRequest(e); + return Response.status(Response.Status.BAD_REQUEST).entity(getError(e)).build(); } } - public Response putEntity(I id, T entity) { + public Response putEntity(long id, T entity) { try { Clazz.setId(entity, id); Context.getDataManager().update(entity); - return ResponseBuilder.ok(entity); + return Response.status(Response.Status.OK).entity(entity).build(); } catch (Exception e) { - return ResponseBuilder.badRequest(e); + return Response.status(Response.Status.BAD_REQUEST).entity(getError(e)).build(); } } - public Response deleteEntity(I id) { + public Response deleteEntity(long id) { try { T entity = Clazz.newInstance(clazz); Clazz.setId(entity, id); Context.getDataManager().remove(entity); - return ResponseBuilder.deleted(); + return Response.status(Response.Status.NO_CONTENT).build(); } catch (Exception e) { - return ResponseBuilder.badRequest(e); + return Response.status(Response.Status.BAD_REQUEST).entity(getError(e)).build(); } } - private void validateSecurityContext(String role, I id) { + private void validateSecurityContext(String role, long id) { UserPrincipal userPrincipal = (UserPrincipal) securityContext.getUserPrincipal(); if (!securityContext.isUserInRole(role) && !userPrincipal.getId().equals(id)) { - throw new WebApplicationException(ResponseBuilder.forbidden()); + throw new WebApplicationException(Response.status(Response.Status.FORBIDDEN).build()); } } + } diff --git a/src/org/traccar/api/ResponseBuilder.java b/src/org/traccar/api/ResponseBuilder.java deleted file mode 100644 index 195cb1923..000000000 --- a/src/org/traccar/api/ResponseBuilder.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * 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; - -import java.io.Serializable; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Logger; -import javax.ws.rs.core.Response; - -public final class ResponseBuilder implements Serializable { - - private static final long serialVersionUID = -2348334499023022836L; - - private static final String WWW_AUTHENTICATE = "WWW-Authenticate"; - private static final String BASIC_REALM = "Basic realm=\"api\""; - private static final String ERROR = "error"; - - private ResponseBuilder() { - } - - public static Response ok() { - return Response.status(Response.Status.OK).build(); - } - - public static Response ok(T entity) { - return Response.status(Response.Status.OK).entity(entity).build(); - } - - public static Response ok(Collection entities) { - return Response.ok(entities).build(); - } - - public static Response created() { - return Response.status(Response.Status.CREATED).build(); - } - - public static Response created(T entity) { - return Response.status(Response.Status.CREATED).entity(entity).build(); - } - - public static Response accepted() { - return Response.status(Response.Status.ACCEPTED).build(); - } - - public static Response accepted(T entity) { - return Response.status(Response.Status.ACCEPTED).entity(entity).build(); - } - - public static Response deleted() { - return Response.status(Response.Status.NO_CONTENT).build(); - } - - public static Response notModified() { - return Response.status(Response.Status.NOT_MODIFIED).build(); - } - - public static Response badRequest() { - return Response.status(Response.Status.BAD_REQUEST).build(); - } - - public static Response badRequest(Exception e) { - return Response.status(Response.Status.BAD_REQUEST).entity(getError(e)).build(); - } - - public static Response unauthorized() { - return Response.status(Response.Status.UNAUTHORIZED).header(WWW_AUTHENTICATE, BASIC_REALM).build(); - } - - public static Response forbidden() { - return Response.status(Response.Status.FORBIDDEN).entity(getError(Response.Status.FORBIDDEN.name())).build(); - } - - public static Response notFound() { - return Response.status(Response.Status.NOT_FOUND).build(); - } - - public static Response timeout() { - return Response.status(Response.Status.REQUEST_TIMEOUT).build(); - } - - public static Response conflict() { - return Response.status(Response.Status.CONFLICT).build(); - } - - public static Response conflict(Exception e) { - return Response.status(Response.Status.CONFLICT).entity(getError(e)).build(); - } - - public static Response notImplemented() { - return Response.status(Response.Status.NOT_IMPLEMENTED).build(); - } - - public static Response redirect(String uri) { - try { - return Response.seeOther(new URI(uri)).build(); - } catch (URISyntaxException e) { - Logger.getAnonymousLogger().warning(e.getMessage()); - return null; - } - } - - private static Map getError(Exception e) { - return getError(e.getMessage()); - } - - private static Map getError(String message) { - Map error = new HashMap<>(); - error.put(ERROR, message); - return error; - } - -} diff --git a/src/org/traccar/api/SecurityRequestFilter.java b/src/org/traccar/api/SecurityRequestFilter.java index 8dbd2bbb0..e9d285f9b 100644 --- a/src/org/traccar/api/SecurityRequestFilter.java +++ b/src/org/traccar/api/SecurityRequestFilter.java @@ -25,9 +25,13 @@ import javax.annotation.security.RolesAllowed; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ResourceInfo; +import javax.ws.rs.core.Response; public class SecurityRequestFilter implements ContainerRequestFilter { + private static final String WWW_AUTHENTICATE = "WWW-Authenticate"; + private static final String BASIC_REALM = "Basic realm=\"api\""; + @javax.ws.rs.core.Context private ResourceInfo resourceInfo; @@ -40,7 +44,7 @@ public class SecurityRequestFilter implements ContainerRequestFilter { } if (method.isAnnotationPresent(DenyAll.class)) { - requestContext.abortWith(ResponseBuilder.forbidden()); + requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build()); return; } @@ -49,7 +53,8 @@ public class SecurityRequestFilter implements ContainerRequestFilter { || userPrincipal.getName() == null || userPrincipal.getPassword() == null || !isAuthenticatedUser(userPrincipal)) { - requestContext.abortWith(ResponseBuilder.unauthorized()); + requestContext.abortWith( + Response.status(Response.Status.UNAUTHORIZED).header(WWW_AUTHENTICATE, BASIC_REALM).build()); return; } @@ -57,7 +62,7 @@ public class SecurityRequestFilter implements ContainerRequestFilter { RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class); Set roles = new HashSet<>(Arrays.asList(rolesAnnotation.value())); if (!isAuthorizedUser(userPrincipal, roles)) { - requestContext.abortWith(ResponseBuilder.forbidden()); + requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build()); return; } } diff --git a/src/org/traccar/api/resource/DeviceResource.java b/src/org/traccar/api/resource/DeviceResource.java index 98f1d1cca..50589171d 100644 --- a/src/org/traccar/api/resource/DeviceResource.java +++ b/src/org/traccar/api/resource/DeviceResource.java @@ -34,7 +34,7 @@ import org.traccar.model.User; @Path("devices") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -public class DeviceResource extends BaseResource { +public class DeviceResource extends BaseResource { @GET @RolesAllowed(User.ROLE_ADMIN) @@ -47,7 +47,7 @@ public class DeviceResource extends BaseResource { @Path("{id}") @RolesAllowed(User.ROLE_USER) @Override - public Device getEntity(@PathParam("id") Long id) { + public Device getEntity(@PathParam("id") long id) { return super.getEntity(id); } @@ -62,7 +62,7 @@ public class DeviceResource extends BaseResource { @Path("{id}") @RolesAllowed(User.ROLE_USER) @Override - public Response putEntity(@PathParam("id") Long id, Device entity) { + public Response putEntity(@PathParam("id") long id, Device entity) { return super.putEntity(id, entity); } @@ -70,7 +70,7 @@ public class DeviceResource extends BaseResource { @Path("{id}") @RolesAllowed(User.ROLE_USER) @Override - public Response deleteEntity(@PathParam("id") Long id) { + public Response deleteEntity(@PathParam("id") long id) { return super.deleteEntity(id); } diff --git a/src/org/traccar/api/resource/UserResource.java b/src/org/traccar/api/resource/UserResource.java index d2964c983..8e17787c2 100644 --- a/src/org/traccar/api/resource/UserResource.java +++ b/src/org/traccar/api/resource/UserResource.java @@ -33,7 +33,7 @@ import org.traccar.model.User; @Path("users") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -public class UserResource extends BaseResource { +public class UserResource extends BaseResource { @GET @RolesAllowed(User.ROLE_ADMIN) @@ -46,7 +46,7 @@ public class UserResource extends BaseResource { @Path("{id}") @RolesAllowed(User.ROLE_USER) @Override - public User getEntity(@PathParam("id") Long id) { + public User getEntity(@PathParam("id") long id) { return super.getEntity(id); } @@ -61,7 +61,7 @@ public class UserResource extends BaseResource { @Path("{id}") @RolesAllowed(User.ROLE_USER) @Override - public Response putEntity(@PathParam("id") Long id, User entity) { + public Response putEntity(@PathParam("id") long id, User entity) { return super.putEntity(id, entity); } @@ -69,7 +69,7 @@ public class UserResource extends BaseResource { @Path("{id}") @RolesAllowed(User.ROLE_USER) @Override - public Response deleteEntity(@PathParam("id") Long id) { + public Response deleteEntity(@PathParam("id") long id) { return super.deleteEntity(id); } -- cgit v1.2.3 From b175699d497967a9105425bf288d833ce96973e2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 1 Dec 2015 13:22:25 +1300 Subject: Remove unused methods and classes --- src/org/traccar/api/UserPrincipal.java | 15 ---------- src/org/traccar/helper/Clazz.java | 21 -------------- src/org/traccar/helper/CommandCall.java | 51 --------------------------------- 3 files changed, 87 deletions(-) delete mode 100644 src/org/traccar/helper/CommandCall.java (limited to 'src/org/traccar') diff --git a/src/org/traccar/api/UserPrincipal.java b/src/org/traccar/api/UserPrincipal.java index 387b7627c..11a6de629 100644 --- a/src/org/traccar/api/UserPrincipal.java +++ b/src/org/traccar/api/UserPrincipal.java @@ -31,18 +31,6 @@ public class UserPrincipal implements Principal { this.roles = roles; } - public UserPrincipal(String username, Set roles) { - this.username = username; - this.roles = roles; - } - - public UserPrincipal(String username) { - this.username = username; - } - - public UserPrincipal() { - } - public Long getId() { return id; } @@ -68,7 +56,4 @@ public class UserPrincipal implements Principal { return roles; } - public void setRoles(Set roles) { - this.roles = roles; - } } diff --git a/src/org/traccar/helper/Clazz.java b/src/org/traccar/helper/Clazz.java index ba4c4fded..1a1b445d5 100644 --- a/src/org/traccar/helper/Clazz.java +++ b/src/org/traccar/helper/Clazz.java @@ -23,19 +23,6 @@ import java.lang.reflect.Type; public final class Clazz implements Serializable { - private static final long serialVersionUID = 4983299355055144885L; - - private Clazz() { - } - - public static Class getGenericArgumentType(Class currentClass, Class genericSuperClass) { - return getGenericArgumentType(currentClass, genericSuperClass, 0); - } - - public static Class getGenericArgumentType(Class currentClass, int argumentIndex) { - return getGenericArgumentType(currentClass, null, argumentIndex); - } - public static Class getGenericArgumentType(Class currentClass) { return getGenericArgumentType(currentClass, null, 0); } @@ -72,14 +59,6 @@ public final class Clazz implements Serializable { throw new ClassCastException(); } - public static Class forName(String className) { - try { - return Class.forName(className, false, Thread.currentThread().getContextClassLoader()); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException(e); - } - } - public static long getId(T entity) throws Exception { Method[] methods = entity.getClass().getMethods(); for (final Method method : methods) { diff --git a/src/org/traccar/helper/CommandCall.java b/src/org/traccar/helper/CommandCall.java deleted file mode 100644 index d5da79348..000000000 --- a/src/org/traccar/helper/CommandCall.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * 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.helper; - -public abstract class CommandCall { - - private long userId; - private T entity; - - public void before() throws Exception { - //Do nothing. - } - - public void check() throws Exception { - //Do nothing. - } - - public void after() throws Exception { - //Do nothing. - } - - public long getUserId() { - return userId; - } - - public void setUserId(long userId) { - this.userId = userId; - } - - public T getEntity() { - return entity; - } - - public void setEntity(T entity) { - this.entity = entity; - } - -} -- cgit v1.2.3 From 40a607faa34d3c21d7b6d8275279fc8ce3c96980 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 1 Dec 2015 13:49:43 +1300 Subject: Explicitly register resource classes --- src/org/traccar/web/WebServer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/org/traccar') diff --git a/src/org/traccar/web/WebServer.java b/src/org/traccar/web/WebServer.java index 5ea31b079..317e4db46 100644 --- a/src/org/traccar/web/WebServer.java +++ b/src/org/traccar/web/WebServer.java @@ -29,6 +29,8 @@ import org.glassfish.jersey.servlet.ServletContainer; import org.traccar.Config; import org.traccar.api.CorsResponseFilter; import org.traccar.api.SecurityRequestFilter; +import org.traccar.api.resource.DeviceResource; +import org.traccar.api.resource.UserResource; import org.traccar.helper.Log; /** @@ -132,9 +134,9 @@ public class WebServer { private void initRestApi() { ResourceConfig resourceConfig = new ResourceConfig(); - resourceConfig.packages("org.traccar.api"); resourceConfig.register(SecurityRequestFilter.class); resourceConfig.register(CorsResponseFilter.class); + resourceConfig.registerClasses(DeviceResource.class, UserResource.class); ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS); ServletHolder servletHolder = new ServletHolder(new ServletContainer(resourceConfig)); servletHandler.addServlet(servletHolder, "/rest/*"); -- cgit v1.2.3 From a4fb24732188e4e0b7cc44079eea02c85e142028 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 1 Dec 2015 14:37:26 +1300 Subject: Refactor base and other resource classes --- src/org/traccar/api/BaseResource.java | 95 +----------------------- src/org/traccar/api/resource/DeviceResource.java | 64 ++++++++-------- src/org/traccar/api/resource/UserResource.java | 63 +++++++++------- src/org/traccar/database/DataManager.java | 72 ++++-------------- 4 files changed, 86 insertions(+), 208 deletions(-) (limited to 'src/org/traccar') diff --git a/src/org/traccar/api/BaseResource.java b/src/org/traccar/api/BaseResource.java index 9b0c2cf79..5a05c6732 100644 --- a/src/org/traccar/api/BaseResource.java +++ b/src/org/traccar/api/BaseResource.java @@ -15,98 +15,5 @@ */ package org.traccar.api; -import java.sql.SQLException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.SecurityContext; -import org.traccar.Context; -import org.traccar.helper.Clazz; -import org.traccar.model.User; - -public class BaseResource { - - private static final String ERROR_KEY = "error"; - - private final Class clazz = Clazz.getGenericArgumentType(getClass()); - - @javax.ws.rs.core.Context - private SecurityContext securityContext; - - private static Map getError(Exception e) { - Map error = new HashMap<>(); - error.put(ERROR_KEY, e.getMessage()); - return error; - } - - public Collection getEntities() { - Collection collection; - try { - collection = Context.getDataManager().get(clazz); - } catch (SQLException e) { - throw new WebApplicationException( - Response.status(Response.Status.BAD_REQUEST).entity(getError(e)).build()); - } - if (collection == null || collection.isEmpty()) { - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); - } else { - return collection; - } - } - - public T getEntity(long id) { - validateSecurityContext(User.ROLE_USER, id); - T entity = Clazz.newInstance(clazz); - try { - Clazz.setId(entity, id); - entity = Context.getDataManager().get(entity); - } catch (Exception e) { - throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).entity(getError(e)).build()); - } - if (entity == null) { - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); - } else { - return entity; - } - } - - public Response postEntity(T entity) { - try { - Context.getDataManager().add(entity); - return Response.status(Response.Status.OK).entity(entity).build(); - } catch (Exception e) { - return Response.status(Response.Status.BAD_REQUEST).entity(getError(e)).build(); - } - } - - public Response putEntity(long id, T entity) { - try { - Clazz.setId(entity, id); - Context.getDataManager().update(entity); - return Response.status(Response.Status.OK).entity(entity).build(); - } catch (Exception e) { - return Response.status(Response.Status.BAD_REQUEST).entity(getError(e)).build(); - } - } - - public Response deleteEntity(long id) { - try { - T entity = Clazz.newInstance(clazz); - Clazz.setId(entity, id); - Context.getDataManager().remove(entity); - return Response.status(Response.Status.NO_CONTENT).build(); - } catch (Exception e) { - return Response.status(Response.Status.BAD_REQUEST).entity(getError(e)).build(); - } - } - - private void validateSecurityContext(String role, long id) { - UserPrincipal userPrincipal = (UserPrincipal) securityContext.getUserPrincipal(); - if (!securityContext.isUserInRole(role) && !userPrincipal.getId().equals(id)) { - throw new WebApplicationException(Response.status(Response.Status.FORBIDDEN).build()); - } - } - +public class BaseResource { } diff --git a/src/org/traccar/api/resource/DeviceResource.java b/src/org/traccar/api/resource/DeviceResource.java index 50589171d..00b77e16c 100644 --- a/src/org/traccar/api/resource/DeviceResource.java +++ b/src/org/traccar/api/resource/DeviceResource.java @@ -15,9 +15,11 @@ */ package org.traccar.api.resource; +import org.traccar.Context; import org.traccar.api.BaseResource; + +import java.sql.SQLException; import java.util.Collection; -import javax.annotation.security.RolesAllowed; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; @@ -26,52 +28,56 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.traccar.model.Device; -import org.traccar.model.User; @Path("devices") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -public class DeviceResource extends BaseResource { +public class DeviceResource extends BaseResource { @GET - @RolesAllowed(User.ROLE_ADMIN) - @Override - public Collection getEntities() { - return super.getEntities(); - } - - @GET - @Path("{id}") - @RolesAllowed(User.ROLE_USER) - @Override - public Device getEntity(@PathParam("id") long id) { - return super.getEntity(id); + public Collection get() { + try { + return Context.getDataManager().getAllDevices(); + } catch (SQLException e) { + throw new WebApplicationException(e); + } } @POST - @RolesAllowed(User.ROLE_USER) - @Override - public Response postEntity(Device entity) { - return super.postEntity(entity); + public Response add(Device entity) { + try { + Context.getDataManager().addDevice(entity); + return Response.ok(entity).build(); + } catch (SQLException e) { + throw new WebApplicationException(e); + } } - @PUT @Path("{id}") - @RolesAllowed(User.ROLE_USER) - @Override - public Response putEntity(@PathParam("id") long id, Device entity) { - return super.putEntity(id, entity); + @PUT + public Response update(@PathParam("id") long id, Device entity) { + try { + entity.setId(id); + Context.getDataManager().updateDevice(entity); + return Response.ok(entity).build(); + } catch (SQLException e) { + throw new WebApplicationException(e); + } } - @DELETE @Path("{id}") - @RolesAllowed(User.ROLE_USER) - @Override - public Response deleteEntity(@PathParam("id") long id) { - return super.deleteEntity(id); + @DELETE + public Response remove(@PathParam("id") long id) { + try { + Context.getDataManager().removeDevice(id); + return Response.noContent().build(); + } catch (SQLException e) { + throw new WebApplicationException(e); + } } } diff --git a/src/org/traccar/api/resource/UserResource.java b/src/org/traccar/api/resource/UserResource.java index 8e17787c2..43bef891f 100644 --- a/src/org/traccar/api/resource/UserResource.java +++ b/src/org/traccar/api/resource/UserResource.java @@ -15,8 +15,8 @@ */ package org.traccar.api.resource; +import java.sql.SQLException; import java.util.Collection; -import javax.annotation.security.RolesAllowed; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; @@ -25,52 +25,59 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +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.User; @Path("users") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -public class UserResource extends BaseResource { +public class UserResource extends BaseResource { @GET - @RolesAllowed(User.ROLE_ADMIN) - @Override - public Collection getEntities() { - return super.getEntities(); - } - - @GET - @Path("{id}") - @RolesAllowed(User.ROLE_USER) - @Override - public User getEntity(@PathParam("id") long id) { - return super.getEntity(id); + public Collection get() { + try { + return Context.getDataManager().getUsers(); + } catch (SQLException e) { + throw new WebApplicationException(e); + } } @POST - @RolesAllowed(User.ROLE_USER) - @Override - public Response postEntity(User entity) { - return super.postEntity(entity); + public Response add(User entity) { + try { + Context.getDataManager().addUser(entity); + return Response.ok(entity).build(); + } catch (SQLException e) { + throw new WebApplicationException(e); + } } - @PUT @Path("{id}") - @RolesAllowed(User.ROLE_USER) - @Override - public Response putEntity(@PathParam("id") long id, User entity) { - return super.putEntity(id, entity); + @PUT + public Response update(@PathParam("id") long id, User entity) { + try { + entity.setId(id); + Context.getDataManager().updateUser(entity); + return Response.ok(entity).build(); + } catch (SQLException e) { + throw new WebApplicationException(e); + } } - @DELETE @Path("{id}") - @RolesAllowed(User.ROLE_USER) - @Override - public Response deleteEntity(@PathParam("id") long id) { - return super.deleteEntity(id); + @DELETE + public Response remove(@PathParam("id") long id) { + try { + Context.getDataManager().removeUser(id); + return Response.noContent().build(); + } catch (SQLException e) { + throw new WebApplicationException(e); + } } } diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java index 31d7155d3..f01280836 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -278,12 +278,19 @@ public class DataManager implements IdentityManager { } } + @Deprecated public void removeUser(User user) throws SQLException { QueryBuilder.create(dataSource, getQuery("database.deleteUser")) .setObject(user) .executeUpdate(); } + public void removeUser(long userId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.deleteUser")) + .setLong("id", userId) + .executeUpdate(); + } + public Collection getPermissions() throws SQLException { return QueryBuilder.create(dataSource, getQuery("database.getPermissionsAll")) .executeQuery(new Permission()); @@ -318,6 +325,7 @@ public class DataManager implements IdentityManager { .executeUpdate(); } + @Deprecated public void removeDevice(Device device) throws SQLException { QueryBuilder.create(dataSource, getQuery("database.deleteDevice")) .setObject(device) @@ -325,6 +333,13 @@ public class DataManager implements IdentityManager { AsyncServlet.sessionRefreshDevice(device.getId()); } + public void removeDevice(long deviceId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.deleteDevice")) + .setLong("id", deviceId) + .executeUpdate(); + AsyncServlet.sessionRefreshDevice(deviceId); + } + public void linkDevice(long userId, long deviceId) throws SQLException { QueryBuilder.create(dataSource, getQuery("database.linkDevice")) .setLong("userId", userId) @@ -387,61 +402,4 @@ public class DataManager implements IdentityManager { .executeUpdate(); } - public Collection get(Class clazz) throws SQLException { - if (clazz.equals(User.class)) { - return (Collection) getUsers(); - } else if (clazz.equals(Device.class)) { - return (Collection) getAllDevices(); - } - return null; - } - - public T get(T entity) throws Exception { - if (entity instanceof User) { - return (T) getUser(Clazz.getId(entity)); - } else if (entity instanceof Device) { - return (T) getDeviceById(Clazz.getId(entity)); - } - return null; - } - - public void add(Object entity) throws SQLException { - if (entity instanceof User) { - addUser((User) entity); - } else if (entity instanceof Device) { - addDevice((Device) entity); - } else if (entity instanceof Position) { - addPosition((Position) entity); - } - } - - public void update(Object entity) throws SQLException { - if (entity instanceof User) { - updateUser((User) entity); - } else if (entity instanceof Device) { - updateDevice((Device) entity); - } else if (entity instanceof Server) { - updateServer((Server) entity); - } - } - - public void remove(Object entity) throws SQLException { - if (entity instanceof User) { - removeUser((User) entity); - } else if (entity instanceof Device) { - removeDevice((Device) entity); - } - } - - public void link(Class clazz, long userId, long entityId) throws SQLException { - if (clazz.equals(Device.class)) { - linkDevice(userId, entityId); - } - } - - public void unlink(Class clazz, long userId, long entityId) throws SQLException { - if (clazz.equals(Device.class)) { - unlinkDevice(userId, entityId); - } - } } -- cgit v1.2.3 From 0e5e61fd14486e6b926b83895eedf9c97c2cb342 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 1 Dec 2015 14:46:17 +1300 Subject: Minor cleanup of security context class --- src/org/traccar/api/SecurityContextApi.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'src/org/traccar') diff --git a/src/org/traccar/api/SecurityContextApi.java b/src/org/traccar/api/SecurityContextApi.java index df10340c5..38ce7e33d 100644 --- a/src/org/traccar/api/SecurityContextApi.java +++ b/src/org/traccar/api/SecurityContextApi.java @@ -20,18 +20,12 @@ import javax.ws.rs.core.SecurityContext; public class SecurityContextApi implements SecurityContext { - private static final String AUTHENTICATION_SCHEME = "BASIC"; - private static final boolean IS_SECURE = true; - private Principal userPrincipal; public SecurityContextApi(Principal userPrincipal) { this.userPrincipal = userPrincipal; } - public SecurityContextApi() { - } - @Override public Principal getUserPrincipal() { return userPrincipal; @@ -45,11 +39,12 @@ public class SecurityContextApi implements SecurityContext { @Override public boolean isSecure() { - return IS_SECURE; + return false; } @Override public String getAuthenticationScheme() { - return AUTHENTICATION_SCHEME; + return BASIC_AUTH; } + } -- cgit v1.2.3 From 77b9194cc963645fc9ccf7ce79280982cead8f0f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 1 Dec 2015 15:10:30 +1300 Subject: Refactor security request filtering --- src/org/traccar/api/AuthorizationBasic.java | 98 -------------------------- src/org/traccar/api/SecurityContextApi.java | 50 ------------- src/org/traccar/api/SecurityRequestFilter.java | 77 ++++++++------------ src/org/traccar/api/UserPrincipal.java | 36 +++------- src/org/traccar/api/UserSecurityContext.java | 49 +++++++++++++ src/org/traccar/model/User.java | 3 - 6 files changed, 85 insertions(+), 228 deletions(-) delete mode 100644 src/org/traccar/api/AuthorizationBasic.java delete mode 100644 src/org/traccar/api/SecurityContextApi.java create mode 100644 src/org/traccar/api/UserSecurityContext.java (limited to 'src/org/traccar') diff --git a/src/org/traccar/api/AuthorizationBasic.java b/src/org/traccar/api/AuthorizationBasic.java deleted file mode 100644 index 291d0e5d6..000000000 --- a/src/org/traccar/api/AuthorizationBasic.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * 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; - -import java.sql.SQLException; -import java.util.List; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.TreeSet; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.core.MultivaluedMap; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.handler.codec.base64.Base64; -import org.jboss.netty.util.CharsetUtil; -import org.traccar.Context; -import org.traccar.model.User; - -public final class AuthorizationBasic { - - private AuthorizationBasic() { - } - - public static final String AUTHORIZATION_HEADER = "Authorization"; - public static final String AUTHORIZATION_SCHEME_VALUE = "Basic"; - public static final String REGEX = AUTHORIZATION_SCHEME_VALUE + " "; - public static final String REPLACEMENT = ""; - public static final String TOKENIZER = ":"; - public static final String USERNAME = "username"; - public static final String PASSWORD = "password"; - public static final String WWW_AUTHENTICATE_VALUE = "Basic realm=\"api\""; - - public static UserPrincipal getUserPrincipal(ContainerRequestContext requestContext) { - final MultivaluedMap headers = requestContext.getHeaders(); - final List authorization = headers.get(AUTHORIZATION_HEADER); - if (authorization == null || authorization.isEmpty()) { - return null; - } - final String encodedUsernameAndPassword = authorization.get(0).replaceFirst(REGEX, REPLACEMENT); - ChannelBuffer buffer = ChannelBuffers.copiedBuffer(encodedUsernameAndPassword, CharsetUtil.UTF_8); - String usernameAndPassword = Base64.decode(buffer).toString(CharsetUtil.UTF_8); - final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, TOKENIZER); - String username = tokenizer.nextToken(); - String password = tokenizer.nextToken(); - Set roles = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); - UserPrincipal userPrincipal = new UserPrincipal(username, password, roles); - return userPrincipal; - } - - public static boolean isAuthenticatedUser(UserPrincipal userPrincipal) { - if (userPrincipal.getName() != null && userPrincipal.getPassword() != null) { - User user; - try { - user = Context.getDataManager().login(userPrincipal.getName(), userPrincipal.getPassword()); - } catch (SQLException e) { - return false; - } - if (user != null) { - userPrincipal.setId(user.getId()); - /* - for (Role role : user.getRoles()) { - userPrincipal.getRoles().add(role.getName()); - } - */ - - //Temporary solution - userPrincipal.getRoles().add(User.ROLE_USER); - if (user.getAdmin()) { - userPrincipal.getRoles().add(User.ROLE_ADMIN); - } - return true; - } - } - return false; - } - - public static boolean isAuthorizedUser(UserPrincipal userPrincipal, Set roles) { - for (String role : roles) { - if (userPrincipal.getRoles().contains(role)) { - return true; - } - } - return false; - } -} diff --git a/src/org/traccar/api/SecurityContextApi.java b/src/org/traccar/api/SecurityContextApi.java deleted file mode 100644 index 38ce7e33d..000000000 --- a/src/org/traccar/api/SecurityContextApi.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * 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; - -import java.security.Principal; -import javax.ws.rs.core.SecurityContext; - -public class SecurityContextApi implements SecurityContext { - - private Principal userPrincipal; - - public SecurityContextApi(Principal userPrincipal) { - this.userPrincipal = userPrincipal; - } - - @Override - public Principal getUserPrincipal() { - return userPrincipal; - } - - @Override - public boolean isUserInRole(String role) { - UserPrincipal user = (UserPrincipal) userPrincipal; - return user.getRoles().contains(role); - } - - @Override - public boolean isSecure() { - return false; - } - - @Override - public String getAuthenticationScheme() { - return BASIC_AUTH; - } - -} diff --git a/src/org/traccar/api/SecurityRequestFilter.java b/src/org/traccar/api/SecurityRequestFilter.java index e9d285f9b..b1e090487 100644 --- a/src/org/traccar/api/SecurityRequestFilter.java +++ b/src/org/traccar/api/SecurityRequestFilter.java @@ -15,67 +15,46 @@ */ package org.traccar.api; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import javax.annotation.security.DenyAll; -import javax.annotation.security.PermitAll; -import javax.annotation.security.RolesAllowed; +import org.traccar.Context; +import org.traccar.model.User; + +import java.sql.SQLException; +import javax.ws.rs.WebApplicationException; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; -import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.Response; +import javax.xml.bind.DatatypeConverter; public class SecurityRequestFilter implements ContainerRequestFilter { - private static final String WWW_AUTHENTICATE = "WWW-Authenticate"; - private static final String BASIC_REALM = "Basic realm=\"api\""; + public static final String AUTHORIZATION_HEADER = "Authorization"; + public static final String WWW_AUTHENTICATE = "WWW-Authenticate"; + public static final String BASIC_REALM = "Basic realm=\"api\""; - @javax.ws.rs.core.Context - private ResourceInfo resourceInfo; + public static String[] decodeBasicAuth(String auth) { + auth = auth.replaceFirst("[B|b]asic ", ""); + byte[] decodedBytes = DatatypeConverter.parseBase64Binary(auth); + if (decodedBytes != null && decodedBytes.length > 0) { + return new String(decodedBytes).split(":", 2); + } + return null; + } @Override public void filter(ContainerRequestContext requestContext) { - Method method = resourceInfo.getResourceMethod(); - - if (method.isAnnotationPresent(PermitAll.class)) { - return; - } - - if (method.isAnnotationPresent(DenyAll.class)) { - requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build()); - return; - } - - UserPrincipal userPrincipal = AuthorizationBasic.getUserPrincipal(requestContext); - if (userPrincipal == null - || userPrincipal.getName() == null - || userPrincipal.getPassword() == null - || !isAuthenticatedUser(userPrincipal)) { - requestContext.abortWith( - Response.status(Response.Status.UNAUTHORIZED).header(WWW_AUTHENTICATE, BASIC_REALM).build()); - return; - } - - if (method.isAnnotationPresent(RolesAllowed.class)) { - RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class); - Set roles = new HashSet<>(Arrays.asList(rolesAnnotation.value())); - if (!isAuthorizedUser(userPrincipal, roles)) { - requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build()); - return; + try { + String[] auth = decodeBasicAuth(requestContext.getHeaderString(AUTHORIZATION_HEADER)); + User user = Context.getDataManager().login(auth[0], auth[1]); + if (user != null) { + requestContext.setSecurityContext( + new UserSecurityContext(new UserPrincipal(user.getId(), user.getName()))); + } else { + throw new WebApplicationException( + Response.status(Response.Status.UNAUTHORIZED).header(WWW_AUTHENTICATE, BASIC_REALM).build()); } + } catch (SQLException e) { + throw new WebApplicationException(e); } - - requestContext.setSecurityContext(new SecurityContextApi(userPrincipal)); - } - - private boolean isAuthenticatedUser(UserPrincipal principal) { - return AuthorizationBasic.isAuthenticatedUser(principal); - } - - private boolean isAuthorizedUser(UserPrincipal userPrincipal, Set roles) { - return AuthorizationBasic.isAuthorizedUser(userPrincipal, roles); } } diff --git a/src/org/traccar/api/UserPrincipal.java b/src/org/traccar/api/UserPrincipal.java index 11a6de629..d858b6f47 100644 --- a/src/org/traccar/api/UserPrincipal.java +++ b/src/org/traccar/api/UserPrincipal.java @@ -16,44 +16,24 @@ package org.traccar.api; import java.security.Principal; -import java.util.Set; public class UserPrincipal implements Principal { - private Long id; - private String username; - private String password; - private Set roles; + private String name; + private long userId; - public UserPrincipal(String username, String password, Set roles) { - this.username = username; - this.password = password; - this.roles = roles; + public UserPrincipal(long userId, String name) { + this.userId = userId; + this.name = name; } - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; + public Long getUserId() { + return userId; } @Override public String getName() { - return username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public Set getRoles() { - return roles; + return name; } } diff --git a/src/org/traccar/api/UserSecurityContext.java b/src/org/traccar/api/UserSecurityContext.java new file mode 100644 index 000000000..127aee4b3 --- /dev/null +++ b/src/org/traccar/api/UserSecurityContext.java @@ -0,0 +1,49 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * 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; + +import java.security.Principal; +import javax.ws.rs.core.SecurityContext; + +public class UserSecurityContext implements SecurityContext { + + private UserPrincipal principal; + + public UserSecurityContext(UserPrincipal principal) { + this.principal = principal; + } + + @Override + public Principal getUserPrincipal() { + return principal; + } + + @Override + public boolean isUserInRole(String role) { + return true; + } + + @Override + public boolean isSecure() { + return false; + } + + @Override + public String getAuthenticationScheme() { + return BASIC_AUTH; + } + +} diff --git a/src/org/traccar/model/User.java b/src/org/traccar/model/User.java index 1c404c38a..8ac9e9d32 100644 --- a/src/org/traccar/model/User.java +++ b/src/org/traccar/model/User.java @@ -20,9 +20,6 @@ import org.traccar.web.JsonIgnore; public class User implements Factory { - public static final String ROLE_USER = "user"; - public static final String ROLE_ADMIN = "admin"; - @Override public User create() { return new User(); -- cgit v1.2.3 From 4ed22fb839fab2f19a6220bb8540317521209c4a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 1 Dec 2015 15:15:05 +1300 Subject: Remove Clazz utility class --- src/org/traccar/database/DataManager.java | 1 - src/org/traccar/helper/Clazz.java | 87 ------------------------------- src/org/traccar/web/JsonConverter.java | 11 +++- 3 files changed, 9 insertions(+), 90 deletions(-) delete mode 100644 src/org/traccar/helper/Clazz.java (limited to 'src/org/traccar') diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java index f01280836..978f08ef3 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -31,7 +31,6 @@ import java.util.Map; import javax.naming.InitialContext; import javax.sql.DataSource; import org.traccar.Config; -import org.traccar.helper.Clazz; import org.traccar.helper.DriverDelegate; import org.traccar.helper.Log; import org.traccar.model.Device; diff --git a/src/org/traccar/helper/Clazz.java b/src/org/traccar/helper/Clazz.java deleted file mode 100644 index 1a1b445d5..000000000 --- a/src/org/traccar/helper/Clazz.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * 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.helper; - -import java.beans.Introspector; -import java.io.Serializable; -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -public final class Clazz implements Serializable { - - public static Class getGenericArgumentType(Class currentClass) { - return getGenericArgumentType(currentClass, null, 0); - } - - public static Class getGenericArgumentType(Class currentClass, Class genericSuperClass, int argumentIndex) { - Type superType = currentClass.getGenericSuperclass(); - if (superType == null) { - throw new IllegalArgumentException(); - } - if (!(superType instanceof ParameterizedType) - || genericSuperClass != null - && ((ParameterizedType) superType).getRawType() != genericSuperClass) { - return getGenericArgumentType(currentClass.getSuperclass(), genericSuperClass, argumentIndex); - } - Object[] args = ((ParameterizedType) superType).getActualTypeArguments(); - if (argumentIndex >= args.length) { - throw new IllegalArgumentException(); - } - return cast(Class.class, args[argumentIndex]); - } - - public static T newInstance(Class clazz) { - try { - return clazz.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { - throw new IllegalArgumentException(); - } - } - - public static T cast(Class classe, Object objeto) { - if (classe.isAssignableFrom(objeto.getClass())) { - return classe.cast(objeto); - } - throw new ClassCastException(); - } - - public static long getId(T entity) throws Exception { - Method[] methods = entity.getClass().getMethods(); - for (final Method method : methods) { - if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { - final String name = Introspector.decapitalize(method.getName().substring(3)); - if (name.equals("id")) { - return Long.parseLong(method.invoke(entity).toString()); - } - } - } - throw new IllegalArgumentException(); - } - - public static void setId(T entity, I id) throws Exception { - Method[] methods = entity.getClass().getMethods(); - for (final Method method : methods) { - if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) { - final String name = Introspector.decapitalize(method.getName().substring(3)); - if (name.equals("id")) { - method.invoke(entity, id); - break; - } - } - } - } -} diff --git a/src/org/traccar/web/JsonConverter.java b/src/org/traccar/web/JsonConverter.java index 38721db61..2ef61fb13 100644 --- a/src/org/traccar/web/JsonConverter.java +++ b/src/org/traccar/web/JsonConverter.java @@ -34,7 +34,6 @@ import javax.json.JsonValue; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; -import org.traccar.helper.Clazz; import org.traccar.helper.Log; import org.traccar.model.Factory; import org.traccar.model.MiscFormatter; @@ -44,6 +43,14 @@ public final class JsonConverter { private JsonConverter() { } + private static T newClassInstance(Class clazz) { + try { + return clazz.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalArgumentException(); + } + } + private static final DateTimeFormatter DATE_FORMAT = ISODateTimeFormat.dateTime(); public static Date parseDate(String value) { @@ -69,7 +76,7 @@ public final class JsonConverter { } public static T objectFromJson(JsonObject json, Class clazz) { - T object = Clazz.newInstance(clazz); + T object = newClassInstance(clazz); Method[] methods = object.getClass().getMethods(); return objectFromJson(json, object, methods); } -- cgit v1.2.3 From 53f70085891cdb0feae56df8990c1245091352a1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 1 Dec 2015 15:18:13 +1300 Subject: Fix warning reported by FindBugs tool --- src/org/traccar/api/SecurityRequestFilter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/org/traccar') diff --git a/src/org/traccar/api/SecurityRequestFilter.java b/src/org/traccar/api/SecurityRequestFilter.java index b1e090487..63295a8b7 100644 --- a/src/org/traccar/api/SecurityRequestFilter.java +++ b/src/org/traccar/api/SecurityRequestFilter.java @@ -18,6 +18,7 @@ package org.traccar.api; import org.traccar.Context; import org.traccar.model.User; +import java.nio.charset.Charset; import java.sql.SQLException; import javax.ws.rs.WebApplicationException; import javax.ws.rs.container.ContainerRequestContext; @@ -35,7 +36,7 @@ public class SecurityRequestFilter implements ContainerRequestFilter { auth = auth.replaceFirst("[B|b]asic ", ""); byte[] decodedBytes = DatatypeConverter.parseBase64Binary(auth); if (decodedBytes != null && decodedBytes.length > 0) { - return new String(decodedBytes).split(":", 2); + return new String(decodedBytes, Charset.defaultCharset()).split(":", 2); } return null; } -- cgit v1.2.3