2015-12-21 237 views
7

私はセキュリティが初めてで、アプリケーションを再起動するだけでロックされるような方法でユーザアカウントをロックさせる問題にぶつかってきました。Spring Securityは同時ログイン試行でユーザをロックアウト

春のセキュリティ(4.0.2.RELEASE)アプリを使用した春のブート(1.3.0.BUILD-SNAPSHOT)を使用して、同時セッション戦略を制御しようとしているため、ユーザーは1回のログインしかできません。これは、別のブラウザーからの後続のログイン試行を正しく検出し、それを防止します。しかし、私は追跡できないような奇妙な動きに気付きました。

  • ユーザーは同じブラウザで2つのタブを認証できます。 3つのタブでログインすることはできませんが、2つは動作します。ログアウトすると、ログアウトしたように見えます。私はクッキーの値が同じで見たので、私は、彼らがセッションを共有している推測しています:

タブ1つのJSESSIONID:DA7C3EF29D55297183AF5A9BEBEF191F & 941135CEBFA92C3912ADDC1DE41CFE9A

タブ2 JSESSIONID:DA7C3EF29D55297183AF5A9BEBEF191F & 48C17A19B2560EAB8EC3FDF51B179AAE

二ログインの試みは、私は春のセキュリティソースを通してステッピングによって検証2番目のログイン試行を(示すように思われる次のログメッセージを提示:

o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /loginPage; Attributes: [permitAll] 
o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframew[email protected]754041c8: Principal: User [[email protected], password=<somevalue> ]; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]43458: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 4708D404F64EE758662B2B308F36FFAC; Granted Authorities: Owner 
o.s.s.access.vote.AffirmativeBased  : Voter: org.sp[email protected]17527bbe, returned: 1 
o.s.s.w.a.i.FilterSecurityInterceptor : Authorization successful 
o.s.s.w.a.i.FilterSecurityInterceptor : RunAsManager did not change Authentication object 
o.s.security.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. 
o.s.s.w.a.ExceptionTranslationFilter  : Chain processed normally 
s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed 
  • 私は、2つのタブとしてログインするとログアウトすると、ユーザーアカウントはロックされ、サーバーを再起動する必要があります。コンソールにエラーはなく、dbのユーザーレコードは変更されません。

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

    私もチェックをユーザー処理するために、次の方法があります:

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

    私はそのようにロックアップからアカウントを防ぐにはどうすればよいのか、ここで

は私のセキュリティの設定でありますプログラムでロックを解除するにはどうすればいいですか?

編集1/5/16 私は私のWebSecurityConfigに以下を追加:

servletContext.addListener(httpSessionEventPublisher()) 

しかし、私は二回にログインしたとき、私はまだ行動を参照してください。

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

と削除同じブラウザ - ログアウトすると、再起動するまでアカウントがロックされます。

+0

を何のWebブラウザがありますか?それはすべてのWebブラウザで起こっていますか? – JOW

+1

これはOSX Safari/Firefox/Chrome、Win IE、Linux Firefox – sonoerin

+0

で気づいています。これはSpring固有のコードの問題であるため、これはStackOverflowの方が良いでしょう。 – schroeder

答えて

3

SessionRegistryImplがセッションからユーザーを削除していないことが判明しました。最初のタブのログアウトは実際にサーバーと呼ばれることはないので、2番目の呼び出しで1つのセッションIDが削除され、プリンシパルに残ります。

私はいくつかの変更をしなければならなかった:

@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; 
    } 
} 
関連する問題