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!)
Grazie per aver pubblicato la soluzione. Stavo affrontando lo stesso problema che la tua soluzione ha funzionato anche per me. –
Felice di sentire che non sono l'unico a vederlo. Grazie per il seguito! – fool4jesus
Sto affrontando lo stesso problema anche dopo aver aggiornato la versione di sicurezza della molla a 3.1.4.RELEASE. – ManojP