2015-03-06 9 views
6

Utilizzo di Spring Java Config puro Sto avendo problemi a ottenere Spring e CAS per eseguire Single Sign Out. Ho Single Sign On che funziona con la configurazione seguente. Io uso una semplice pagina JSP per fare un modulo POST all'URL https://nginx.shane.com/app/logout e includo il valore CSRF nei dati POST'd. Sembra che tutto funzioni senza errori, ma quando vado su una pagina protetta mi fa tornare indietro senza dover effettuare il login. Qualche idea?Single Sign-Out con Spring Security e CAS

@Configuration 
@EnableWebSecurity 
public class SecurityWebAppConfig extends WebSecurityConfigurerAdapter { 

@Bean 
protected ServiceProperties serviceProperties() { 
    ServiceProperties serviceProperties = new ServiceProperties(); 
    serviceProperties.setService("https://nginx.shane.com/app/j_spring_cas_security_check"); 
    serviceProperties.setSendRenew(false); 
    return serviceProperties; 
} 

@Bean 
public CasAuthenticationProvider casAuthenticationProvider() { 
    CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider(); 
    casAuthenticationProvider.setAuthenticationUserDetailsService(authenticationUserDetailsService()); 
    casAuthenticationProvider.setServiceProperties(serviceProperties()); 
    casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator()); 
    casAuthenticationProvider.setKey("an_id_for_this_auth_provider_only"); 
    return casAuthenticationProvider; 
} 

@Bean 
public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService() { 
    return new TestCasAuthenticationUserDetailsService(); 
} 

@Bean 
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() { 
    return new Cas20ServiceTicketValidator("https://nginx.shane.com/cas"); 
} 

@Bean 
public CasAuthenticationFilter casAuthenticationFilter() throws Exception { 
    CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter(); 
    casAuthenticationFilter.setAuthenticationManager(authenticationManager()); 
    return casAuthenticationFilter; 
} 

@Bean 
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() { 
    CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint(); 
    casAuthenticationEntryPoint.setLoginUrl("https://nginx.shane.com/cas/login"); 
    casAuthenticationEntryPoint.setServiceProperties(serviceProperties()); 

    return casAuthenticationEntryPoint; 
} 

@Bean 
public SingleSignOutFilter singleSignOutFilter() { 
    // This filter handles a Single Logout Request from the CAS Server 
    return new SingleSignOutFilter(); 
} 

@Bean 
public LogoutFilter requestLogoutFilter() { 
    // This filter redirects to the CAS Server to signal Single Logout should be performed 
    SecurityContextLogoutHandler handler = new SecurityContextLogoutHandler(); 
    handler.setClearAuthentication(true); 
    handler.setInvalidateHttpSession(true); 

    LogoutFilter logoutFilter = new LogoutFilter("https://nginx.shane.com/", handler); 
    return logoutFilter; 
} 

@Override 
protected void configure(HttpSecurity http) throws Exception { 
    http.addFilter(casAuthenticationFilter()); 
    http.addFilterBefore(requestLogoutFilter(), LogoutFilter.class); 
    http.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class); 

    http.exceptionHandling() 
     .authenticationEntryPoint(casAuthenticationEntryPoint()); 

    http.authorizeRequests() 
     .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')") 
     .antMatchers("/dba/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_DBA')"); 

    http.logout() 
     .addLogoutHandler(handler) 
     .deleteCookies("remove") 
     .invalidateHttpSession(true) 
     .logoutUrl("/logout") 
     .logoutSuccessUrl("/"); 
} 

@Override 
protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
    auth.authenticationProvider(casAuthenticationProvider()); 
} 

}

Ho anche aggiunto un WebListener per gestire la sessione evento distrutto:

@WebListener 
public class SecurityWebListener implements HttpSessionListener { 

private SingleSignOutHttpSessionListener listener = new SingleSignOutHttpSessionListener(); 

@Override 
public void sessionCreated(HttpSessionEvent se) { 
    listener.sessionCreated(se); 
} 

@Override 
public void sessionDestroyed(HttpSessionEvent se) { 
    listener.sessionDestroyed(se); 
} 
} 

Ecco l'output del registro

[org.springframework.security.web.FilterChainProxy] [/logout at position 6 of 14 in additional filter chain; firing Filter: 'LogoutFilter'] [] 
[org.springframework.security.web.util.matcher.AntPathRequestMatcher] [Checking match of request : '/logout'; against '/logout'] [] 
[org.springframework.security.web.authentication.logout.LogoutFilter] [Logging out user 'org.spr[email protected]836ad34b: Principal: [email protected]: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]fffdaa08: RemoteIpAddress: 127.0.0.1; SessionId: FA880C15EF09C033E1CA0C8E4785905F; Granted Authorities: ROLE_ADMIN Assertion: [email protected] Credentials (Service/Proxy Ticket): ST-23-1UandqRxBcG6HCTx0Pdd-cas01.example.org' and transferring to logout destination] [] 
[org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler] [Invalidating session: FA880C15EF09C033E1CA0C8E4785905F] [] 
[org.jasig.cas.client.session.HashMapBackedSessionMappingStorage] [Attempting to remove Session=[FA880C15EF09C033E1CA0C8E4785905F]] [] 
[org.jasig.cas.client.session.HashMapBackedSessionMappingStorage] [Found mapping for session. Session Removed.] [] 
[org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler] [Using default Url: /] [] 
[org.springframework.security.web.DefaultRedirectStrategy] [Redirecting to '/app/'] [] 

risposta

3

(s) fortuna ho avuto problema simile ;) Si verifica quando CAS tenta di chiamare l'applicazione per disconnettersi. Da un lato CAS tenta di passare sessionId per eseguire il logout, d'altra parte SpringSecurity si aspetta di ottenere il token CSRF, che non è stato inviato da CAS poiché invia solo la richiesta GET. CsrfFilter non trova il token csrf e interrompe la catena del filtro. L'utente non è a conoscenza di ciò poiché CAS chiama implicitamente la richiesta di disconnessione. La richiesta passa direttamente dal server CAS al server delle applicazioni, non reindirizzando l'utente nel browser Web.

Per farlo funzionare è necessario configurare HttpSecurity di escludere/non includere LogoutFilter filterProcessesUrl (che è j_spring_security_logout nel tuo caso, come si utilizza quello di default).

Supponendo che si desidera controllare CSRF quando si cerca di creare nuovo admin, per insatnce, è necessario configurarlo come segue:

@Override 
protected void configure(HttpSecurity http) throws Exception { 
    http.addFilter(casAuthenticationFilter()); 
    http.addFilterBefore(requestLogoutFilter(), LogoutFilter.class); 
    http.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class); 

    http.exceptionHandling() 
     .authenticationEntryPoint(casAuthenticationEntryPoint()); 

    http.authorizeRequests() 
     .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')") 
     .antMatchers("/dba/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_DBA')"); 

    http.csrf() 
     .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/admin/create")); 

    http.logout() 
     .addLogoutHandler(handler) 
     .deleteCookies("remove") 
     .invalidateHttpSession(true) 
     .logoutUrl("/logout") 
     .logoutSuccessUrl("/"); 
} 

Proprio per indicare, ho aggiunto

http.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/admin/create")); .

Fare attenzione che non è possibile utilizzare la corrispondenza di tutti i modelli (/ admin/**) poiché si presume che si desideri chiamare anche alcune richieste di ricezione e il filtro CSRF si aspetta che inviino il token.

Tale problema non si presenterà con Spring Security precedente alla 3.2.x, dal momento che è stato introdotto il supporto CSRF (Cross Site Request Forgery).

Spero che questi aiuti :)

+0

grazie, che ha aiutato. –

Problemi correlati