Security is now completed... only token-based calls are now permitted.

This commit is contained in:
Nikolaos Laskaris 2017-10-13 18:08:49 +03:00
parent 55e4556167
commit 7bebf8b84b
15 changed files with 175 additions and 86 deletions

View File

@ -32,5 +32,6 @@
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
</natures>
</projectDescription>

View File

@ -4,7 +4,7 @@
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<property name="java-output-path" value="/dmp-backend/target/classes"/>
<property name="context-root" value="dmp-backend"/>
<property name="java-output-path" value="/dmp-backend/target/classes"/>
</wb-module>
</project-modules>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<fixed facet="wst.jsdt.web"/>
<installed facet="wst.jsdt.web" version="1.0"/>
<installed facet="java" version="1.8"/>
<installed facet="jst.web" version="3.0"/>
<installed facet="jpt.jpa" version="2.1"/>
<installed facet="wst.jsdt.web" version="1.0"/>
</faceted-project>

View File

@ -98,19 +98,19 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.2.3.RELEASE</version>
<version>${org.springframework.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.3.RELEASE</version>
<version>${org.springframework.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.3.RELEASE</version>
<version>${org.springframework.security.version}</version>
</dependency>
<dependency>
@ -239,20 +239,20 @@
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${org.springframework.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${org.springframework.security.version}</version>
</dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${org.springframework.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${org.springframework.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework.version}</version>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework.version}</version>
</dependency>

View File

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

View File

@ -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<>());
}

View File

@ -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);
}

View File

@ -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];

View File

@ -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");
}
// }
}

View File

@ -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!");
}
}

View File

@ -0,0 +1,9 @@
package security.validators;
import exceptions.NonValidTokenException;
public interface TokenValidator {
public void validateToken(String token) throws NonValidTokenException;
}

View File

@ -25,8 +25,11 @@
</bean>
<bean id="tokenSessionManager" class="security.TokenSessionManager" factory-method="getInstance">
</bean>
<bean id="tokenSessionManager" class="security.TokenSessionManager" factory-method="getInstance" />
<bean id="googleTokenValidator" class="security.validators.GoogleTokenValidator" />
<bean id="nativeTokenValidator" class="security.validators.NativeTokenValidator" />
<bean id="proxy" class="rest.proxy.Proxy">
<constructor-arg type = "String" value = "${proxy.allowed.host}"/>
@ -79,7 +82,7 @@
</props>
</property>
</bean>
<bean id="organisationDao" class="dao.entities.OrganisationDaoImpl" />

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<!-- <context:property-placeholder location="classpath*:**/dmp.properties" /> -->
<mvc:resources mapping="resources/**" location="/resources/" />
<mvc:annotation-driven />
<context:component-scan base-package="login" />
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000000" />
</bean>
<bean id="jsonConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="prefixJson" value="false" />
<property name="supportedMediaTypes" value="application/json" />
</bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter" />
</list>
</property>
</bean>
</beans>

View File

@ -1,5 +1,4 @@
<!--
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@ -32,18 +31,5 @@
<beans:bean id="tokenFilter" class="security.TokenAuthenticationFilter"/>
<authentication-manager>
<authentication-provider>
<password-encoder ref="encoder" />
</authentication-provider>
</authentication-manager>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="11" />
</beans:bean>
</beans:beans>
-->

View File

@ -3,6 +3,20 @@
<display-name>dmp-backend</display-name>
<servlet>
<servlet-name>dmp-backend-login</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dmp-backend-login</servlet-name>
<url-pattern>/login/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dmp-backend-rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
@ -37,11 +51,10 @@
</listener-class>
</listener>
<!-- ,/WEB-INF/spring-security.xml -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml
<param-value>/WEB-INF/applicationContext.xml,/WEB-INF/spring-security.xml
</param-value>
</context-param>
<session-config>
@ -49,17 +62,15 @@
</session-config>
<!-- THIS FILTER IS FOR SPRING SECURITY -->
<!--
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>
-->