如何使用 Spring Security SAML 配置远程发现?
Posted
技术标签:
【中文标题】如何使用 Spring Security SAML 配置远程发现?【英文标题】:How to configure the remote discovery with Spring Security SAML? 【发布时间】:2016-02-17 21:44:47 【问题描述】:我正在尝试配置 Spring Security SAML 1.0.1 以访问位于 https://discovery.renater.fr/test 的远程发现服务。而是到达“CachingMetadataManager”的属性defaultIDP
中指定的IDP。
在Spring Security SAML 1.0.1 documentation,我们可以阅读:
远程发现服务
为了启用外部 IDP 发现服务,请将本地 SP 扩展元数据中的属性
idpDiscoveryURL
配置为外部发现 URL。确保属性idpDiscoveryEnabled
设置为true
。远程发现服务需要支持身份提供者发现服务协议和配置文件。
这是我生成 SP 元数据的方式:
<!-- Filter automatically generates default SP metadata -->
<b:bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
<b:constructor-arg>
<b:bean class="org.springframework.security.saml.metadata.MetadataGenerator">
<b:property name="includeDiscoveryExtension" value="true"/>
<b:property name="extendedMetadata">
<b:bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<b:property name="idpDiscoveryEnabled" value="true"/>
<b:property name="idpDiscoveryURL" value="https://discovery.renater.fr/test"/>
<b:property name="idpDiscoveryResponseURL" value="http://acem.u-bretagneloire.fr/ACEM/saml/login/alias/defaultAlias?disco=true"/>
</b:bean>
</b:property>
</b:bean>
</b:constructor-arg>
</b:bean>
可以看出,我在 bean MetadataGenerator
中将属性 includeDiscoveryExtension
设置为 true
。我还在 bean ExtendedMetadata
中设置了属性 idpDiscoveryEnabled
、idpDiscoveryURL
和 idpDiscoveryResponseURL
。但是当我将应用程序的日志级别设置为“TRACE”时,idpDiscoveryURL
值永远不会显示。
问题:我的配置中缺少什么来访问发现 URL?
完整的 Spring SAML 配置文件是:
<?xml version="1.0" encoding="UTF-8" ?>
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns="http://www.springframework.org/schema/security"
xmlns:p="http://www.springframework.org/schema/p"
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.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Enable auto-wiring -->
<context:annotation-config/>
<!-- Scan for auto-wiring classes in spring saml packages -->
<context:component-scan base-package="org.springframework.security.saml"/>
<!--
<http security="none" pattern="/favicon.ico"/>
<http security="none" pattern="/images/**"/>
<http security="none" pattern="/css/**"/>
<http security="none" pattern="/logout.jsp"/>
-->
<!-- Security for the administration UI -->
<http pattern="/saml/web/**" use-expressions="false">
<access-denied-handler error-page="/saml/web/metadata/login"/>
<form-login login-processing-url="/saml/web/login" login-page="/saml/web/metadata/login" default-target-url="/saml/web/metadata"/>
<intercept-url pattern="/saml/web/metadata/login" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/saml/web/**" access="ROLE_ADMIN"/>
<custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
</http>
<!-- Secured pages with SAML as entry point -->
<!--
<http entry-point-ref="samlEntryPoint" use-expressions="false">
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
<custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
<custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/>
</http>
-->
<http entry-point-ref="samlEntryPoint" use-expressions="true" auto-config="true">
<!-- For Spring Security 4.x, we need to disable csrf, otherwise AJAX requests get 403:-->
<csrf disabled="true"/>
<intercept-url access="permitAll" pattern="/" /><!-- To permit "/" allows the use of web.xml's <welcome-file> -->
<intercept-url access="permitAll" pattern="/home" />
<intercept-url access="permitAll" pattern="/pages/exceptions/**" />
<intercept-url access="permitAll" pattern="/javax.faces.resource/**" />
<intercept-url access="permitAll" pattern="/resources/**" />
<intercept-url access="hasRole('ROLE_ADMIN')" pattern="/administration/**" />
<intercept-url access="hasRole('ROLE_ADMIN')" pattern="/rest/**" />
<intercept-url access="isAuthenticated()" pattern="/**"/><!-- When the user is authentificated by the IDP, but doesn't exist in the application database -->
<form-login login-page="/login-page-should-not-be-generated-when-using-saml" />
<logout logout-url="/logout" logout-success-url="/home"/>
<custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
<custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/>
</http>
<!-- Filters for processing of SAML messages -->
<b: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>
</b:bean>
<!-- Handler deciding where to redirect user after successful login -->
<b:bean id="successRedirectHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<b:property name="defaultTargetUrl" value="/"/>
<b:property name="alwaysUseDefaultTargetUrl" value="true"/>
</b:bean>
<!--
Use the following for interpreting RelayState coming from unsolicited response as redirect URL:
<b:bean id="successRedirectHandler" class="org.springframework.security.saml.SAMLRelayStateSuccessHandler">
<b:property name="defaultTargetUrl" value="/" />
</b:bean>
-->
<!-- Handler deciding where to redirect user after failed login -->
<b:bean id="failureRedirectHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<b:property name="useForward" value="true"/>
<b:property name="defaultFailureUrl" value="/error.jsp"/>
</b:bean>
<!-- Handler for successful logout -->
<b:bean id="successLogoutHandler" class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
<b:property name="defaultTargetUrl" value="/logout.jsp"/>
</b:bean>
<authentication-manager alias="authenticationManager">
<!-- Register authentication manager for SAML provider -->
<authentication-provider ref="authProvider"/>
<!-- Register authentication manager for administration UI -->
<authentication-provider>
<user-service id="adminInterfaceService">
<user name="admin" password="admin" authorities="ROLE_ADMIN"/>
</user-service>
</authentication-provider>
</authentication-manager>
<!-- Logger for SAML messages and events -->
<b:bean id="samlLogger" class="org.springframework.security.saml.log.SAMLDefaultLogger"/>
<!-- Central storage of cryptographic keys -->
<b:bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
<b:constructor-arg value="classpath:security/samlKeystore.jks"/>
<b:constructor-arg type="java.lang.String" value="nalle123"/>
<b:constructor-arg>
<b:map>
<b:entry key="apollo" value="nalle123"/>
</b:map>
</b:constructor-arg>
<b:constructor-arg type="java.lang.String" value="apollo"/>
</b:bean>
<!-- Entry point to initialize authentication, default values taken from properties file -->
<b:bean id="samlEntryPoint" class="org.springframework.security.saml.SAMLEntryPoint">
<b:property name="defaultProfileOptions">
<b:bean class="org.springframework.security.saml.websso.WebSSOProfileOptions">
<b:property name="includeScoping" value="false"/>
</b:bean>
</b:property>
</b:bean>
<!-- IDP Discovery Service -->
<b:bean id="samlIDPDiscovery" class="org.springframework.security.saml.SAMLDiscovery">
<b:property name="idpSelectionPath" value="/WEB-INF/security/idpSelection.jsp"/>
</b:bean>
<!-- Filter automatically generates default SP metadata -->
<b:bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
<b:constructor-arg>
<b:bean class="org.springframework.security.saml.metadata.MetadataGenerator">
<b:property name="includeDiscoveryExtension" value="true"/>
<b:property name="extendedMetadata">
<b:bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<b:property name="idpDiscoveryEnabled" value="true"/>
<b:property name="idpDiscoveryURL" value="https://discovery.renater.fr/test"/>
<b:property name="idpDiscoveryResponseURL" value="http://acem.u-bretagneloire.fr/ACEM/saml/login/alias/defaultAlias?disco=true"/>
</b:bean>
</b:property>
</b:bean>
</b:constructor-arg>
</b:bean>
<!-- The filter is waiting for connections on URL suffixed with filterSuffix and presents SP metadata there -->
<b:bean id="metadataDisplayFilter" class="org.springframework.security.saml.metadata.MetadataDisplayFilter"/>
<!-- Configure HTTP Client to accept certificates from the keystore for HTTPS verification -->
<!--
<b:bean class="org.springframework.security.saml.trust.httpclient.TLSProtocolConfigurer">
<b:property name="sslHostnameVerification" value="default"/>
</b:bean>
-->
<!-- IDP Metadata configuration - paths to metadata of IDPs in circle of
trust is here -->
<b:bean id="metadata"
class="org.springframework.security.saml.metadata.CachingMetadataManager">
<b:constructor-arg>
<b:list>
<b:bean
class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
<b:constructor-arg>
<b:bean
class="org.opensaml.saml2.metadata.provider.HTTPMetadataProvider">
<!-- URL containing the metadata -->
<b:constructor-arg>
<b:value type="java.lang.String">https://federation.renater.fr/test/renater-test-metadata.xml</b:value>
</b:constructor-arg>
<!-- Timeout for metadata loading in ms -->
<b:constructor-arg>
<b:value type="int">15000</b:value>
</b:constructor-arg>
<b:property name="parserPool" ref="parserPool" />
</b:bean>
</b:constructor-arg>
<b:constructor-arg>
<!-- Default extended metadata for entities not specified in the map -->
<b:bean
class="org.springframework.security.saml.metadata.ExtendedMetadata">
</b:bean>
</b:constructor-arg>
<b:constructor-arg>
<!-- Extended metadata for specific IDPs -->
<b:map>
<b:entry key="http://idp.ssocircle.com">
<b:bean
class="org.springframework.security.saml.metadata.ExtendedMetadata" />
</b:entry>
</b:map>
</b:constructor-arg>
</b:bean>
</b:list>
</b:constructor-arg>
<!-- OPTIONAL used when one of the metadata files contains information
about this service provider -->
<!-- <b:property name="hostedSPName" value=""/> -->
<!-- OPTIONAL property: can tell the system which IDP should be used for
authenticating user by default. -->
<b:property name="defaultIDP" value="https://ident-shib-test.univ-rennes1.fr/idp/shibboleth"/>
</b:bean>
<!--
NOTE: In a real application you should not use an in memory implementation. You will also want
to ensure to clean up expired tickets by calling ProxyGrantingTicketStorage.cleanup()
-->
<b:bean id="pgtStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl"/>
<!-- SAML Authentication Provider responsible for validating of received SAML messages -->
<b:bean id="authProvider" class="org.springframework.security.saml.SAMLAuthenticationProvider">
<!-- OPTIONAL property: can be used to store/load user data after login -->
<b:property name="userDetails">
<b:bean class="eu.ueb.acem.services.auth.SamlAuthenticationUserDetailsService"/>
</b:property>
</b:bean>
<!-- Provider of default SAML Context -->
<b:bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl"/>
<!-- Processing filter for WebSSO profile messages -->
<b:bean id="samlWebSSOProcessingFilter" class="org.springframework.security.saml.SAMLProcessingFilter">
<b:property name="authenticationManager" ref="authenticationManager"/>
<b:property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
<b:property name="authenticationFailureHandler" ref="failureRedirectHandler"/>
</b:bean>
<!-- Processing filter for WebSSO Holder-of-Key profile -->
<b:bean id="samlWebSSOHoKProcessingFilter" class="org.springframework.security.saml.SAMLWebSSOHoKProcessingFilter">
<b:property name="authenticationManager" ref="authenticationManager"/>
<b:property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
<b:property name="authenticationFailureHandler" ref="failureRedirectHandler"/>
</b:bean>
<!-- Logout handler terminating local session -->
<b:bean id="logoutHandler"
class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
<b:property name="invalidateHttpSession" value="false"/>
</b:bean>
<!-- Override default logout processing filter with the one processing SAML messages -->
<b:bean id="samlLogoutFilter" class="org.springframework.security.saml.SAMLLogoutFilter">
<b:constructor-arg index="0" ref="successLogoutHandler"/>
<b:constructor-arg index="1" ref="logoutHandler"/>
<b:constructor-arg index="2" ref="logoutHandler"/>
</b:bean>
<!-- Filter processing incoming logout messages -->
<!-- First argument determines URL user will be redirected to after successful global logout -->
<b:bean id="samlLogoutProcessingFilter" class="org.springframework.security.saml.SAMLLogoutProcessingFilter">
<b:constructor-arg index="0" ref="successLogoutHandler"/>
<b:constructor-arg index="1" ref="logoutHandler"/>
</b:bean>
<!-- Class loading incoming SAML messages from httpRequest stream -->
<b:bean id="processor" class="org.springframework.security.saml.processor.SAMLProcessorImpl">
<b:constructor-arg>
<b:list>
<b:ref bean="redirectBinding"/>
<b:ref bean="postBinding"/>
<b:ref bean="artifactBinding"/>
<b:ref bean="soapBinding"/>
<b:ref bean="paosBinding"/>
</b:list>
</b:constructor-arg>
</b:bean>
<!-- SAML 2.0 WebSSO Assertion Consumer -->
<b:bean id="webSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerImpl"/>
<!-- SAML 2.0 Holder-of-Key WebSSO Assertion Consumer -->
<b:bean id="hokWebSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>
<!-- SAML 2.0 Web SSO profile -->
<b:bean id="webSSOprofile" class="org.springframework.security.saml.websso.WebSSOProfileImpl"/>
<!-- SAML 2.0 Holder-of-Key Web SSO profile -->
<b:bean id="hokWebSSOProfile" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>
<!-- SAML 2.0 ECP profile -->
<b:bean id="ecpprofile" class="org.springframework.security.saml.websso.WebSSOProfileECPImpl"/>
<!-- SAML 2.0 Logout Profile -->
<b:bean id="logoutprofile" class="org.springframework.security.saml.websso.SingleLogoutProfileImpl"/>
<!-- Bindings, encoders and decoders used for creating and parsing messages -->
<b:bean id="postBinding" class="org.springframework.security.saml.processor.HTTPPostBinding">
<b:constructor-arg ref="parserPool"/>
<b:constructor-arg ref="velocityEngine"/>
</b:bean>
<b:bean id="redirectBinding" class="org.springframework.security.saml.processor.HTTPRedirectDeflateBinding">
<b:constructor-arg ref="parserPool"/>
</b:bean>
<b:bean id="artifactBinding" class="org.springframework.security.saml.processor.HTTPArtifactBinding">
<b:constructor-arg ref="parserPool"/>
<b:constructor-arg ref="velocityEngine"/>
<b:constructor-arg>
<b:bean class="org.springframework.security.saml.websso.ArtifactResolutionProfileImpl">
<b:constructor-arg>
<b:bean class="org.apache.commons.httpclient.HttpClient">
<b:constructor-arg>
<b:bean class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager"/>
</b:constructor-arg>
</b:bean>
</b:constructor-arg>
<b:property name="processor">
<b:bean class="org.springframework.security.saml.processor.SAMLProcessorImpl">
<b:constructor-arg ref="soapBinding"/>
</b:bean>
</b:property>
</b:bean>
</b:constructor-arg>
</b:bean>
<b:bean id="soapBinding" class="org.springframework.security.saml.processor.HTTPSOAP11Binding">
<b:constructor-arg ref="parserPool"/>
</b:bean>
<b:bean id="paosBinding" class="org.springframework.security.saml.processor.HTTPPAOS11Binding">
<b:constructor-arg ref="parserPool"/>
</b:bean>
<!-- Initialization of OpenSAML library-->
<b:bean class="org.springframework.security.saml.SAMLBootstrap"/>
<!-- Initialization of the velocity engine -->
<b:bean id="velocityEngine" class="org.springframework.security.saml.util.VelocityFactory" factory-method="getEngine"/>
<!-- XML parser pool needed for OpenSAML parsing -->
<b:bean id="parserPool" class="org.opensaml.xml.parse.StaticBasicParserPool" init-method="initialize">
<b:property name="builderFeatures">
<b:map>
<b:entry key="http://apache.org/xml/features/dom/defer-node-expansion" value="false"/>
</b:map>
</b:property>
</b:bean>
<b:bean id="parserPoolHolder" class="org.springframework.security.saml.parser.ParserPoolHolder"/>
【问题讨论】:
【参考方案1】:我终于找到了解决方案,可以访问 Discovery URL(返回错误,但会是another question)。
对我的问题的解释是属性:
<b:property name="idpDiscoveryEnabled" value="true"/>
<b:property name="idpDiscoveryURL" value="https://discovery.renater.fr/test"/>
必须在 IDP 元数据中设置(在注释为“地图中未指定实体的默认扩展元数据”的部分中),而不是像我所做的那样在 SP 元数据中设置。
我必须在Spring Security SAML's repository on GitHub 中搜索字符串“idpDiscoveryEnabled”以找出我做错了什么。
我会建议 Vladimír Schäfer 在 Spring Security SAML 的文档中添加更多关于此的信息。因为在 SP 和 IDP 配置中都使用了元数据,所以很容易混合主题并且不会意识到我们在错误的 bean 中设置了属性。
更新:我意识到文档提供的信息可能有误:
远程发现服务
为了启用外部 IDP 发现服务,请将 本地 SP 扩展元数据 中的属性
idpDiscoveryURL
配置为 外部发现 URL。确保设置了属性idpDiscoveryEnabled
到true
。远程发现服务需要支持 Identity 提供者发现服务协议和配置文件。
根据我的经验,粗体部分可能是错误的。
【讨论】:
感谢您解决此 Grégoire 问题,我会看看。 @VladimírSchäfer :如果您有几分钟的时间,我将非常感谢您对此的帮助:***.com/q/33943499/1528942以上是关于如何使用 Spring Security SAML 配置远程发现?的主要内容,如果未能解决你的问题,请参考以下文章
如何配置 Spring Security SAML 以与 Okta 一起使用?
spring-security saml2:如何获取当前用户?
如何使用 Spring Security SAML 配置远程发现?
如何在同一应用程序中使用 spring-sample 示例配置 Spring Security 基本身份验证和 SAML 身份验证