2013-06-14 13 views
7

Sto cercando di capire un problema che riguarda Spring Security e SAML. Stiamo cercando di utilizzare Spring Security (spring-security-core-3.1.1.RELEASE.jar) e SAML (spring-security-saml2-core-1.0.0-RC1-SNAPSHOT.jar) per modificare il nostro prodotto in modo da essere un SAML SP. EDIT: Ecco la sezione pertinente (credo!) Del mio contesto xml relativo alla sicurezza. Come puoi vedere, è quasi identico allo this sample XML.Spring Security e nested FilterChainProxy scrivono Provider di servizi SAML

<!-- Entry point to initialize authentication, default values taken from properties file --> 
<bean id="samlEntryPoint" class="com.myproduct.samlsp.impl.PSSAMLEntryPoint"> 
    <property name="defaultProfileOptions"> 
     <bean class="org.springframework.security.saml.websso.WebSSOProfileOptions"> 
      <property name="includeScoping" value="false"/> 
     </bean> 
    </property> 
</bean> 

<!-- Unsecured pages --> 
<security:http security="none" pattern="/saml/web/**"/> 
<security:http security="none" pattern="/logout.jsp"/> 
<security:http security="none" pattern="/favicon.ico"/> 
<security:http security="none" pattern="/images/**"/> 
<security:http security="none" pattern="/scripts/**"/> 
<security:http security="none" pattern="/flash/**"/> 
<security:http security="none" pattern="/loggedout.html"/> 

<!-- Secured pages --> 
<security:http entry-point-ref="samlEntryPoint"> 
    <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/> 
    <security:custom-filter before="FIRST" ref="metadataGeneratorFilter"/> 
    <security:custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/> 
</security:http> 

<!-- IDP Discovery Service --> 
<bean id="samlIDPDiscovery" class="org.springframework.security.saml.SAMLDiscovery"> 
    <property name="idpSelectionPath" value="/WEB-INF/security/idpSelection.jsp"/> 
</bean> 

<bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy"> 
    <security:filter-chain-map request-matcher="ant"> 
     <security:filter-chain pattern="/saml/login/**" filters="samlEntryPoint"/> 
     <security:filter-chain pattern="/saml/logout/**" filters="samlLogoutFilter"/> 
     <security:filter-chain pattern="/saml/metadata/**" filters="metadataDisplayFilter"/> 
     <security:filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter"/> 
     <security:filter-chain pattern="/saml/SSOHoK/**" filters="samlWebSSOHoKProcessingFilter"/> 
     <security:filter-chain pattern="/saml/SingleLogout/**" filters="samlLogoutProcessingFilter"/> 
     <security:filter-chain pattern="/saml/discovery/**" filters="samlIDPDiscovery"/> 
    </security:filter-chain-map> 
</bean> 

Il sintomo è che, subito dopo l'autenticazione con l'IDP, la pagina del mio SP si presenta correttamente; tuttavia, cambiando l'URL (ad esempio facendo clic su un collegamento qualsiasi) mi viene immediatamente restituito all'IDP. Penso di aver capito perché, ma non so perché questo non è sempre il caso.

La mia conoscenza di Spring Security è che il controllo dell'autorizzazione è basato su SecurityContextHolder. Vale a dire, metti un oggetto Autenticazione sul supporto e tutto controlla l'autenticazione attorno ad esso. Quindi SecurityContextPersistenceFilter è responsabile della gestione del repository di sessione in modo che corrisponda.

Quindi, come ho traccio attraverso il codice Primavera di sicurezza, vedo SecurityContextPersistenceFilter con il seguente codice:

SecurityContext contextBeforeChainExecution = repo.loadContext(holder); 
try { 
    SecurityContextHolder.setContext(contextBeforeChainExecution); 
    chain.doFilter(holder.getRequest(), holder.getResponse()); 
} finally { 
    SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext(); 
    // Crucial removal of SecurityContextHolder contents - do this before anything else. 
    SecurityContextHolder.clearContext(); 
    repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse()); 
    .... 
} 

Fin qui, tutto bene. Quindi, guardo FilterChainProxy e trova:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
     throws IOException, ServletException { 
    try { 
     doFilterInternal(request, response, chain); 
    } finally { 
     // SEC-1950 
     SecurityContextHolder.clearContext(); <------- Key line here 
    } 
} 

Questo sembra ancora ok. Poiché FilterChainProxy deve essere invocato solo una volta, alla base di tutti i filtri Spring Security, non è un problema cancellare ClearContextHolder in quel punto.

TUTTAVIA, questo non è ciò che sta accadendo. Quello che sta realmente accadendo è che clearContext in FilterChainProxy è chiamato BEFORE SecurityContextPersistenceFilter ha la possibilità di leggerlo fuori dal contesto in contextAfterChainExecution. Il motivo per cui ciò accade è che FilterChainProxy si verifica effettivamente due volte nella catena di chiamate. Lo so perché ho impostato un breakpoint in FilterChainProxy.doFilter, ed è chiamato due volte. La prima volta che viene chiamato, ha un'altra istanza di FilterChainProxy nella sua FilterChain. Ecco la pila di filtri restituito dal metodo getFilters di FilterChainProxy:

org[email protected]78104d3c 
org.spring[email protected]168c795e 
FilterChainProxy[ Filter Chains: [ .... my patterns ] ], 
org.sp[email protected]7fffde92 
org.springframework.security.web.[email protected] 
org.springfram[email protected]1c2b968f 
o[email protected]395f222a 
org[email protected]372e6f09 
org.springfr[email protected]7dab91aa 

Con questa catena di filtri, non capisco come SecurityContextPersistenceFilter mai può funzionare: sembra che il SecurityContextHolder sarà sempre essere cancellata prima che arrivi una possibilità per persistere.

C'è qualcosa di ovvio in questo caso? Sto fraintendendo qualcosa in Spring Security (molto possibile!)

risposta

4

Non sono stato in grado di ottenere alcuna dichiarazione definitiva di questo, ma il problema sembra essere con Spring Security 3.1.1 che non sta giocando bene con Spring SAML o con qualsiasi implementazione che utilizza lo stesso tipo di FilterChainProxys nidificati. Sembra che FilterChainProxy sia stato completamente riscritto per 3.1.1. Quando ho guardato l'ultima versione (3.1.4), ho notato che c'è una verifica nella clausola finally che cancella solo SecurityContextHolder ("SEC-1950") SE è la prima chiamata del filtro.

Così, l'aggiornamento della sicurezza della molla a 3.1.4 ha risolto il problema.

+0

Grazie per aver pubblicato la soluzione. Stavo affrontando lo stesso problema che la tua soluzione ha funzionato anche per me. –

+0

Felice di sentire che non sono l'unico a vederlo. Grazie per il seguito! – fool4jesus

+0

Sto affrontando lo stesso problema anche dopo aver aggiornato la versione di sicurezza della molla a 3.1.4.RELEASE. – ManojP

Problemi correlati