From 7bebf8b84b4f20829b9859d365e82ccfe94a0233 Mon Sep 17 00:00:00 2001 From: Nikolaos Laskaris Date: Fri, 13 Oct 2017 18:08:49 +0300 Subject: [PATCH] Security is now completed... only token-based calls are now permitted. --- dmp-backend/.project | 1 + .../org.eclipse.wst.common.component | 2 +- ....eclipse.wst.common.project.facet.core.xml | 2 +- dmp-backend/pom.xml | 32 ++++++------- .../src/main/java/{rest => }/login/Login.java | 4 +- .../CustomAuthenticationProvider.java | 46 +++++++++++++------ .../security/TokenAuthenticationFilter.java | 24 +++++----- .../java/security/TokenSessionManager.java | 10 ++-- .../validators/GoogleTokenValidator.java | 22 ++++----- .../validators/NativeTokenValidator.java | 22 +++++++++ .../security/validators/TokenValidator.java | 9 ++++ .../webapp/WEB-INF/applicationContext.xml | 9 ++-- .../WEB-INF/dmp-backend-login-servlet.xml | 39 ++++++++++++++++ .../main/webapp/WEB-INF/spring-security.xml | 16 +------ dmp-backend/src/main/webapp/WEB-INF/web.xml | 23 +++++++--- 15 files changed, 175 insertions(+), 86 deletions(-) rename dmp-backend/src/main/java/{rest => }/login/Login.java (98%) create mode 100644 dmp-backend/src/main/java/security/validators/NativeTokenValidator.java create mode 100644 dmp-backend/src/main/java/security/validators/TokenValidator.java create mode 100644 dmp-backend/src/main/webapp/WEB-INF/dmp-backend-login-servlet.xml diff --git a/dmp-backend/.project b/dmp-backend/.project index bcfc37cda..cff1ef775 100644 --- a/dmp-backend/.project +++ b/dmp-backend/.project @@ -32,5 +32,6 @@ org.eclipse.m2e.core.maven2Nature org.eclipse.jdt.core.javanature org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature diff --git a/dmp-backend/.settings/org.eclipse.wst.common.component b/dmp-backend/.settings/org.eclipse.wst.common.component index 319e1de6c..9c7a1cfe1 100644 --- a/dmp-backend/.settings/org.eclipse.wst.common.component +++ b/dmp-backend/.settings/org.eclipse.wst.common.component @@ -4,7 +4,7 @@ - + diff --git a/dmp-backend/.settings/org.eclipse.wst.common.project.facet.core.xml b/dmp-backend/.settings/org.eclipse.wst.common.project.facet.core.xml index 41fc032d2..1c90fe5f2 100644 --- a/dmp-backend/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/dmp-backend/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -1,8 +1,8 @@ - + diff --git a/dmp-backend/pom.xml b/dmp-backend/pom.xml index ef61d55b6..3e790fb93 100644 --- a/dmp-backend/pom.xml +++ b/dmp-backend/pom.xml @@ -98,19 +98,19 @@ org.springframework.security spring-security-core - 4.2.3.RELEASE + ${org.springframework.security.version} org.springframework.security spring-security-web - 4.2.3.RELEASE + ${org.springframework.security.version} org.springframework.security spring-security-config - 4.2.3.RELEASE + ${org.springframework.security.version} @@ -239,20 +239,20 @@ - org.springframework.security - spring-security-web - ${org.springframework.security.version} - - - org.springframework.security - spring-security-config - ${org.springframework.security.version} - + org.springframework.security + spring-security-web + ${org.springframework.security.version} + + + org.springframework.security + spring-security-config + ${org.springframework.security.version} + - - org.springframework - spring-tx - ${org.springframework.version} + + org.springframework + spring-tx + ${org.springframework.version} diff --git a/dmp-backend/src/main/java/rest/login/Login.java b/dmp-backend/src/main/java/login/Login.java similarity index 98% rename from dmp-backend/src/main/java/rest/login/Login.java rename to dmp-backend/src/main/java/login/Login.java index 9a6022613..83396c21a 100644 --- a/dmp-backend/src/main/java/rest/login/Login.java +++ b/dmp-backend/src/main/java/login/Login.java @@ -1,4 +1,4 @@ -package rest.login; +package login; import java.io.Serializable; import java.security.MessageDigest; @@ -71,7 +71,7 @@ public class Login { // create a token token = tokenSessionManager.generateRandomAlphanumeric(512); // add it to the cache - tokenSessionManager.set(credentials.getUsername(), token); + tokenSessionManager.set(token, credentials.getUsername()); } //get also the additional info of the user (if he has) diff --git a/dmp-backend/src/main/java/security/CustomAuthenticationProvider.java b/dmp-backend/src/main/java/security/CustomAuthenticationProvider.java index 77247c341..dd3c92938 100644 --- a/dmp-backend/src/main/java/security/CustomAuthenticationProvider.java +++ b/dmp-backend/src/main/java/security/CustomAuthenticationProvider.java @@ -2,15 +2,22 @@ package security; import java.util.ArrayList; +import javax.naming.NameAlreadyBoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.stereotype.Component; import dao.entities.security.UserInfoDao; +import entities.security.UserInfo; +import exceptions.NonValidTokenException; +import security.validators.GoogleTokenValidator; +import security.validators.NativeTokenValidator; +import security.validators.TokenValidator; @Component public class CustomAuthenticationProvider implements AuthenticationProvider { @@ -18,36 +25,49 @@ public class CustomAuthenticationProvider implements AuthenticationProvider { @Autowired private UserInfoDao userInfoDao; + @Autowired private GoogleTokenValidator googleTokenValidator; + @Autowired private NativeTokenValidator nativeTokenValidator; + @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { - /* + if (authentication != null) { - // check whether the token is valid + String token = (String)authentication.getCredentials(); - GoogleTokenValidator gValidator = new GoogleTokenValidator(); - UserInfo userInfo = null; + + TokenValidator tokenValidator = null; + + if(TokenAuthenticationFilter.HEADER_GOOGLE_TOKEN_FIELD.equals(authentication.getPrincipal())) + tokenValidator = googleTokenValidator; + else if(TokenAuthenticationFilter.HEADER_NATIVE_TOKEN_FIELD.equals(authentication.getPrincipal())) + tokenValidator = nativeTokenValidator; + else + throw new AuthenticationServiceException("The appropriate http headers have not been set. Please check!"); + + try { - userInfo = gValidator.validateToken(token); + tokenValidator.validateToken(token); } catch (NonValidTokenException e) { System.out.println("Could not validate a user by his token! Reason: "+e.getMessage()); throw new AuthenticationServiceException("Token validation failed - Not a valid token"); } - //store to database if new - UserInfo existingUserInfo = userInfoDao.getByKey(userInfo.getId(), userInfo.getEmail()); - if(existingUserInfo == null) - userInfoDao.create(userInfo); - // if reached this point, authentication is ok + //store to database if new +// UserInfo existingUserInfo = userInfoDao.getByKey(userInfo.getId(), userInfo.getEmail()); +// if(existingUserInfo == null) +// userInfoDao.create(userInfo); + + // if reached this point, authentication is ok, so return just an instance with whatever. return new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), new ArrayList<>()); } else throw new AuthenticationServiceException("Authentication failed"); - */ + - //DELETE THIS, USE THE ABOVE - return new UsernamePasswordAuthenticationToken("", "", new ArrayList<>()); +// //DELETE THIS, USE THE ABOVE +// return new UsernamePasswordAuthenticationToken("", "", new ArrayList<>()); } diff --git a/dmp-backend/src/main/java/security/TokenAuthenticationFilter.java b/dmp-backend/src/main/java/security/TokenAuthenticationFilter.java index dd69e94c6..a38204eba 100644 --- a/dmp-backend/src/main/java/security/TokenAuthenticationFilter.java +++ b/dmp-backend/src/main/java/security/TokenAuthenticationFilter.java @@ -14,9 +14,11 @@ import org.springframework.web.filter.GenericFilterBean; public class TokenAuthenticationFilter extends GenericFilterBean { - - private static final String HEADER_NATIVE_TOKEN_FIELD = "native-token"; - private static final String HEADER_GOOGLE_TOKEN_FIELD = "google-token"; + + public static final String HEADER_NATIVE_TOKEN_FIELD = "native-token"; + public static final String HEADER_GOOGLE_TOKEN_FIELD = "google-token"; + + public static final char HEADERNAME_USERNAME_DELIMITER = 0x1e; //specially crafted delimiter @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { @@ -26,17 +28,17 @@ public class TokenAuthenticationFilter extends GenericFilterBean { String nativeToken = httpRequest.getHeader(HEADER_NATIVE_TOKEN_FIELD); String googleToken = httpRequest.getHeader(HEADER_GOOGLE_TOKEN_FIELD); - //just pass the token into the credentials object of the UsernamePasswordAuthenticationToken class + //just pass the header, the username and the token into the credentials object of the UsernamePasswordAuthenticationToken class UsernamePasswordAuthenticationToken authentication = null; - if(nativeToken != null) - authentication = new UsernamePasswordAuthenticationToken("native-user", nativeToken); + if(nativeToken != null) + authentication = new UsernamePasswordAuthenticationToken(HEADER_NATIVE_TOKEN_FIELD, nativeToken); if(googleToken != null) - authentication = new UsernamePasswordAuthenticationToken("google-user", nativeToken); + authentication = new UsernamePasswordAuthenticationToken(HEADER_GOOGLE_TOKEN_FIELD, googleToken); - if(authentication != null) { - SecurityContextHolder.getContext().setAuthentication(authentication); - chain.doFilter(request, response); - } + + SecurityContextHolder.getContext().setAuthentication(authentication); + chain.doFilter(request, response); + } diff --git a/dmp-backend/src/main/java/security/TokenSessionManager.java b/dmp-backend/src/main/java/security/TokenSessionManager.java index 18e491f77..8b4e36047 100644 --- a/dmp-backend/src/main/java/security/TokenSessionManager.java +++ b/dmp-backend/src/main/java/security/TokenSessionManager.java @@ -34,16 +34,14 @@ public class TokenSessionManager { .build(); } - - public String get(String key) { - return cache.getIfPresent(key); + public String getUser(String token) { + return cache.getIfPresent(token); } - public void set(String key, String value) { - cache.put(key, value); + public void set(String token, String user) { + cache.put(token, user); } - public String generateRandomAlphanumeric(int length) { SecureRandom random = new SecureRandom(); byte bytes[] = new byte[length]; diff --git a/dmp-backend/src/main/java/security/validators/GoogleTokenValidator.java b/dmp-backend/src/main/java/security/validators/GoogleTokenValidator.java index 23fecaf41..cc381c298 100644 --- a/dmp-backend/src/main/java/security/validators/GoogleTokenValidator.java +++ b/dmp-backend/src/main/java/security/validators/GoogleTokenValidator.java @@ -15,7 +15,7 @@ import com.google.api.client.json.jackson2.JacksonFactory; import entities.security.UserInfo; import exceptions.NonValidTokenException; -public class GoogleTokenValidator { +public class GoogleTokenValidator implements TokenValidator { private static final JacksonFactory jacksonFactory = new JacksonFactory(); private static final HttpTransport transport = new NetHttpTransport(); @@ -34,7 +34,8 @@ public class GoogleTokenValidator { } - public UserInfo validateToken(String token) throws NonValidTokenException { + @Override + public void validateToken(String token) throws NonValidTokenException { GoogleIdToken idToken = null; try { @@ -49,22 +50,19 @@ public class GoogleTokenValidator { catch(IllegalArgumentException ex) { throw new NonValidTokenException("Could not verify token"); } - - if (idToken != null) { - Payload payload = idToken.getPayload(); - + if(idToken == null) { + throw new NonValidTokenException("Not a valid token"); + } +// else { +// Payload payload = idToken.getPayload(); // UserInfo userInfo = new UserInfo(payload.getSubject(), payload.getEmail(), // payload.getEmailVerified(), (String)payload.get("name"), (String)payload.get("picture"), // (String)payload.get("locale"), (String)payload.get("family_name"), (String)payload.get("given_name"), ""); // System.out.println(userInfo.toString()); // return userInfo; - - return null; - - } else { - throw new NonValidTokenException("Not a valid token"); - } +// } + } diff --git a/dmp-backend/src/main/java/security/validators/NativeTokenValidator.java b/dmp-backend/src/main/java/security/validators/NativeTokenValidator.java new file mode 100644 index 000000000..65494cd2d --- /dev/null +++ b/dmp-backend/src/main/java/security/validators/NativeTokenValidator.java @@ -0,0 +1,22 @@ +package security.validators; + +import org.springframework.beans.factory.annotation.Autowired; + +import exceptions.NonValidTokenException; +import security.TokenSessionManager; + +public class NativeTokenValidator implements TokenValidator { + + @Autowired private TokenSessionManager tokenSessionManager; + + @Override + public void validateToken(String token) throws NonValidTokenException { + String tokenUser = tokenSessionManager.getUser(token); + if(tokenUser==null || tokenUser.isEmpty()) + throw new NonValidTokenException("Login session has expired! Need to login again!"); + } + + + + +} diff --git a/dmp-backend/src/main/java/security/validators/TokenValidator.java b/dmp-backend/src/main/java/security/validators/TokenValidator.java new file mode 100644 index 000000000..65a7a6710 --- /dev/null +++ b/dmp-backend/src/main/java/security/validators/TokenValidator.java @@ -0,0 +1,9 @@ +package security.validators; + +import exceptions.NonValidTokenException; + +public interface TokenValidator { + + public void validateToken(String token) throws NonValidTokenException; + +} diff --git a/dmp-backend/src/main/webapp/WEB-INF/applicationContext.xml b/dmp-backend/src/main/webapp/WEB-INF/applicationContext.xml index 298b9bcc0..eda1d3d0e 100644 --- a/dmp-backend/src/main/webapp/WEB-INF/applicationContext.xml +++ b/dmp-backend/src/main/webapp/WEB-INF/applicationContext.xml @@ -25,8 +25,11 @@ - - + + + + + @@ -79,7 +82,7 @@ - + diff --git a/dmp-backend/src/main/webapp/WEB-INF/dmp-backend-login-servlet.xml b/dmp-backend/src/main/webapp/WEB-INF/dmp-backend-login-servlet.xml new file mode 100644 index 000000000..4d2127185 --- /dev/null +++ b/dmp-backend/src/main/webapp/WEB-INF/dmp-backend-login-servlet.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dmp-backend/src/main/webapp/WEB-INF/spring-security.xml b/dmp-backend/src/main/webapp/WEB-INF/spring-security.xml index 1110f6bb5..4b7e18fac 100644 --- a/dmp-backend/src/main/webapp/WEB-INF/spring-security.xml +++ b/dmp-backend/src/main/webapp/WEB-INF/spring-security.xml @@ -1,5 +1,4 @@ - \ No newline at end of file diff --git a/dmp-backend/src/main/webapp/WEB-INF/web.xml b/dmp-backend/src/main/webapp/WEB-INF/web.xml index 957c29d88..36f94ae55 100644 --- a/dmp-backend/src/main/webapp/WEB-INF/web.xml +++ b/dmp-backend/src/main/webapp/WEB-INF/web.xml @@ -3,6 +3,20 @@ dmp-backend + + + dmp-backend-login + org.springframework.web.servlet.DispatcherServlet + 1 + + + dmp-backend-login + /login/* + + + org.springframework.web.context.ContextLoaderListener + + dmp-backend-rest org.springframework.web.servlet.DispatcherServlet @@ -37,11 +51,10 @@ - - + contextConfigLocation - /WEB-INF/applicationContext.xml + /WEB-INF/applicationContext.xml,/WEB-INF/spring-security.xml @@ -49,17 +62,15 @@ -