From 00e3b0194998d238bdc5c060a2d0c8a0836bc6e3 Mon Sep 17 00:00:00 2001 From: Julian Horner <julianhorner@web.de> Date: Thu, 2 Jan 2020 10:17:59 +0100 Subject: [PATCH] Add config, filter and controller packages --- .../rtuni/ms/apig/{ => config}/JwtConfig.java | 144 ++++++------ .../{ => config}/SecurityConfiguration.java | 152 ++++++------ .../{ => controller}/LoginController.java | 2 +- .../JwtTokenAuthenticationFilter.java | 217 +++++++++--------- 4 files changed, 259 insertions(+), 256 deletions(-) rename src/main/java/de/rtuni/ms/apig/{ => config}/JwtConfig.java (94%) rename src/main/java/de/rtuni/ms/apig/{ => config}/SecurityConfiguration.java (96%) rename src/main/java/de/rtuni/ms/apig/{ => controller}/LoginController.java (95%) rename src/main/java/de/rtuni/ms/apig/{ => filter}/JwtTokenAuthenticationFilter.java (97%) diff --git a/src/main/java/de/rtuni/ms/apig/JwtConfig.java b/src/main/java/de/rtuni/ms/apig/config/JwtConfig.java similarity index 94% rename from src/main/java/de/rtuni/ms/apig/JwtConfig.java rename to src/main/java/de/rtuni/ms/apig/config/JwtConfig.java index c95b1ce..da12d51 100644 --- a/src/main/java/de/rtuni/ms/apig/JwtConfig.java +++ b/src/main/java/de/rtuni/ms/apig/config/JwtConfig.java @@ -1,72 +1,72 @@ -/* - * Copyright 2019 (C) by Julian Horner. - * All Rights Reserved. - */ - -package de.rtuni.ms.apig; - -import org.springframework.beans.factory.annotation.Value; - -/** - * Configuration class for json web token. - * - * @author Julian - * - */ -public class JwtConfig { - //---------------------------------------------------------------------------------------------- - - @Value("${security.jwt.uri:/auth/**}") - private String Uri; - - @Value("${security.jwt.header:Authorization}") - private String header; - - @Value("${security.jwt.prefix:Bearer}") - private String prefix; - - @Value("${security.jwt.expiration:#{24*60*60}}") - private int expiration; - - @Value("${security.jwt.secret:JwtSecretKey}") - private String secret; - - //---------------------------------------------------------------------------------------------- - - /** - * Get the uri. - * - * @return The uri - */ - public String getUri() { return Uri; } - - /** - * Get the header. - * - * @return The header - */ - public String getHeader() { return header; } - - /** - * Get the prefix. - * - * @return The prefix - */ - public String getPrefix() { return prefix; } - - /** - * Get the expiration. - * - * @return The expiration - */ - public int getExpiration() { return expiration; } - - /** - * Get the secret. - * - * @return The secret - */ - public String getSecret() { return secret; } - - //---------------------------------------------------------------------------------------------- -} +/* + * Copyright 2019 (C) by Julian Horner. + * All Rights Reserved. + */ + +package de.rtuni.ms.apig.config; + +import org.springframework.beans.factory.annotation.Value; + +/** + * Configuration class for json web token. + * + * @author Julian + * + */ +public class JwtConfig { + //---------------------------------------------------------------------------------------------- + + @Value("${security.jwt.uri:/auth/**}") + private String Uri; + + @Value("${security.jwt.header:Authorization}") + private String header; + + @Value("${security.jwt.prefix:Bearer}") + private String prefix; + + @Value("${security.jwt.expiration:#{24*60*60}}") + private int expiration; + + @Value("${security.jwt.secret:JwtSecretKey}") + private String secret; + + //---------------------------------------------------------------------------------------------- + + /** + * Get the uri. + * + * @return The uri + */ + public String getUri() { return Uri; } + + /** + * Get the header. + * + * @return The header + */ + public String getHeader() { return header; } + + /** + * Get the prefix. + * + * @return The prefix + */ + public String getPrefix() { return prefix; } + + /** + * Get the expiration. + * + * @return The expiration + */ + public int getExpiration() { return expiration; } + + /** + * Get the secret. + * + * @return The secret + */ + public String getSecret() { return secret; } + + //---------------------------------------------------------------------------------------------- +} diff --git a/src/main/java/de/rtuni/ms/apig/SecurityConfiguration.java b/src/main/java/de/rtuni/ms/apig/config/SecurityConfiguration.java similarity index 96% rename from src/main/java/de/rtuni/ms/apig/SecurityConfiguration.java rename to src/main/java/de/rtuni/ms/apig/config/SecurityConfiguration.java index db00303..e1b430e 100644 --- a/src/main/java/de/rtuni/ms/apig/SecurityConfiguration.java +++ b/src/main/java/de/rtuni/ms/apig/config/SecurityConfiguration.java @@ -1,75 +1,77 @@ -/* - * Copyright 2019 (C) by Julian Horner. - * All Rights Reserved. - */ - -package de.rtuni.ms.apig; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -/** - * Class that enables custom security configuration. - * - * @author Julian - */ -@EnableWebSecurity -public class SecurityConfiguration extends WebSecurityConfigurerAdapter { - //---------------------------------------------------------------------------------------------- - - /** The <code>JwtConfig</code> for the json web token. */ - @Autowired - private JwtConfig jwtConfig; - - //---------------------------------------------------------------------------------------------- - - /** - * Overrides the default security configuration. - */ - @Override - protected void configure(HttpSecurity http) throws Exception { - http.csrf().disable() - // make sure we use stateless session; session won't be used to store user's state. - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() - - // Add a filter to validate the tokens with every request. - .addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), - UsernamePasswordAuthenticationFilter.class) - - .authorizeRequests() - .antMatchers("/auth/**").permitAll() - // Anyone who is trying to access the securedPage must be an ADMIN. - // TODO can we change the path to /securedPage? - .antMatchers("/securedPage/**").hasRole("ADMIN") - // Permit default path. - .antMatchers("/login").permitAll().and() - // Configures where to forward if authentication is required. - .formLogin().loginPage("/login") - // Configures url for processing of login data. - .loginProcessingUrl("process_login") // TODO can we remove this? - // Configures where to go if there is no previous visited page. - .defaultSuccessUrl("/", true).and() - // Configures url for processing of logout. - .logout().logoutUrl("/process_logout") - .deleteCookies("JSESSIONID"); // TODO i think we can remove this - } - - //---------------------------------------------------------------------------------------------- - - /** - * Get a new <code>JwtConfig</code>. - * - * @return The stated configuration - */ - @Bean - public JwtConfig jwtConfig() { - return new JwtConfig(); - } - - //---------------------------------------------------------------------------------------------- -} +/* + * Copyright 2019 (C) by Julian Horner. + * All Rights Reserved. + */ + +package de.rtuni.ms.apig.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +import de.rtuni.ms.apig.filter.JwtTokenAuthenticationFilter; + +/** + * Class that enables custom security configuration. + * + * @author Julian + */ +@EnableWebSecurity +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + //---------------------------------------------------------------------------------------------- + + /** The <code>JwtConfig</code> for the json web token. */ + @Autowired + private JwtConfig jwtConfig; + + //---------------------------------------------------------------------------------------------- + + /** + * Overrides the default security configuration. + */ + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable() + // make sure we use stateless session; session won't be used to store user's state. + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() + + // Add a filter to validate the tokens with every request. + .addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), + UsernamePasswordAuthenticationFilter.class) + + .authorizeRequests() + .antMatchers("/auth/**").permitAll() + // Anyone who is trying to access the securedPage must be an ADMIN. + // TODO can we change the path to /securedPage? + .antMatchers("/securedPage/**").hasRole("ADMIN") + // Permit default path. + .antMatchers("/login").permitAll().and() + // Configures where to forward if authentication is required. + .formLogin().loginPage("/login") + // Configures url for processing of login data. + .loginProcessingUrl("process_login") // TODO can we remove this? + // Configures where to go if there is no previous visited page. + .defaultSuccessUrl("/", true).and() + // Configures url for processing of logout. + .logout().logoutUrl("/process_logout") + .deleteCookies("JSESSIONID"); // TODO i think we can remove this + } + + //---------------------------------------------------------------------------------------------- + + /** + * Get a new <code>JwtConfig</code>. + * + * @return The stated configuration + */ + @Bean + public JwtConfig jwtConfig() { + return new JwtConfig(); + } + + //---------------------------------------------------------------------------------------------- +} diff --git a/src/main/java/de/rtuni/ms/apig/LoginController.java b/src/main/java/de/rtuni/ms/apig/controller/LoginController.java similarity index 95% rename from src/main/java/de/rtuni/ms/apig/LoginController.java rename to src/main/java/de/rtuni/ms/apig/controller/LoginController.java index b5ec763..f2a138b 100644 --- a/src/main/java/de/rtuni/ms/apig/LoginController.java +++ b/src/main/java/de/rtuni/ms/apig/controller/LoginController.java @@ -3,7 +3,7 @@ * All Rights Reserved. */ -package de.rtuni.ms.apig; +package de.rtuni.ms.apig.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/src/main/java/de/rtuni/ms/apig/JwtTokenAuthenticationFilter.java b/src/main/java/de/rtuni/ms/apig/filter/JwtTokenAuthenticationFilter.java similarity index 97% rename from src/main/java/de/rtuni/ms/apig/JwtTokenAuthenticationFilter.java rename to src/main/java/de/rtuni/ms/apig/filter/JwtTokenAuthenticationFilter.java index 902c4b6..7928f77 100644 --- a/src/main/java/de/rtuni/ms/apig/JwtTokenAuthenticationFilter.java +++ b/src/main/java/de/rtuni/ms/apig/filter/JwtTokenAuthenticationFilter.java @@ -1,108 +1,109 @@ -/* - * Copyright 2019 (C) by Julian Horner. - * All Rights Reserved. - */ - -package de.rtuni.ms.apig; - -import java.io.IOException; -import java.util.List; -import java.util.stream.Collectors; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.web.filter.OncePerRequestFilter; - -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; - -/** - * Filter class for authentication of the provided JSON web token. - * - * @author Julian - */ -public class JwtTokenAuthenticationFilter extends OncePerRequestFilter { - //---------------------------------------------------------------------------------------------- - - /** The <code>JwtConfig</code> for the json web token. */ - private final JwtConfig jwtConfig; - - //---------------------------------------------------------------------------------------------- - - /** - * Set the given <code>JwtConfig</code> for the token. - * - * @param config The stated configuration - */ - public JwtTokenAuthenticationFilter(final JwtConfig config) { jwtConfig = config; } - - //---------------------------------------------------------------------------------------------- - - /** - * If a token is supplied by the user the token will be decrypt and the user will be set as - * currently authenticated user. That includes the authorities which were granted to the - * user by the authentication service. If there is no supplied token the next filter will be - * executed. - * <p> - * {@inheritDoc} - */ - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, - FilterChain chain) throws ServletException, IOException { - - // Gets the authentication header. - String bearerToken = request.getParameter("access_token"); - // Validate the header and check the prefix. - if (bearerToken == null || !bearerToken.startsWith(jwtConfig.getPrefix())) { - // If no token is provided the user is not authenticated - // and we continue with the next filter. - // Thats okay because maybe the user is accessing a public path. - chain.doFilter(request, response); // If not valid, go to the next filter. - - return; - } - - // Removes the bearer substring from the authentication header. - String token = bearerToken.replace(jwtConfig.getPrefix(), ""); - - // Note that exceptions can be triggered when creating claims, e.g if the token has expired. - try { - // Sets secret and decrypt the token. - Claims claims = Jwts.parser().setSigningKey(jwtConfig.getSecret().getBytes()) - .parseClaimsJws(token).getBody(); - - String username = claims.getSubject(); - if (username != null) { - // Gets the authorities which were added to the token by the auth-service. - @SuppressWarnings("unchecked") - List<String> authorities = (List<String>) claims.get("authorities"); - - // Create an UsernamePasswordAuthenticationToken which represents the - // authenticated user or the user who is being authenticated currently. - // - // Because we need a list of authorities, which are from the type GrantedAuthority - // we have to convert the Strings to SimpleGrantedAuthority which is an - // implementation. - UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken( - username, null, authorities.stream() - .map(SimpleGrantedAuthority::new).collect(Collectors.toList())); - - // Set the user as new authenticated user. - SecurityContextHolder.getContext().setAuthentication(auth); - } - } catch (Exception e) { - // In case of failure. Make sure user won't be authenticated. - SecurityContextHolder.clearContext(); - } - - chain.doFilter(request, response); - } - - //---------------------------------------------------------------------------------------------- -} +/* + * Copyright 2019 (C) by Julian Horner. + * All Rights Reserved. + */ + +package de.rtuni.ms.apig.filter; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.OncePerRequestFilter; + +import de.rtuni.ms.apig.config.JwtConfig; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; + +/** + * Filter class for authentication of the provided JSON web token. + * + * @author Julian + */ +public class JwtTokenAuthenticationFilter extends OncePerRequestFilter { + //---------------------------------------------------------------------------------------------- + + /** The <code>JwtConfig</code> for the json web token. */ + private final JwtConfig jwtConfig; + + //---------------------------------------------------------------------------------------------- + + /** + * Set the given <code>JwtConfig</code> for the token. + * + * @param config The stated configuration + */ + public JwtTokenAuthenticationFilter(final JwtConfig config) { jwtConfig = config; } + + //---------------------------------------------------------------------------------------------- + + /** + * If a token is supplied by the user the token will be decrypt and the user will be set as + * currently authenticated user. That includes the authorities which were granted to the + * user by the authentication service. If there is no supplied token the next filter will be + * executed. + * <p> + * {@inheritDoc} + */ + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain chain) throws ServletException, IOException { + + // Gets the authentication header. + String bearerToken = request.getParameter("access_token"); + // Validate the header and check the prefix. + if (bearerToken == null || !bearerToken.startsWith(jwtConfig.getPrefix())) { + // If no token is provided the user is not authenticated + // and we continue with the next filter. + // Thats okay because maybe the user is accessing a public path. + chain.doFilter(request, response); // If not valid, go to the next filter. + + return; + } + + // Removes the bearer substring from the authentication header. + String token = bearerToken.replace(jwtConfig.getPrefix(), ""); + + // Note that exceptions can be triggered when creating claims, e.g if the token has expired. + try { + // Sets secret and decrypt the token. + Claims claims = Jwts.parser().setSigningKey(jwtConfig.getSecret().getBytes()) + .parseClaimsJws(token).getBody(); + + String username = claims.getSubject(); + if (username != null) { + // Gets the authorities which were added to the token by the auth-service. + @SuppressWarnings("unchecked") + List<String> authorities = (List<String>) claims.get("authorities"); + + // Create an UsernamePasswordAuthenticationToken which represents the + // authenticated user or the user who is being authenticated currently. + // + // Because we need a list of authorities, which are from the type GrantedAuthority + // we have to convert the Strings to SimpleGrantedAuthority which is an + // implementation. + UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken( + username, null, authorities.stream() + .map(SimpleGrantedAuthority::new).collect(Collectors.toList())); + + // Set the user as new authenticated user. + SecurityContextHolder.getContext().setAuthentication(auth); + } + } catch (Exception e) { + // In case of failure. Make sure user won't be authenticated. + SecurityContextHolder.clearContext(); + } + + chain.doFilter(request, response); + } + + //---------------------------------------------------------------------------------------------- +} -- GitLab