Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot/Spring Security AuthenticationEntryPoint not getting executed

I have a created a class JwtAuthenticationFilter that includes this method:

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    Authentication authentication = null;

    if(hasJsonToken(request)) {
        JwtAuthenticationToken jwtAuthenticationToken = new JwtAuthenticationToken(getJsonToken(request)); 
        authentication = getAuthenticationManager().authenticate(jwtAuthenticationToken);           
    } else {
        throw new AuthenticationCredentialsNotFoundException(AUTHENTICATION_CREDENTIALS_NOT_FOUND_MSG);
    }

    return authentication;
}

If no JWT has been supplied an AuthenticationCredentialsNotFoundException is thrown. I would expect this to trigger the commence method in my AuthenticationEntryPoint - which looks like this:

@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException authException) throws IOException, ServletException {   
response.sendError(HttpStatus.UNAUTHORIZED.value(),HttpStatus.UNAUTHORIZED.getReasonPhrase());
}

The commence method is not being call. This in my spring security config (or part of it):

@Bean
public RestAuthenticationEntryPoint restAuthenticationEntryPoint() {
    return new RestAuthenticationEntryPoint();              
}

protected void configure(HttpSecurity http) throws Exception {
    http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
        .exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint()).and()
        .csrf().disable()
        .authorizeRequests().antMatchers(AUTHORISED_SERVICE_REQUESTS_ANT_MATCHER).authenticated()
        .anyRequest().permitAll();      
}

Not sure what I'done wrong here and I'm hoping someone point it out to me. Thanks

My SecurityConfig class extends WebSecurityConfigurerAdapter and is annotated with @Configuration and @EnableWebSecurity

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    ...
}

I am using spring boot.

So... eventually I got the behaviour I wanted by creating a custom AuthenticationFailureHandler and registering it in my Authentication F.ilter

jwtAuthenticationFilter.setAuthenticationFailureHandler(new JwtAuthenticationFailureHandler());

My question now is, is this the right thing to do and what is the difference between an AuthenticationEntryPoint and an AuthenticationFailureHandler?

like image 393
SME Avatar asked Sep 15 '16 13:09

SME


1 Answers

This is my code to implement AuthenticationEntryPoint and AccessDeniedHandler with Spring Boot / JWT. I hope it will be of help to anyone.

AuthenticationEntryPoint

@Component
public class AuthenticationEntryPointJwt implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException authenticationException) throws IOException {

        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        final Map<String, Object> body = new HashMap<>();
        body.put("code", HttpServletResponse.SC_UNAUTHORIZED);
        body.put("payload", "You need to login first in order to perform this action.");

        final ObjectMapper mapper = new ObjectMapper();
        mapper.writeValue(httpServletResponse.getOutputStream(), body);
    }
}

AccessDeniedHandler

@Component
public class AccessDeniedHandlerJwt implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {

        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
        httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);

        final Map<String, Object> body = new HashMap<>();
        body.put("code", HttpServletResponse.SC_FORBIDDEN);
        body.put("payload", "You don't have required role to perform this action.");

        final ObjectMapper mapper = new ObjectMapper();
        mapper.writeValue(httpServletResponse.getOutputStream(), body);
    }
}

WebSecurityConfigurerAdapter

    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private Environment env;
        @Autowired
        private SecurityUserDetailsService securityUserDetailsService;
        @Autowired
        private SecurityRequestFilter securityRequestFilter;
        @Autowired
        private AuthenticationEntryPointJwt authenticationEntryPointJwt;
        @Autowired
        private AccessDeniedHandlerJwt accessDeniedHandlerJwt;
    
        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(securityUserDetailsService).passwordEncoder(passwordEncoder());
        }
    
        @Bean
        public BCryptPasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    
        @Override
        protected void configure(HttpSecurity httpSecurity) throws Exception {
    
            if (Boolean.parseBoolean(env.getRequiredProperty("security.disable.csrf")))
                httpSecurity.csrf().disable();
    
            httpSecurity
                    .httpBasic().disable()
                    .formLogin().disable()
                    .authorizeRequests()
                    .antMatchers(env.getRequiredProperty("security.uri.white-list").split(",")).permitAll()
                    .anyRequest().authenticated().and()
                    .exceptionHandling().authenticationEntryPoint(authenticationEntryPointJwt).and()
                    .exceptionHandling().accessDeniedHandler(accessDeniedHandlerJwt).and()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
            httpSecurity.addFilterBefore(securityRequestFilter, UsernamePasswordAuthenticationFilter.class);
        }
    }

You can check the complete code on my GitHub

https://github.com/JonathanM2ndoza/Nginx-Docker-Spring-Boot/tree/master/security/src/main/java/com/jmendoza/wallet/security

like image 150
Jonathan Mendoza Avatar answered Sep 21 '22 18:09

Jonathan Mendoza