Reputation: 41
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
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
Reputation: 1
Try to write .deleteCookies("JSESSONID")
in your SpringSecurityConfig
class.
Upvotes: 0