Thomas
Thomas

Reputation: 41

Spring boot security cannot log in after invalid credentials

I have problem with validating user credentials. When I give correct credentials first time everything goes OK but giving invalid credentials first and then give correct ones I get invalid credentials error. I use Postman Basic Auth.

My config class:

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;

    @Autowired
    private CustomAuthenticationEntryPoint authenticationEntryPoint;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

           http.cors().and().csrf().disable().authorizeRequests()
                .antMatchers(HttpMethod.POST ,"/login").permitAll()
                .antMatchers("/admin").hasAuthority("ADMIN")
                .anyRequest().authenticated().and().exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.ALWAYS).and()
                .logout()
                .deleteCookies("remove")
                .invalidateHttpSession(true);

           http.rememberMe().disable();

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                auth.userDetailsService(this.userService)
                        .and().eraseCredentials(true);
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

And my controller class

 @PostMapping
        public ResponseEntity<?> loginButtonClicked(HttpServletRequest request) {
            HttpSession session = request.getSession();
            final String authorization = request.getHeader("Authorization");
            String[] authorizationData=null;
            if (authorization != null && authorization.startsWith("Basic")) {
                // Authorization: Basic base64credentials
                String base64Credentials = authorization.substring("Basic" .length()).trim();
                String credentials = new String(Base64.getDecoder().decode(base64Credentials),
                        Charset.forName("UTF-8"));
                // credentials = username:password
                authorizationData = credentials.split(":", 2);
                UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(authorizationData[0], authorizationData[1],Arrays.asList(new SimpleGrantedAuthority("USER")));
                User user = userService.findUserEntityByLogin(authorizationData[0]);
                if(user != null && user.getFromWhenAcceptLoginAttempts() != null && (user.getFromWhenAcceptLoginAttempts()).isBefore(LocalDateTime.now())){
                    // Authenticate the user
                    Authentication authentication = authenticationManager.authenticate(authRequest);
                    SecurityContext securityContext = SecurityContextHolder.getContext();
                    securityContext.setAuthentication(authentication);
    
                    // Create a new session and add the security context.
                    session = request.getSession();
    
                    session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
    
                    return new ResponseEntity<>(new LoginResponseObject(200,"ACCESS GRANTED. YOU HAVE BEEN AUTHENTICATED"), HttpStatus.OK);
                }else{
                    session.getId();
                    SecurityContextHolder.clearContext();
                    if(session != null) {
                        session.invalidate();
                    }
                    return new ResponseEntity<>(new ErrorObject(403,"TOO MANY LOGIN REQUESTS","YOU HAVE ENTERED TOO MANY WRONG CREDENTIALS. YOUR ACCOUNT HAS BEEN BLOCKED FOR 15 MINUTES.", "/login"), HttpStatus.FORBIDDEN);
                }
            }else{
                session.getId();
                SecurityContextHolder.clearContext();
                if(session != null) {
                    session.invalidate();
                }
                return new ResponseEntity<>(new ErrorObject(401,"INVALID DATA","YOU HAVE ENTERED WRONG USERNAME/PASSWORD CREDENTIALS", "/login"), HttpStatus.UNAUTHORIZED);
            }
    
        } 
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    
        @Bean
        public ObjectMapper objectMapper(){
            return new ObjectMapper();
        }
    
        @Bean
        public HttpSessionEventPublisher httpSessionEventPublisher() {
            return new HttpSessionEventPublisher();
        } 

Upvotes: 4

Views: 5274

Answers (2)

lsantamaria
lsantamaria

Reputation: 178

The problem is that the request is stored in cache due to your sessionCreationPolicy.

To avoid this problem, you could add .requestCache().requestCache(new NullRequestCache()) in your http security config to override the default request cache configuration, but be careful because this could create another side effect (it depends on your application).

In case you do not need the session, you can choose another session policy:

.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).

Another alternative is to relay in Spring's BasicAuthenticationFilter. This filter does all the authentication logic for you. To enable it, you only have to add .httpBasic()in your http security configuration.

You may want to add a custom logic on authentication success/failure. In that case, you only have to create a custom filter (CustomBasicAuthenticationFilter) that extends BasicAuthenticationFilter class and overrides the methods onSuccessfulAuthentication()and onUnsuccessfulAuthentication(). You will not need to add .httpBasic() but you will need to insert your custom filter in the correct place:

.addFilterAfter(new CustomBasicAuthenticationFilter(authenticationManager), LogoutFilter.class).

Any of that 3 solutions will avoid your problem.

Upvotes: 4

HsB
HsB

Reputation: 1

Try to write .deleteCookies("JSESSONID") in your SpringSecurityConfig class.

Upvotes: 0

Related Questions