I'm using Spring Security SAML 1.0.1. I've set up the IDP metadata so it reaches a Discovery service which is defined by idpDiscoveryURL
. This parameter contains the URL http://wayf-shib.ueb.eu/fede-renater/WAYF
.
The remote Discovery is reached, but it complains that the request does not contain the "return" parameter. Indeed, this is the request that Spring SAML generates:
http://wayf-shib.ueb.eu/fede-renater/WAYF?entityID=http%3A%2F%2Facem.u-bretagneloire.fr%3A80%2FACEM%2Fsaml%2Fmetadata&returnIDParam=idp
The generated parameters are :
entityID
with the correct value;returnIDParam
with the value "idp" that is set automatically by Spring SAML.
Question : How I can configure Spring Security SAML so that it generates a return
parameter in the request?
If this can help, this is my current configuration:
<?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"/>
<!-- 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="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" />
<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>
<!-- 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="samlAuthenticationProvider"/>
<!-- 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="entityId" value="http://acem.u-bretagneloire.fr:80/ACEM"/>
<b:property name="entityBaseURL" value="http://acem.u-bretagneloire.fr:80/ACEM"/>
<!-- POSSIBLY IMPORTANT, OTHERWISE THE USER MIGHT BE REFERENCED BY THE NameID VALUE
(example: _246558c0d7c514447292d750df577b6b) AND NOT THE USERDETAILS "LOGIN" VALUE
Note : I haven't tested to remove this property and see if it still works. -->
<b:property name="nameID" value="PERSISTENT" />
<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="http://wayf-shib.ueb.eu/fede-renater/WAYF"/>
<b:property name="idpDiscoveryResponseURL" value="http://acem.u-bretagneloire.fr/ACEM/saml/login/alias/defaultAlias?disco=true&return=http%3A%2F%2acem.u-bretagneloire.fr/ACEM/"/>
</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:property name="idpDiscoveryEnabled" value="true"/>
<b:property name="idpDiscoveryURL" value="http://wayf-shib.ueb.eu/fede-renater/WAYF"/>
<b:property name="idpDiscoveryResponseURL" value="http://acem.u-bretagneloire.fr/ACEM/saml/login/alias/defaultAlias?disco=true&return=http%3A%2F%2acem.u-bretagneloire.fr/ACEM/"/>
</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="http://acem.u-bretagneloire.fr:80/ACEM/saml/metadata"/>
<!-- 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>
<!-- SAML Authentication Provider responsible for validating of received SAML messages -->
<b:bean id="samlAuthenticationProvider" 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>
<!-- VERY IMPORTANT, OTHERWISE THE USER WILL BE REFERENCED BY THE NameID VALUE
(example: _246558c0d7c514447292d750df577b6b) AND NOT THE USERDETAILS "LOGIN" VALUE -->
<b:property name="forcePrincipalAsString" value="false"/>
</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"/>