@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
CredentialsService credentialsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String email = authentication.getName();
String password = authentication.getCredentials().toString();
List<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<SimpleGrantedAuthority>();
User user = null;
try {
user = credentialsService.findByEmail(new EmailAddress(email));
} catch (IllegalArgumentException e) {
throw new BadCredentialsException("The login " + email + " and password could not match.");
}
if (user != null) {
if (credentialsService.checkPassword(user, password)) {
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
return new UsernamePasswordAuthenticationToken(email, password, grantedAuthorities);
} else {
throw new BadCredentialsException("The login " + user.getEmail() + " and password could not match.");
}
}
throw new BadCredentialsException("The login " + authentication.getPrincipal() + " and password could not match.");
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
@Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
}
@Component
public class AuthenticationFromTokenFilter extends GenericFilterBeanOncePerRequestFilter {
@Autowired
private TokenAuthenticationService tokenAuthenticationService;
@Override
publicprotected void doFilterdoFilterInternal(ServletRequestHttpServletRequest request, ServletResponseHttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = getAsHttpRequest(request);
tokenAuthenticationService.authenticateFromToken(httpRequestrequest);
chain.doFilter(request, response);
}
private HttpServletRequest getAsHttpRequest(ServletRequest request) {
if (!(request instanceof HttpServletRequest)) {
throw new RuntimeException("The request was not an HTTP request");
}
return (HttpServletRequest) request;
}
}
@Service
public class TokenAuthenticationServiceImpl implements TokenAuthenticationService {
private static Logger logger = LoggerFactory.getLogger(TokenAuthenticationServiceImpl.class);
private static final long ONE_WEEK = 1000 * 60 * 60 * 24 * 7;
private static final String TOKEN_URL_PARAM_NAME = "token";
@Autowired
private ApplicationProperties applicationProperties;
@Autowired
private UserDetailsService userDetailsService;
public void addTokenToResponseHeader(HttpHeaders headers, String username) {
String token = buildToken(username);
headers.add(CommonConstants.AUTH_HEADER_NAME, token);
}
public void addTokenToResponseHeader(HttpServletResponse response, Authentication authentication) {
String username = authentication.getName();
if (username != null) {
String token = buildToken(username);
response.addHeader(CommonConstants.AUTH_HEADER_NAME, token);
}
}
private String buildToken(String username) {
String token = null;
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (userDetails != null) {
Date expirationDate = new Date(System.currentTimeMillis() + ONE_WEEK);
token = CommonConstants.AUTH_BEARER + " " + Jwts.builder().signWith(HS256, getEncodedPrivateKey()).setExpiration(expirationDate).setSubject(userDetails.getUsername()).compact();
}
return token;
}
public Authentication authenticateFromToken(HttpServletRequest request) {
String token = extractAuthTokenFromRequest(request);
logger.debug("The request contained the JWT token: " + token);
if (token != null && !token.isEmpty()) {
try {
String username = Jwts.parser().setSigningKey(getEncodedPrivateKey()).parseClaimsJws(token).getBody().getSubject();
if (username != null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
logger.debug("Security - The filter authenticated fine from the JWT token");
}
} catch (SignatureException e) {
logger.info("The JWT token " + token + " could not be parsed.");
}
}
return null;
}
private String extractAuthTokenFromRequest(HttpServletRequest request) {
String token = null;
String header = request.getHeader(CommonConstants.AUTH_HEADER_NAME);
if (header != null && header.contains(CommonConstants.AUTH_BEARER)) {
int start = (CommonConstants.AUTH_BEARER + " ").length();
if (header.length() > start) {
token = header.substring(start - 1);
}
} else {
// The token may be set as an HTTP parameter in case the client could not set it as an HTTP header
token = request.getParameter(TOKEN_URL_PARAM_NAME);
}
return token;
}
private String getEncodedPrivateKey() {
String privateKey = applicationProperties.getAuthenticationTokenPrivateKey();
return Base64.getEncoder().encodeToString(privateKey.getBytes());
}
}
@Configuration
@EnableWebSecurity
@ComponentScan(nameGenerator = PackageBeanNameGenerator.class, basePackages = { "com.thalasoft.user.rest.security", "com.thalasoft.user.rest.filter" })
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override@Autowired
protectedprivate voidUserDetailsService configure(AuthenticationManagerBuilderuserDetailsService;
authenticationManagerBuilder
@Autowired
private AuthenticationFromTokenFilter authenticationFromTokenFilter;
@Autowired
private SimpleCORSFilter simpleCORSFilter;
@Autowired
private RESTAuthenticationEntryPoint restAuthenticationEntryPoint;
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
authenticationManagerBuilderreturn super.authenticationProviderauthenticationManagerBean(customAuthenticationProvider);
}
@Override
protected void configure(HttpSecurityAuthenticationManagerBuilder httpauthenticationManagerBuilder) throws Exception {
httpauthenticationManagerBuilder.userDetailsServiceauthenticationProvider(userDetailsServicenew CustomAuthenticationProvider());
}
http.addFilterBefore(new SimpleCORSFilter(), UsernamePasswordAuthenticationFilter.class);
@Override
protected void http.addFilterBeforeconfigure(authenticationFromTokenFilter,HttpSecurity UsernamePasswordAuthenticationFilter.classhttp);
throws Exception {
http.headers().cacheControlexceptionHandling();
.authenticationEntryPoint(restAuthenticationEntryPoint)
http.and()
.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().httpBasicaddFilterBefore()simpleCORSFilter, UsernamePasswordAuthenticationFilter.authenticationEntryPoint(restAuthenticationEntryPointclass)
.andaddFilterBefore()authenticationFromTokenFilter, UsernamePasswordAuthenticationFilter.authorizeRequests(class)
.antMatchers(RESTConstants.SLASH + RESTConstants.API + "/**".headers().hasRolecacheControl("ADMIN").anyRequestdisable().authenticatedframeOptions().disable()
.antMatchersand(RESTConstants.SLASH)
+ RESTConstants.API + RESTConstants.SLASH + RESTConstants.ERRORuserDetailsService(userDetailsService).permitAllauthorizeRequests()
.antMatchers(RESTConstants.SLASH + RESTConstantsUserDomainConstants.APIUSERS + RESTConstants.SLASH + UserDomainConstants.USERSLOGIN).permitAll()
+ .antMatchers(RESTConstants.SLASH + UserDomainConstantsRESTConstants.LOGINERROR).permitAll()
.andantMatchers("/**").exceptionHandlinghasRole(UserDomainConstants.ROLE_ADMIN).authenticationEntryPointanyRequest(restAuthenticationEntryPoint).authenticated();
}
}
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
CredentialsService credentialsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String email = authentication.getName();
String password = authentication.getCredentials().toString();
List<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<SimpleGrantedAuthority>();
User user = null;
try {
user = credentialsService.findByEmail(new EmailAddress(email));
} catch (IllegalArgumentException e) {
throw new BadCredentialsException("The login " + email + " and password could not match.");
}
if (user != null) {
if (credentialsService.checkPassword(user, password)) {
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
return new UsernamePasswordAuthenticationToken(email, password, grantedAuthorities);
} else {
throw new BadCredentialsException("The login " + user.getEmail() + " and password could not match.");
}
}
throw new BadCredentialsException("The login " + authentication.getPrincipal() + " and password could not match.");
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
@Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
}
@Component
public class AuthenticationFromTokenFilter extends GenericFilterBean {
@Autowired
private TokenAuthenticationService tokenAuthenticationService;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = getAsHttpRequest(request);
tokenAuthenticationService.authenticateFromToken(httpRequest);
chain.doFilter(request, response);
}
private HttpServletRequest getAsHttpRequest(ServletRequest request) {
if (!(request instanceof HttpServletRequest)) {
throw new RuntimeException("The request was not an HTTP request");
}
return (HttpServletRequest) request;
}
}
@Service
public class TokenAuthenticationServiceImpl implements TokenAuthenticationService {
private static Logger logger = LoggerFactory.getLogger(TokenAuthenticationServiceImpl.class);
private static final long ONE_WEEK = 1000 * 60 * 60 * 24 * 7;
private static final String TOKEN_URL_PARAM_NAME = "token";
@Autowired
private ApplicationProperties applicationProperties;
@Autowired
private UserDetailsService userDetailsService;
public void addTokenToResponseHeader(HttpHeaders headers, String username) {
String token = buildToken(username);
headers.add(CommonConstants.AUTH_HEADER_NAME, token);
}
public void addTokenToResponseHeader(HttpServletResponse response, Authentication authentication) {
String username = authentication.getName();
if (username != null) {
String token = buildToken(username);
response.addHeader(CommonConstants.AUTH_HEADER_NAME, token);
}
}
private String buildToken(String username) {
String token = null;
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (userDetails != null) {
Date expirationDate = new Date(System.currentTimeMillis() + ONE_WEEK);
token = CommonConstants.AUTH_BEARER + " " + Jwts.builder().signWith(HS256, getEncodedPrivateKey()).setExpiration(expirationDate).setSubject(userDetails.getUsername()).compact();
}
return token;
}
public Authentication authenticateFromToken(HttpServletRequest request) {
String token = extractAuthTokenFromRequest(request);
logger.debug("The request contained the JWT token: " + token);
if (token != null && !token.isEmpty()) {
try {
String username = Jwts.parser().setSigningKey(getEncodedPrivateKey()).parseClaimsJws(token).getBody().getSubject();
if (username != null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
logger.debug("Security - The filter authenticated fine from the JWT token");
}
} catch (SignatureException e) {
logger.info("The JWT token " + token + " could not be parsed.");
}
}
return null;
}
private String extractAuthTokenFromRequest(HttpServletRequest request) {
String token = null;
String header = request.getHeader(CommonConstants.AUTH_HEADER_NAME);
if (header != null && header.contains(CommonConstants.AUTH_BEARER)) {
int start = (CommonConstants.AUTH_BEARER + " ").length();
if (header.length() > start) {
token = header.substring(start - 1);
}
} else {
// The token may be set as an HTTP parameter in case the client could not set it as an HTTP header
token = request.getParameter(TOKEN_URL_PARAM_NAME);
}
return token;
}
private String getEncodedPrivateKey() {
String privateKey = applicationProperties.getAuthenticationTokenPrivateKey();
return Base64.getEncoder().encodeToString(privateKey.getBytes());
}
}
@Configuration
@EnableWebSecurity
@ComponentScan(nameGenerator = PackageBeanNameGenerator.class, basePackages = { "com.thalasoft.user.rest.security" })
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.authenticationProvider(customAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.userDetailsService(userDetailsService);
http.addFilterBefore(new SimpleCORSFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(authenticationFromTokenFilter, UsernamePasswordAuthenticationFilter.class);
http.headers().cacheControl();
http
.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().httpBasic().authenticationEntryPoint(restAuthenticationEntryPoint)
.and().authorizeRequests()
.antMatchers(RESTConstants.SLASH + RESTConstants.API + "/**").hasRole("ADMIN").anyRequest().authenticated()
.antMatchers(RESTConstants.SLASH + RESTConstants.API + RESTConstants.SLASH + RESTConstants.ERROR).permitAll()
.antMatchers(RESTConstants.SLASH + RESTConstants.API + RESTConstants.SLASH + UserDomainConstants.USERS + RESTConstants.SLASH + UserDomainConstants.LOGIN).permitAll()
.and().exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint);
}
}
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
CredentialsService credentialsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String email = authentication.getName();
String password = authentication.getCredentials().toString();
List<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<SimpleGrantedAuthority>();
User user = null;
try {
user = credentialsService.findByEmail(new EmailAddress(email));
} catch (IllegalArgumentException e) {
throw new BadCredentialsException("The login " + email + " and password could not match.");
}
if (user != null) {
if (credentialsService.checkPassword(user, password)) {
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
return new UsernamePasswordAuthenticationToken(email, password, grantedAuthorities);
} else {
throw new BadCredentialsException("The login " + user.getEmail() + " and password could not match.");
}
}
throw new BadCredentialsException("The login " + authentication.getPrincipal() + " and password could not match.");
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
@Component
public class AuthenticationFromTokenFilter extends OncePerRequestFilter {
@Autowired
private TokenAuthenticationService tokenAuthenticationService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
tokenAuthenticationService.authenticateFromToken(request);
chain.doFilter(request, response);
}
}
@Service
public class TokenAuthenticationServiceImpl implements TokenAuthenticationService {
private static Logger logger = LoggerFactory.getLogger(TokenAuthenticationServiceImpl.class);
private static final long ONE_WEEK = 1000 * 60 * 60 * 24 * 7;
private static final String TOKEN_URL_PARAM_NAME = "token";
@Autowired
private ApplicationProperties applicationProperties;
@Autowired
private UserDetailsService userDetailsService;
public void addTokenToResponseHeader(HttpHeaders headers, String username) {
String token = buildToken(username);
headers.add(CommonConstants.AUTH_HEADER_NAME, token);
}
public void addTokenToResponseHeader(HttpServletResponse response, Authentication authentication) {
String username = authentication.getName();
if (username != null) {
String token = buildToken(username);
response.addHeader(CommonConstants.AUTH_HEADER_NAME, token);
}
}
private String buildToken(String username) {
String token = null;
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (userDetails != null) {
Date expirationDate = new Date(System.currentTimeMillis() + ONE_WEEK);
token = CommonConstants.AUTH_BEARER + " " + Jwts.builder().signWith(HS256, getEncodedPrivateKey()).setExpiration(expirationDate).setSubject(userDetails.getUsername()).compact();
}
return token;
}
public Authentication authenticateFromToken(HttpServletRequest request) {
String token = extractAuthTokenFromRequest(request);
logger.debug("The request contained the JWT token: " + token);
if (token != null && !token.isEmpty()) {
try {
String username = Jwts.parser().setSigningKey(getEncodedPrivateKey()).parseClaimsJws(token).getBody().getSubject();
if (username != null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
logger.debug("Security - The filter authenticated fine from the JWT token");
}
} catch (SignatureException e) {
logger.info("The JWT token " + token + " could not be parsed.");
}
}
return null;
}
private String extractAuthTokenFromRequest(HttpServletRequest request) {
String token = null;
String header = request.getHeader(CommonConstants.AUTH_HEADER_NAME);
if (header != null && header.contains(CommonConstants.AUTH_BEARER)) {
int start = (CommonConstants.AUTH_BEARER + " ").length();
if (header.length() > start) {
token = header.substring(start - 1);
}
} else {
// The token may be set as an HTTP parameter in case the client could not set it as an HTTP header
token = request.getParameter(TOKEN_URL_PARAM_NAME);
}
return token;
}
private String getEncodedPrivateKey() {
String privateKey = applicationProperties.getAuthenticationTokenPrivateKey();
return Base64.getEncoder().encodeToString(privateKey.getBytes());
}
}
@Configuration
@EnableWebSecurity
@ComponentScan(nameGenerator = PackageBeanNameGenerator.class, basePackages = { "com.thalasoft.user.rest.security", "com.thalasoft.user.rest.filter" })
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private AuthenticationFromTokenFilter authenticationFromTokenFilter;
@Autowired
private SimpleCORSFilter simpleCORSFilter;
@Autowired
private RESTAuthenticationEntryPoint restAuthenticationEntryPoint;
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.authenticationProvider(new CustomAuthenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().addFilterBefore(simpleCORSFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(authenticationFromTokenFilter, UsernamePasswordAuthenticationFilter.class)
.headers().cacheControl().disable().frameOptions().disable()
.and()
.userDetailsService(userDetailsService).authorizeRequests()
.antMatchers(RESTConstants.SLASH + UserDomainConstants.USERS + RESTConstants.SLASH + UserDomainConstants.LOGIN).permitAll()
.antMatchers(RESTConstants.SLASH + RESTConstants.ERROR).permitAll()
.antMatchers("/**").hasRole(UserDomainConstants.ROLE_ADMIN).anyRequest().authenticated();
}
}
I also tried to have the filter after as in:
http.addFilterAfter(authenticationFromTokenFilter, UsernamePasswordAuthenticationFilter.class);
instead of addFilterBefore but it didn't change anything to the issue.
I also tried to have the filter after as in:
http.addFilterAfter(authenticationFromTokenFilter, UsernamePasswordAuthenticationFilter.class);
instead of addFilterBefore but it didn't change anything to the issue.
So, is there anything wrong with my usage of the configure method for setting up the authenticationManagerBuilder.authenticationProvider(customAuthenticationProvider); ?
Instead of the above configuration, I tried the following configuration:
@Autowired
public void initialize(AuthenticationManagerBuilder authenticationManagerBuilder) {
authenticationManagerBuilder.authenticationProvider(customAuthenticationProvider);
}
But it still didn't exercise the custom authentication provider upon a request.
So, is there anything wrong with my usage of the configure method for setting up the authenticationManagerBuilder.authenticationProvider(customAuthenticationProvider); ?
So, is there anything wrong with my usage of the configure method for setting up the authenticationManagerBuilder.authenticationProvider(customAuthenticationProvider); ?
Instead of the above configuration, I tried the following configuration:
@Autowired
public void initialize(AuthenticationManagerBuilder authenticationManagerBuilder) {
authenticationManagerBuilder.authenticationProvider(customAuthenticationProvider);
}
But it still didn't exercise the custom authentication provider upon a request.