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; @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; }
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.