Spring Security blocks user while logging in

I am new to security and have encountered a problem that forces me to lock my user account so that the fix for this fix is ​​fixed.

I have a spring boot (1.3.0.BUILD-SNAPSHOT) with a spring security application (4.0.2.RELEASE), which I am trying to control the parallel session strategy, so the user can only have one login. It correctly detects subsequent login attempts from another browser and prevents this. However, I noticed some strange behavior that I cannot track:

  • A user can have two authenticated tabs in one browser. I can not enter with three tabs, but two work. The way out of one of them seems to be coming out of both. I see that the cookie values ​​are the same, so I assume they share the session:

JSESSIONID tab 1: DA7C3EF29D55297183AF5A9BEBEF191F & 941135CEBFA92C3912ADDC1DE41CFE9A

tab 2 JSESSIONID: DA7C3EF29D55297183AF5A9BEBEF191F & 48C17A19B2560EAB8EC3FDF51B179AAE

The second logon attempt presents the following log messages, which seem to indicate a second logon attempt (which I checked by going through the Spring-Security source:

osswaiFilterSecurityInterceptor : Secure object: FilterInvocation: URL: /loginPage; Attributes: [permitAll] osswaiFilterSecurityInterceptor : Previously Authenticated: org.springframew ork.security.authentication.UsernamePasswordAuthenticationToken@ 754041c8: Principal: User [ username=xxx@xxx.xx , password=<somevalue> ]; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin gframework.security.web.authentication.WebAuthenticationDetails@ 43458: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 4708D404F64EE758662B2B308F36FFAC; Granted Authorities: Owner ossaccess.vote.AffirmativeBased : Voter: org.sp ringframework.security.web.access.expression.WebExpressionVoter@ 17527bbe, returned: 1 osswaiFilterSecurityInterceptor : Authorization successful osswaiFilterSecurityInterceptor : RunAsManager did not change Authentication object ossecurity.web.FilterChainProxy : /loginPage reached end of additional filter chain; proceeding with original chain org.apache.velocity : ResourceManager : unable to find resource 'loginPage.vm' in any resource loader. osswaExceptionTranslationFilter : Chain processed normally sswcSecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed 
  • When I log in with two tabs and then log out, the user account is locked and requires a server restart. There are no errors in the console, and user entries in db are not changed.

Here is my security config:

 @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomUserDetailsService customUserDetailsService; @Autowired private SessionRegistry sessionRegistry; @Autowired ServletContext servletContext; @Autowired private CustomLogoutHandler logoutHandler; @Autowired private MessageSource messageSource; /** * Sets security configurations for the authentication manager */ @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .userDetailsService(customUserDetailsService) .passwordEncoder(passwordEncoder()); return; } protected void configure(HttpSecurity http) throws Exception { http .formLogin() .loginPage("/loginPage") .permitAll() .loginProcessingUrl("/login") .defaultSuccessUrl("/?tab=success") .and() .logout().addLogoutHandler(logoutHandler).logoutRequestMatcher( new AntPathRequestMatcher("/logout")) .deleteCookies("JSESSIONID") .invalidateHttpSession(true).permitAll().and().csrf() .and() .sessionManagement().sessionAuthenticationStrategy( concurrentSessionControlAuthenticationStrategy).sessionFixation().changeSessionId().maximumSessions(1) .maxSessionsPreventsLogin( true).expiredUrl("/login?expired" ).sessionRegistry(sessionRegistry ) .and() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .invalidSessionUrl("/") .and().authorizeRequests().anyRequest().authenticated(); http.headers().contentTypeOptions(); http.headers().xssProtection(); http.headers().cacheControl(); http.headers().httpStrictTransportSecurity(); http.headers().frameOptions(); servletContext.getSessionCookieConfig().setHttpOnly(true); } @Bean public ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlAuthenticationStrategy() { ConcurrentSessionControlAuthenticationStrategy strategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry()); strategy.setExceptionIfMaximumExceeded(true); strategy.setMessageSource(messageSource); return strategy; } // Work around https://jira.spring.io/browse/SEC-2855 @Bean public SessionRegistry sessionRegistry() { SessionRegistry sessionRegistry = new SessionRegistryImpl(); return sessionRegistry; } } 

I also have the following validation processing methods:

 @Entity @Table(name = "USERS") @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "username") public class User implements UserDetails { ... @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((username == null) ? 0 : username.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; User other = (User) obj; if (username == null) { if (other.username != null) return false; } else if (!username.equals(other.username)) return false; return true; } } 

How to prevent account lockout, or at least how to unlock it programmatically?

Edit 1/5/16 I added the following to my WebSecurityConfig:

  @Bean public static ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() { return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher()); } 

and deleted:

 servletContext.addListener(httpSessionEventPublisher()) 

But I still see the behavior when I log in for the first time in one browser - logging out of the system blocks the account until the reboot.

+7
java spring spring-boot spring-security
source share
1 answer

It turns out that SessionRegistryImpl did not remove the user from the session. The first tab entry was never called a server, so the second call deletes one session, leaving one in the principals.

I had to make a few changes:

 @Component public class CustomLogoutHandler implements LogoutHandler { @Autowired private SessionRegistry sessionRegistry; @Override public void logout(HttpServletRequest httpServletRequest, httpServletResponse httpServletResponse, Authentication authentication) { ... httpServletRequest.getSession().invalidate(); httpServletResponse.setStatus(HttpServletResponse.SC_OK); //redirect to login httpServletResponse.sendRedirect("/"); List<SessionInformation> userSessions = sessionRegistry.getAllSessions(user, true); for (SessionInformation session: userSessions) { sessionRegistry.removeSessionInformation(session.getSessionId()); } } @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean public SessionRegistry sessionRegistry() { if (sessionRegistry == null) { sessionRegistry = new SessionRegistryImpl(); } return sessionRegistry; } @Bean public static ServletListenerRegistrationBean httpSessionEventPublisher() { return new ServletListenerRegistrationBean(new HttpSessionEventPublisher()); } @Bean public ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlAuthenticationStrategy() { ConcurrentSessionControlAuthenticationStrategy strategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry()); strategy.setExceptionIfMaximumExceeded(true); strategy.setMessageSource(messageSource); return strategy; } } 
+3
source share

All Articles