2013-06-14 5 views
7

Я пытаюсь выяснить проблему с Spring Security и SAML. Мы пытаемся использовать Spring Security (spring-security-core-3.1.1.RELEASE.jar) и SAML (spring-security-saml2-core-1.0.0-RC1-SNAPSHOT.jar), чтобы изменить наш продукт как SAML SP. EDIT: Вот (я думаю!) Соответствующий раздел моего связанного с безопасностью контекста xml. Как вы можете видеть, он почти идентичен this sample XML.Spring Security и вложенный файл FilterChainProxy 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> 

Симптом заключается в том, что сразу после аутентификации с IDP страница моего SP отображается правильно; однако изменение URL (например, нажатие любой ссылки) немедленно отправляет меня обратно в IDP. Я думаю, что я понял, почему, но я не знаю, почему это не всегда так.

Мое понимание Spring Security заключается в том, что проверка авторизации основана на SecurityContextHolder. А именно, поместите объект аутентификации на держатель, и все проверяет его. Тогда SecurityContextPersistenceFilter отвечает за поддержание соответствия репозитория сеанса.

Итак, как я проследить через код Spring Security, я вижу SecurityContextPersistenceFilter со следующим кодом:

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()); 
    .... 
} 

До сих пор, так хорошо. Затем я смотрю FilterChainProxy и нахожу:

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

Это все еще кажется ок. Поскольку FilterChainProxy следует вызывать только один раз, в основе всех фильтров Spring Security, это не проблема, чтобы очистить SecurityContextHolder в этот момент.

ОДНАКО, это не то, что происходит. То, что на самом деле происходит, - clearContext в FilterChainProxy, называется BEFORE. SecurityContextPersistenceFilter получает возможность считывать его из контекста в contextAfterChainExecution. Причина, по которой это происходит, заключается в том, что FilterChainProxy фактически встречается дважды в цепочке вызовов. Я знаю это, потому что я установил точку останова в FilterChainProxy.doFilter, и он вызывается дважды. В первый раз, когда он вызывается, у него есть еще один экземпляр FilterChainProxy в FilterChain. Вот стопка фильтров, возвращаемый методом getFilters FilterChainProxy в:

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

С этой цепочке фильтров, я не понимаю, как SecurityContextPersistenceFilter никогда не может работать: кажется, что SecurityContextHolder всегда будет очищен, прежде чем он получает шанс чтобы упорствовать.

Что-то здесь явно не так? Я что-то недопонимаю в Spring Security (очень возможно!)

ответ

4

Мне не удалось получить окончательную информацию об этом, но проблема связана с тем, что Spring Security 3.1.1 не играет хорошо с Spring SAML или даже с какой-либо реализацией который использует тот же тип вложенных FilterChainProxys. Похоже, что FilterChainProxy был полностью переписан для 3.1.1. Когда я посмотрел на последнюю версию (3.1.4), я заметил, что есть проверка в предложении finally, который очищает только SecurityContextHolder («SEC-1950»), если он является первым вызовом фильтра.

Таким образом, обновление весенней безопасности до 3.1.4 решило проблему.

+0

Благодарим за размещение решения. Я столкнулся с той же проблемой, что и ваше решение. –

+0

Рад слышать, что я не единственный, кто его видел. Спасибо за продолжение! – fool4jesus

+0

Я столкнулся с такой же проблемой, даже после обновления весенней версии безопасности до 3.1.4.RELEASE. – ManojP

Смежные вопросы