1

尝试将 SAML 2 与 Spring Security 集成到我的 web 应用程序时遇到问题。

我在用着:

  • spring-security-saml2-core 1.0.3.RELEASE

  • spring-security-web 3.2.3.RELEASE

  • 弹簧安全配置 3.2.3.RELEASE。

安全上下文.xml

            <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security"
            xsi:schemaLocation="
                    http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd
                    http://www.springframework.org/schema/security
                    http://www.springframework.org/schema/security/spring-security.xsd">

            <security:global-method-security pre-post-annotations="enabled"/>

            <security:http auto-config="true"  use-expressions="true">

                <security:access-denied-handler error-page="/error/403.jsf" />
                <security:form-login login-page="/" />
                <security:logout logout-url="/logout" invalidate-session="true" logout-success-url="/" delete-cookies="JSESSIONID"/>

                <security:session-management >
                    <security:concurrency-control max-sessions="1"  error-if-maximum-exceeded="true" expired-url="/logout"/>
                </security:session-management>

                <security:intercept-url pattern="/error/*" access="hasAnyRole('ROLE_A','ROLE_B','ROLE_C','ROLE_D','ROLE_E','ROLE_F','ROLE_G')" />

                <security:intercept-url pattern="/web/Home.xhtml" access="hasAnyRole('ROLE_A','ROLE_C','ROLE_D','ROLE_E','ROLE_F','ROLE_G')" />

                <security:intercept-url pattern="/web/comm/*" access="hasAnyRole('ROLE_A','ROLE_B','ROLE_C','ROLE_D','ROLE_E')" />                          

                <security:intercept-url pattern="/pack/*" access="hasAnyRole('ROLE_A','ROLE_C','ROLE_D','ROLE_E','ROLE_F','ROLE_G')" />                         

                <security:intercept-url pattern="/web/admin/*" access="hasAnyRole('ROLE_A')" />

                <security:session-management >
                    <security:concurrency-control expired-url="/already-logged-in.faces" max-sessions="1" error-if-maximum-exceeded="true" />
                </security:session-management>

            </security:http>

            <!--  SAML 2.0 -->
            <!-- Secured pages with SAML as entry point -->
            <security:http entry-point-ref="samlEntryPoint" use-expressions="false" pattern="/">
                <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>

            <!-- Filters for processing of SAML messages -->
            <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>

            <bean id="samlIDPDiscovery" class="org.springframework.security.saml.SAMLDiscovery">
                    <!-- Do not show the IdP selection page. Always use the default IdP. There's only one configured anyway. -->
                    <!--<property name="idpSelectionPath" value="/WEB-INF/security/idpSelection.jsp"/> -->
            </bean>

            <!-- Handler deciding where to redirect user after successful login -->
            <bean id="successRedirectHandler"
                  class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
                <property name="defaultTargetUrl" value="/"/>
            </bean>
            <!--
            Use the following for interpreting RelayState coming from unsolicited response as redirect URL:
            <bean id="successRedirectHandler" class="org.springframework.security.saml.SAMLRelayStateSuccessHandler">
               <property name="defaultTargetUrl" value="/" />
            </bean>
            -->

            <!-- Handler deciding where to redirect user after failed login -->
            <bean id="failureRedirectHandler"
                  class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
                <property name="useForward" value="true"/>
                <property name="defaultFailureUrl" value="/error/403.jsf"/>
            </bean>

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

            <security:authentication-manager alias="authenticationManager">
                <!-- Register authentication manager for SAML provider -->
                <security:authentication-provider ref="samlAuthenticationProvider"/>
                <!-- Register authentication manager for administration UI -->
                <security:authentication-provider>
                    <security:user-service id="adminInterfaceService">
                        <security:user name="admin" password="admin" authorities="ROLE_ADMIN"/>
                    </security:user-service>
                </security:authentication-provider>
            </security:authentication-manager>

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

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

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

            <!-- Filter automatically generates default SP metadata -->
            <bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
            <constructor-arg>
                <bean class="org.springframework.security.saml.metadata.MetadataGenerator">
                    <property name="entityId" value="replaceWithUniqueIdentifier"/>
                    <property name="extendedMetadata">
                        <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                            <property name="signMetadata" value="false"/>
                            <property name="idpDiscoveryEnabled" value="true"/>
                        </bean>
                    </property>
                </bean>
            </constructor-arg>
        </bean>

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

            <!-- Configure HTTP Client to accept certificates from the keystore for HTTPS verification -->
            <!--
            <bean class="org.springframework.security.saml.trust.httpclient.TLSProtocolConfigurer">
                <property name="sslHostnameVerification" value="default"/>
            </bean>
            -->

            <!-- IDP Metadata configuration - paths to metadata of IDPs in circle of trust is here -->
            <bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
                <constructor-arg>
                    <list>
                        <!-- Example of classpath metadata with Extended Metadata -->
                        <bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
                            <constructor-arg>
                                <bean class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
                                    <constructor-arg>
                                        <bean class="java.util.Timer"/>
                                    </constructor-arg>
                                    <constructor-arg>
                                        <bean class="org.opensaml.util.resource.ClasspathResource">
                                            <constructor-arg value="/metadata/metadata.xml"/>
                                        </bean>
                                    </constructor-arg>
                                    <property name="parserPool" ref="parserPool"/>
                                </bean>
                            </constructor-arg>
                            <constructor-arg>
                                <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                                </bean>
                            </constructor-arg>
                        </bean>
                        <!-- Example of HTTP metadata without Extended Metadata -->
                        <bean class="org.opensaml.saml2.metadata.provider.HTTPMetadataProvider">
                            <!-- URL containing the metadata -->
                            <constructor-arg>
                                <value type="java.lang.String">https://myIDP/saml/metadata</value>
                            </constructor-arg>
                            <!-- Timeout for metadata loading in ms -->
                            <constructor-arg>
                                <value type="int">15000</value>
                            </constructor-arg>
                            <property name="parserPool" ref="parserPool"/>
                        </bean>
                        <!-- Example of file system metadata without Extended Metadata -->
                        <!--
                        <bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
                            <constructor-arg>
                                <value type="java.io.File">/usr/local/metadata/idp.xml</value>
                            </constructor-arg>
                            <property name="parserPool" ref="parserPool"/>
                        </bean>
                        -->
                    </list>
                </constructor-arg>
            </bean>

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

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

            <!-- Processing filter for WebSSO profile messages -->
            <bean id="samlWebSSOProcessingFilter" class="org.springframework.security.saml.SAMLProcessingFilter">
                <property name="authenticationManager" ref="authenticationManager"/>
                <property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
                <property name="authenticationFailureHandler" ref="failureRedirectHandler"/>
            </bean>

            <!-- Processing filter for WebSSO Holder-of-Key profile -->
            <bean id="samlWebSSOHoKProcessingFilter" class="org.springframework.security.saml.SAMLWebSSOHoKProcessingFilter">
                <property name="authenticationManager" ref="authenticationManager"/>
                <property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
                <property name="authenticationFailureHandler" ref="failureRedirectHandler"/>
            </bean>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            <bean id="parserPool" class="org.opensaml.xml.parse.StaticBasicParserPool" init-method="initialize"/>

            <bean id="parserPoolHolder" class="org.springframework.security.saml.parser.ParserPoolHolder"/>

        </beans>

当我尝试运行服务器时,出现异常:

        Caused by: java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.filterChainProxy': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: A universal match pattern ('/**') is defined  before other patterns in the filter chain, causing them to be ignored. Please check the ordering in your <security:http> namespace or FilterChainProxy bean configuration
        at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:231)
        at org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:100)
        at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:82)
        ... 6 more
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.filterChainProxy': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: A universal match pattern ('/**') is defined  before other patterns in the filter chain, causing them to be ignored. Please check the ordering in your <security:http> namespace or FilterChainProxy bean configuration
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1512)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:633)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
        at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:410)
        at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
        at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
        at io.undertow.servlet.core.ApplicationListeners.contextInitialized(ApplicationListeners.java:187)
        at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:198)

提前谢谢,请给我建议。

4

1 回答 1

0

问题:

日志说得很清楚。

A universal match pattern ('/**') is defined  before other patterns in the filter chain, causing them to be ignored. Please check the ordering in your <security:http> namespace or FilterChainProxy bean configuration

在您的配置中,您定义了两个<security:http>命名空间。

  1. 没有任何图案<security:http auto-config="true" use-expressions="true">

  2. 带图案<security:http entry-point-ref="samlEntryPoint" use-expressions="false" pattern="/">

根据弹簧文件:

为 http 元素定义一个模式控制将通过它定义的过滤器列表过滤的请求。解释取决于配置的请求匹配器。如果没有定义模式,所有的请求都会被匹配,所以最具体的模式应该首先声明。

所以在你的情况下,第一个<security:http>是导致所有其他被忽略。

解决方案:

要么在每个<security:http>提及它应该处理的请求中指定模式属性,要么只定义一个<security:http>并在其中定义多个<security:intercept-url>

于 2018-02-16T02:33:05.700 回答