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') 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