2014-10-22 7 views
5

Abbiamo un'applicazione Spring MVC (4.0.5) con Spring Security (3.2.4) che include la protezione CSRF che funziona correttamente. Ora stiamo aggiungendo l'estensione di sicurezza SAML (spring-security-saml2-core 1.0.0) che causa un problema con la protezione CSRF.Spring SAML Extension e Spring Security Conflitto di protezione CSRF

I metadati sono stati configurati su SSOCircle e si sta tentando di accedere alle direttrici http://localhost:8080/myapp alla pagina di accesso in SSOCircle. Dopo l'autenticazione, il browser reindirizza a http://localhost:8080/myapp/saml/SSO e genera un errore:

Stato HTTP 403 - Token CSRF previsto non trovato. La tua sessione è scaduta?

Se disattiviamo la protezione CSRF, tutto funziona. Come possiamo mantenere la protezione CSRF e utilizzare ancora l'estensione SAML?

Prima di configurare l'estensione SAML, abbiamo utilizzato un modulo di accesso e la protezione CSRF funzionava e non abbiamo ricevuto un errore sul JSP di accesso e non aveva il token.

codice prima SAML:

@Override 
protected void configure(HttpSecurity httpSecurity) throws Exception { 
    httpSecurity.authorizeRequests() 
      .antMatchers("/login", "/login.request", "/logout").permitAll() 
      .anyRequest() 
       .hasAnyAuthority("MyRole") 
        .and().formLogin() 
      .loginPage("/login.request").loginProcessingUrl("/login") 
      .failureUrl("/login.request?error").permitAll().and().logout() 
      .logoutUrl("/logout").permitAll() 
      .logoutSuccessUrl("/login.request"); 
} 

Codice con SAML:

@Override 
protected void configure(HttpSecurity http) throws Exception { 
    //http.csrf().disable(); 

    http.httpBasic().authenticationEntryPoint(samlEntryPoint()); 

    http.addFilterBefore(metadataGeneratorFilter(), 
      ChannelProcessingFilter.class).addFilterAfter(samlFilter(), 
      BasicAuthenticationFilter.class); 

    http 
     .authorizeRequests() 
      .antMatchers("/error").permitAll() 
      .antMatchers("/saml/**").permitAll() 
      .anyRequest() 
       .hasAnyAuthority("MyRole") 
      .anyRequest().authenticated(); 

    http.logout().logoutSuccessUrl("/"); 
} 

UPDATE

Dopo riattivare la protezione CSRF e impostando la registrazione a DEBUG, qui i registri si verificano subito dopo l'autenticazione avvenuta con successo:

22.10.2014 16:54:17.374 [http-bio-8080-exec-8] DEBUG o.s.w.m.support.MultipartFilter - 
       Using MultipartResolver 'filterMultipartResolver' for MultipartFilter 

22.10.2014 16:54:17.377 [http-bio-8080-exec-8] DEBUG o.s.b.f.s.DefaultListableBeanFactory - 
       Returning cached instance of singleton bean 'filterMultipartResolver' 

22.10.2014 16:54:17.788 [http-bio-8080-exec-8] DEBUG o.s.w.m.support.MultipartFilter - 
       Request [/epass/saml/SSO] is not a multipart request 

22.10.2014 16:54:17.790 [http-bio-8080-exec-8] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - 
       Checking match of request : '/saml/sso'; against '/resources/**' 

22.10.2014 16:54:17.791 [http-bio-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - 
       /saml/SSO at position 1 of 14 in additional filter chain; firing Filter: 'MetadataGeneratorFilter' 

22.10.2014 16:54:17.793 [http-bio-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - 
       /saml/SSO at position 2 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' 

22.10.2014 16:54:17.795 [http-bio-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - 
       /saml/SSO at position 3 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 

22.10.2014 16:54:17.797 [http-bio-8080-exec-8] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - 
       HttpSession returned null object for SPRING_SECURITY_CONTEXT 

22.10.2014 16:54:17.798 [http-bio-8080-exec-8] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - 
       No SecurityContext was available from the HttpSession: [email protected] A new one will be created. 

22.10.2014 16:54:17.800 [http-bio-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - 
       /saml/SSO at position 4 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter' 

22.10.2014 16:54:17.801 [http-bio-8080-exec-8] DEBUG o.s.s.w.h.writers.HstsHeaderWriter - 
       Not injecting HSTS header since it did not match the requestMatcher org.springframework.se[email protected]244a79ef 

22.10.2014 16:54:17.802 [http-bio-8080-exec-8] DEBUG o.s.security.web.FilterChainProxy - 
       /saml/SSO at position 5 of 14 in additional filter chain; firing Filter: 'CsrfFilter' 
22.10.2014 16:54:17.805 [http-bio-8080-exec-8] DEBUG o.s.security.web.csrf.CsrfFilter - 
       Invalid CSRF token found for `http://localhost:8080/myapp/saml/SSO` 

22.10.2014 16:54:17.807 [http-bio-8080-exec-8] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - 
       SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession. 

22.10.2014 16:54:17.808 [http-bio-8080-exec-8] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - 
       SecurityContextHolder now cleared, as request processing completed 

risposta

8

Hai almeno due opzioni.

Uno è quello di implementare una consuetudine RequestMatcher (org.springframework.security.web.util.RequestMatcher), che non corrispondono a primavera SAML URL e fornire questo per la configurazione CSRF con:

http.csrf().requireCsrfProtectionMatcher(matcher); 

L'altro, più facile è quello di definire gli endpoint primavera SAML in un configurazione http separata che non avrà la protezione csrf abilitata.

La configurazione XML per fare questo può essere simile a:

<!-- SAML processing endpoints --> 
<security:http pattern="/saml/**" entry-point-ref="samlEntryPoint"> 
    <security:custom-filter before="FIRST" ref="metadataGeneratorFilter"/> 
    <security:custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/> 
</security:http> 

<!-- Secured pages with SAML as entry point --> 
<security:http entry-point-ref="samlEntryPoint"> 
    <security:csrf /> 
    <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/> 
    <security:custom-filter before="FIRST" ref="metadataGeneratorFilter"/> 
</security:http> 

Per Java configurazione qualcosa come questo dovrebbe funzionare:

@Configuration 
@EnableWebSecurity 
public class MutlipleHttpConfigurationConfig { 

    @Configuration 
    @Order(1) 
    public static class SAMLWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 
     protected void configure(HttpSecurity http) throws Exception { 
      http.antMatcher("/saml/**"); 
      http.csrf().disable(); 
      http.httpBasic().authenticationEntryPoint(samlEntryPoint()); 
      http.addFilterBefore(metadataGeneratorFilter(), 
        ChannelProcessingFilter.class).addFilterAfter(samlFilter(), 
        BasicAuthenticationFilter.class); 
     } 
    } 

    @Configuration 
    public static class BasicWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 
     protected void configure(HttpSecurity http) throws Exception { 
      http.httpBasic().authenticationEntryPoint(samlEntryPoint()); 
      http.addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class); 
      http 
        .authorizeRequests() 
        .antMatchers("/error").permitAll() 
        .anyRequest() 
        .hasAnyAuthority("MyRole") 
        .anyRequest().authenticated(); 

      http.logout().logoutSuccessUrl("/"); 
     } 
    } 
} 

dettagli sulla definizione di configurazione http multipla con configurazione Java può essere trovato nello Spring Security manual.

4

Per gli altri che potrebbero affrontare questo problema, sono stato anche in grado di risolverlo forzando l'ordine dei filtri.

ho sostituito questo:

http.addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class) 
    .addFilterAfter(samlFilter(), BasicAuthenticationFilter.class); 

con questo:

FilterChainProxy samlFilter = samlFilter(); 

http.addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class) 
    .addFilterAfter(samlFilter, BasicAuthenticationFilter.class) 
    .addFilterBefore(samlFilter, CsrfFilter.class); 

e funziona ora.

+1

Mi hai salvato la giornata! Grazie. – Evgeni