2015-12-21 16 views
7

Güvenlik konusunda yeniyim ve kullanıcı hesabının yalnızca uygulamanın yeniden başlatılmasını engelleyecek şekilde kilitlenmesine neden olan bir sorunla karşılaştım.Spring Security, eşzamanlı oturum açma girişimleriyle kullanıcıyı kilitler

Yaylı güvenlik (4.0.2.RELEASE) uygulamasıyla bir ilkbahar önyükleme (1.3.0.BUILD-SNAPSHOT) uygulamam var; bu eşzamanlı oturum stratejisini denetlemeye çalışıyorum, böylece bir kullanıcı yalnızca tek bir giriş yapabilir. Başka bir tarayıcıdan gelen giriş denemelerini doğru şekilde algılar ve bunu engeller. Ancak, izleyemediğim bazı garip davranışları farkettim:

  • A Kullanıcı, aynı tarayıcıda kimliği doğrulanmış iki sekme içerebilir. Üç sekme ile giriş yapamıyorum, ancak iki eser. Birinden çıkış yapmak her ikisinden de çıktı. Ben çerez değerleri aynıdır bkz, bu yüzden onlar bir oturum paylaştığı tahmin ediyorum:

sekmesi 1 jsessionid: DA7C3EF29D55297183AF5A9BEBEF191F & 941135CEBFA92C3912ADDC1DE41CFE9A

sekmesi 2 jsessionid: DA7C3EF29D55297183AF5A9BEBEF191F & 48C17A19B2560EAB8EC3FDF51B179AAE

İkinci giriş denemesi Spring-Güvenlik kaynağı aracılığıyla adım doğruladığı bir ikinci oturum açma girişimini (işaret gibi görünüyor şu günlük iletilerini sunar:

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.springframework.security.web.authentication.WebAuthenticationDe[email protected]: 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 
  • Sonra İki sekme ile giriş yaptığınızda Oturum kapatma, kullanıcı hesabı kilitlenir ve bir sunucu yeniden başlatılmasını gerektirir. Konsolda hata yok ve db'deki kullanıcı kayıtları değişmiyor.

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

    Ben de kontrol kullanıcıyı işlemek için aşağıdaki yöntemleri vardır:

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

    Böyle kilitlenmesini hesap önlemek nasıl veya Buraya

benim güvenlik yapılandırma olduğunu en azından program aracılığıyla bunları nasıl açabilirim?

Düzenleme 1/5/16 benim WebSecurityConfig için aşağıdaki eklendi:

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

ve kaldırılan:

servletContext.addListener(httpSessionEventPublisher()) 

Ama iki kez üzerinde oturum açtığınızda hala davranışı görürsünüz aynı tarayıcı - çıkış oturumu yeniden başlatana kadar hesabı kilitler.

+0

: Ben vardı

birkaç değişiklik yapmak için? tüm web tarayıcılarında oluyor mu? – JOW

+1

Bunu OS X Safari/Firefox/Chrome, Win IE ve Linux Firefox – sonoerin

+0

ile farkettim çünkü bu, Spring'e özgü bir kod sorunudur, bunun StackOverflow – schroeder

cevap

3

SessionRegistryImpl'in kullanıcıyı oturumdan kaldırmadığı ortaya çıkıyor. İlk sekme oturumu aslında hiçbir zaman sunucuyu çağırmadı, bu yüzden ikinci çağrı, bir oturum yöneticisini kaldırarak, müdürlere bırakıyor.ne Web tarayıcısı

@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; 
    } 
} 
İlgili konular