2014-10-22 14 views
5

Mamy aplikację Spring MVC (4.0.5) z Spring Security (3.2.4), która obejmuje ochronę CSRF, która działa dobrze. Teraz dodajemy rozszerzenie bezpieczeństwa SAML (spring-security-saml2-core 1.0.0), które powoduje problem z zabezpieczeniem CSRF.Spring Rozszerzenie SAML i Spring Security CSRF Protection Conflict

Metadane zostały skonfigurowane na SSOCircle i próby uzyskania dostępu http://localhost:8080/myapp kieruje do strony logowania na SSOCircle. Po uwierzytelnieniu przeglądarka przekierowuje do http://localhost:8080/myapp/saml/SSO i generuje błąd:

Status HTTP 403 - Nie znaleziono oczekiwanego tokenu CSRF. Czy Twoja sesja wygasła?

Jeśli wyłączymy ochronę CSRF, wszystko działa. Jak możemy zachować ochronę CSRF i nadal korzystać z rozszerzenia SAML?

Przed skonfigurowaniem rozszerzenia SAML skorzystaliśmy z formularza logowania i zadziałała ochrona CSRF, a my nie otrzymaliśmy błędu na stronie logowania JSP i nie było tokena.

kod przed 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"); 
} 

Kod z 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

Po ponownym włączeniu ochronę CSRF i ustawienie zalogowaniu do debugowania, oto logi że występuje po pomyślnym uwierzytelnieniu:

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 

Odpowiedz

8

Masz co najmniej dwie opcje.

Jedno jest wdrożenie niestandardowych RequestMatcher (org.springframework.security.web.util.RequestMatcher), który nie będzie pasował na wiosennym SAML URL i dostarczyć to do konfiguracji CSRF z:

http.csrf().requireCsrfProtectionMatcher(matcher); 

Drugi, łatwiej jest określić Wiosna SAML punktów końcowych w krótkim osobna konfiguracja http, która nie będzie miała włączonej ochrony csrf.

Konfiguracja XML zrobić to może być podobny do:

<!-- 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> 

Dla konfiguracji coś Java jak to powinno działać:

@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("/"); 
     } 
    } 
} 

Szczegóły dotyczące definiowania wielu konfiguracji HTTP w konfiguracji Java można znaleźć w numerze Spring Security manual.

4

Dla innych osób, które mogą napotkać ten problem, udało mi się rozwiązać ten problem, wymuszając kolejność filtrów.

wymieniłem to:

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

z tym:

FilterChainProxy samlFilter = samlFilter(); 

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

i teraz działa.

+1

Uratowałeś mój dzień! Dziękuję Ci. – Evgeni

Powiązane problemy