Spring SAML 在成功重定向到仪表板后出现无限循环

Spring SAML is having endless loop after successRedirect to dash board

我已经使用当前 spring 项目配置了 spring SAML,但是在重定向到仪表板页面后我得到了 ERR_TOO_MANY_REDIRECTS。我们有基于 User_Roles 的 dashBoard,如果我在拦截器中添加 permittAll() 它会重定向到 Dashboard 但如果添加 hasAnyRole() 那么它会导致 ERR_TOO_MANY_REDIRECTS 。 我在控制台中没有收到任何错误。除了 ERR_TOO_MANY_REDIRECTS 在浏览器中

我已经覆盖了 loadBySAMlUser() 方法并返回了 UserDetails,

请帮我解决无限循环的问题

我通过在 samlFilter 中添加 pre_auth_filter 解决了这个问题,并确保你禁用了 CSRF,下面是工作得很好的配置

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.2.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- SAML 1 Strats -->
    <!-- Enable auto-wiring -->
    <context:annotation-config />
    <context:component-scan base-package="org.springframework.security.saml" />
    <!-- SAML 1 Ends -->

    <!-- enable use-expressions -->
    <http auto-config="true" pattern="/index.jsp" security="none" disable-url-rewriting="true" />
     <http auto-config="true" use-expressions="true" authentication-manager-ref="authenticationManager">
      <intercept-url pattern="/saml**" access="isFullyAuthenticated()"/>
         <custom-filter ref="metadataGeneratorFilter" before="FIRST"/>
        <custom-filter ref="samlFilter" after="PRE_AUTH_FILTER"/>
        <intercept-url pattern="/admin**" access="hasRole('ROLE_SUPERADMIN')" />
        <intercept-url pattern="/dashboard1**" access="hasAnyAuthority('ROLE_SUPERADMIN_DEMO')" />
        <intercept-url pattern="/dashboard2/**" access="hasAnyAuthority('ROLE_ADMIN_DEMO_MANAGE_HI','ROLE_SUPERADMIN_DEMO','ROLE_SUPERADMIN')" />

        <!-- access denied page -->
        <access-denied-handler error-page="/unauthorized.do" />
        <form-login login-page="/login.do" authentication-success-handler-ref="customSuccessHandler" 
            authentication-failure-url="/login.do?error=Y" username-parameter="username" password-parameter="password" /> 
        <logout logout-success-url="/sessionOut.do" invalidate-session="false" delete-cookies="JSESSIONID" />
        <session-management invalid-session-url="/login.do?error=timeout">
            <concurrency-control max-sessions="1" error-if-maximum-exceeded="false" expired-url="/login.do?error=timeout" />
        </session-management>
        <!-- enable csrf protection-->
        <!-- <csrf/>  -->
    </http>  
    <!-- SAML 6 Strats -->
    <beans:bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy" >
        <filter-chain-map request-matcher="ant">
            <filter-chain pattern="/saml/login/**" filters="samlEntryPoint"  />
            <filter-chain pattern="/saml/logout/**" filters="samlLogoutFilter"/>
          <filter-chain pattern="/saml/metadata/**" filters="metadataDisplayFilter"/>
            <filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter"/>
            <filter-chain pattern="/saml/SSOHoK/**" filters="samlWebSSOHoKProcessingFilter"/>
            <filter-chain pattern="/saml/SingleLogout/**" filters="samlLogoutProcessingFilter"/>
           <filter-chain pattern="/saml/discovery/**" filters="samlIDPDiscovery"/>
        </filter-chain-map>
    </beans:bean>

    <!-- SAML 6 Ends -->

    <!-- SAML 3 Strats  (for time being commented ) -->
    <!-- Handler deciding where to redirect user after successful login -->
<!--    <beans:bean id="successRedirectHandler"
        class="com.demo.util.CustomSuccessHandler" >
    </beans:bean> -->

    <!-- Handler for successful logout -->
    <beans:bean id="successLogoutHandler"
        class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
        <beans:property name="defaultTargetUrl" value="/logout.jsp" />
    </beans:bean>

    <!-- Register authentication manager with SAML provider -->
<!--    <authentication-manager id="authenticationManager">
        <authentication-provider ref="samlAuthenticationProvider" />
    </authentication-manager> -->

    <!-- Logger for SAML messages and events -->
    <beans:bean id="samlLogger"
        class="org.springframework.security.saml.log.SAMLDefaultLogger"></beans:bean>

    <!-- Central storage of cryptographic keys -->
    <beans:bean id="keyManager"
        class="org.springframework.security.saml.key.JKSKeyManager">
        <beans:constructor-arg value="classpath:security/.keystore" />
        <beans:constructor-arg type="java.lang.String"
            value="123456" />
        <beans:constructor-arg>
            <beans:map>
                <beans:entry key="tomcat" value="123456" />
            </beans:map>
        </beans:constructor-arg>
        <beans:constructor-arg type="java.lang.String"
            value="tomcat" />
    </beans:bean>



    <!-- Entry point to initialize authentication, default values taken from 
        properties file (for time being commented)-->
    <beans:bean id="samlEntryPoint"
        class="org.springframework.security.saml.SAMLEntryPoint">
        <beans:property name="defaultProfileOptions">
            <beans:bean
                class="org.springframework.security.saml.websso.WebSSOProfileOptions">
                <beans:property name="includeScoping" value="false" />
            </beans:bean>
        </beans:property>
    </beans:bean> 


    <!-- IDP Discovery Service -->
    <beans:bean id="samlIDPDiscovery"
        class="org.springframework.security.saml.SAMLDiscovery">
        <beans:property name="idpSelectionPath"
            value="/WEB-INF/loginPage.jsp" />
    </beans:bean>
    <!-- SAML 3 Ends -->

    <!-- SAML 4 Strats -->
    <!-- Filter automatically generates default SP metadata -->

        <beans:bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
        <beans:constructor-arg>
            <beans:bean class="org.springframework.security.saml.metadata.MetadataGenerator">
              <beans:property name="entityId" value="https://localhost:8443/demo/saml/metadata"/>
              <beans:property name="entityBaseURL" value="https://localhost:8443/demo"/>
              <beans:property name="requestSigned" value="true"/>
            </beans:bean>
        </beans:constructor-arg>
    </beans:bean>



    <!-- The filter is waiting for connections on URL suffixed with filterSuffix 
        and presents SP metadata there -->
    <beans:bean id="metadataDisplayFilter"
        class="org.springframework.security.saml.metadata.MetadataDisplayFilter"></beans:bean>

    <!-- IDP Metadata configuration - paths to metadata of IDPs in circle of 
        trust is here -->
    <!-- Do no forget to call iniitalize method on providers -->


    <beans:bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
    <beans:constructor-arg>
        <beans:list>
<beans:bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
    <beans:constructor-arg>
        <beans:bean class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
            <beans:constructor-arg>
                <beans:bean class="java.util.Timer"/>
            </beans:constructor-arg>
            <beans:constructor-arg>
                <beans:bean class="org.opensaml.util.resource.ClasspathResource">
                    <beans:constructor-arg value="/security/FederationMetadata.xml"/>
                </beans:bean>
            </beans:constructor-arg>
            <beans:property name="parserPool" ref="parserPool"/>
        </beans:bean>
    </beans:constructor-arg>
    <beans:constructor-arg>
        <beans:bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
        <beans:property name="local" value="false" />
                    <beans:property name="signMetadata" value="true" />
                <!--    <beans:property name="idpDiscoveryEnabled" value="false" /> -->

         </beans:bean>
    </beans:constructor-arg>
    <beans:property name="metadataTrustCheck" value="false"/>
</beans:bean>
</beans:list>
</beans:constructor-arg>
</beans:bean>


    <!-- SAML Authentication Provider responsible for validating of received 
        SAML messages -->
    <beans:bean id="samlAuthenticationProvider"
        class="org.springframework.security.saml.SAMLAuthenticationProvider">
        <!-- OPTIONAL property: can be used to store/load user data after login -->
         <beans:property name="userDetails" ref="samlUserDetailService" /> 
         <beans:property name="forcePrincipalAsString" value="false" />
    </beans:bean>

    <beans:bean id="samlUserDetailService" class="com.demo.util.SamlUserDetailService"/>

    <!-- Provider of default SAML Context -->
    <beans:bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl"/>

    <!-- Processing filter for WebSSO profile messages -->
    <beans:bean id="samlWebSSOProcessingFilter"
        class="org.springframework.security.saml.SAMLProcessingFilter">
        <beans:property name="authenticationManager" ref="authenticationManager" />
        <beans:property name="authenticationSuccessHandler"
            ref="customSuccessHandler" />
    </beans:bean>
    <!-- SAML 4 Ends -->


    <!-- SAML 5 Ends -->
    <!-- Processing filter for WebSSO Holder-of-Key profile -->
    <beans:bean id="samlWebSSOHoKProcessingFilter"
        class="org.springframework.security.saml.SAMLWebSSOHoKProcessingFilter">
        <beans:property name="authenticationManager" ref="authenticationManager" />
        <beans:property name="authenticationSuccessHandler"
            ref="customSuccessHandler" />
    </beans:bean>

    <!-- Logout handler terminating local session -->
    <beans:bean id="logoutHandler"
        class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
        <beans:property name="invalidateHttpSession" value="false" />
    </beans:bean>

    <!-- Override default logout processing filter with the one processing SAML 
        messages -->
    <beans:bean id="samlLogoutFilter"
        class="org.springframework.security.saml.SAMLLogoutFilter">
         <beans:constructor-arg index="0" ref="successLogoutHandler"/>
        <beans:constructor-arg index="1" ref="logoutHandler"/>
        <beans:constructor-arg index="2" ref="logoutHandler"/>
    </beans:bean>

    <!-- Filter processing incoming logout messages -->
    <!-- First argument determines URL user will be redirected to after successful 
        global logout -->
    <beans:bean id="samlLogoutProcessingFilter"
        class="org.springframework.security.saml.SAMLLogoutProcessingFilter">
         <beans:constructor-arg index="0" ref="successLogoutHandler"/>
        <beans:constructor-arg index="1" ref="logoutHandler"/>
    </beans:bean>

    <!-- Class loading incoming SAML messages from httpRequest stream -->
    <beans:bean id="processor"
        class="org.springframework.security.saml.processor.SAMLProcessorImpl">
        <beans:constructor-arg>
            <beans:list>
                <beans:ref bean="redirectBinding" />
                <beans:ref bean="postBinding" />
                <beans:ref bean="artifactBinding" />
                <beans:ref bean="soapBinding" />
                <beans:ref bean="paosBinding" />
            </beans:list>
        </beans:constructor-arg>
    </beans:bean>

    <!-- SAML 2.0 WebSSO Assertion Consumer -->
    <beans:bean id="webSSOprofileConsumer"
        class="org.springframework.security.saml.websso.WebSSOProfileConsumerImpl"></beans:bean>

    <!-- SAML 2.0 Holder-of-Key WebSSO Assertion Consumer -->
    <beans:bean id="hokWebSSOprofileConsumer"
        class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"></beans:bean>

    <!-- SAML 2.0 Web SSO profile -->
    <beans:bean id="webSSOprofile"
        class="org.springframework.security.saml.websso.WebSSOProfileImpl"></beans:bean>

    <!-- SAML 2.0 Holder-of-Key Web SSO profile -->
    <beans:bean id="hokWebSSOProfile"
        class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"></beans:bean>

    <!-- SAML 2.0 ECP profile -->
    <beans:bean id="ecpprofile"
        class="org.springframework.security.saml.websso.WebSSOProfileECPImpl"></beans:bean>

    <!-- SAML 2.0 Logout Profile -->
    <beans:bean id="logoutprofile"
        class="org.springframework.security.saml.websso.SingleLogoutProfileImpl"></beans:bean>

   <beans:bean class="org.springframework.security.saml.trust.httpclient.TLSProtocolConfigurer">
    <beans:property name="keyManager" ref="keyManager" />
    <beans:property name="sslHostnameVerification" value="allowAll" />
</beans:bean>

    <!-- Bindings, encoders and decoders used for creating and parsing messages -->
    <beans:bean id="postBinding"
        class="org.springframework.security.saml.processor.HTTPPostBinding">
        <beans:constructor-arg ref="parserPool" />
        <beans:constructor-arg ref="velocityEngine" />
    </beans:bean>

    <beans:bean id="redirectBinding"
        class="org.springframework.security.saml.processor.HTTPRedirectDeflateBinding">
        <beans:constructor-arg ref="parserPool" />
    </beans:bean>

    <beans:bean id="artifactBinding"
        class="org.springframework.security.saml.processor.HTTPArtifactBinding">
        <beans:constructor-arg ref="parserPool" />
        <beans:constructor-arg ref="velocityEngine" />
        <beans:constructor-arg>
            <beans:bean
                class="org.springframework.security.saml.websso.ArtifactResolutionProfileImpl">
                <beans:constructor-arg>
                    <beans:bean class="org.apache.commons.httpclient.HttpClient" />
                </beans:constructor-arg>
                <beans:property name="processor">
                    <beans:bean id="soapProcessor"
                        class="org.springframework.security.saml.processor.SAMLProcessorImpl">
                        <beans:constructor-arg ref="soapBinding" />
                    </beans:bean>
                </beans:property>
            </beans:bean>
        </beans:constructor-arg>
    </beans:bean>

    <beans:bean id="soapBinding"
        class="org.springframework.security.saml.processor.HTTPSOAP11Binding">
        <beans:constructor-arg ref="parserPool" />
    </beans:bean>

    <beans:bean id="paosBinding"
        class="org.springframework.security.saml.processor.HTTPPAOS11Binding">
        <beans:constructor-arg ref="parserPool" />
    </beans:bean>

    <!-- Initialization of OpenSAML library -->
    <beans:bean class="org.springframework.security.saml.SAMLBootstrap"></beans:bean>

    <!-- Initialization of the velocity engine -->
    <beans:bean id="velocityEngine"
        class="org.springframework.security.saml.util.VelocityFactory"
        factory-method="getEngine"></beans:bean>

    <!-- XML parser pool needed for OpenSAML parsing -->
    <beans:bean id="parserPool"
        class="org.opensaml.xml.parse.StaticBasicParserPool" scope="singleton"
        init-method="initialize"></beans:bean>
    <beans:bean id="parserPoolHolder"
        class="org.springframework.security.saml.parser.ParserPoolHolder"
        scope="singleton"></beans:bean>

    <!-- SAML 5 Ends -->

    <beans:bean id="authenticationProvider"
        class="com.demo.util.LimitLoginAuthenticationProvider">
        <beans:property name="userDetailsService" ref="loginService" />
        <beans:property name="passwordEncoder" ref="passwordEncoder" />
    </beans:bean>
    <beans:bean
        class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"
        id="passwordEncoder" />
    <authentication-manager alias="authenticationManager">
        <authentication-provider ref="authenticationProvider"/>
        <authentication-provider ref="samlAuthenticationProvider" />
    </authentication-manager>
    <beans:bean id="customSuccessHandler" class="com.demo.util.CustomSuccessHandler" />
</beans:beans>