SAML Extension can be deployed in scenarios where multiple back-end servers process SAML requests forwarded by a reverse-proxy or a load balancer. SSL termination proxies which communicate using an unencrypted channel between the proxy and back-end servers are also supported. In order to configure SAML Extension for deployment behind a load balancer or a reverse-proxy please follow these steps:
Make sure that your reverse-proxy or load-balancer is configured to use sticky sessions. Information about e.g. sent requests is stored within a user's HTTP session and sending of response to another back-end node would make the original request data unavailable and fail the validation. Sticky session are not necessary in case only IDP-initialized SSO is used or when sessions are replicated to all nodes.
Provide information about front-end URL to the back-end servers by changing the contextProvider bean implementation in your securityContext.xml to class org.springframework.security.saml.context.SAMLContextProviderLB:
<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderLB"> <property name="scheme" value="https"/> <property name="serverName" value="www.myserver.com"/> <property name="serverPort" value="443"/> <property name="includeServerPortInRequestURL" value="false"/> <property name="contextPath" value="/spring-security-saml2-sample"/> </bean>
This setting enables the extension to correctly form all generated URLs and verify endpoints of the incoming SAML messages.
In case you use automatically generated metadata make sure to configure entityBaseURL matching the front-end URL in your metadataGeneratorFilter bean:
<bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter"> <constructor-arg> <bean class="org.springframework.security.saml.metadata.MetadataGenerator"> <property name="entityBaseURL" value="https://www.myserver.com/spring-security-saml2-sample"/> </bean> </constructor-arg> </bean>
Context provider populates information about the local service provider (your application) such as entityId, role, metadata, security keys, SSL credentials and trust engines for verification of signatures and SSL/TLS connections. Once populated context is made available to all components participating in processing of the incoming or outgoing SAML messages. ContextProvider can customized to alter behavior of the SAML Extension. The default implementation org.springframework.security.saml.context.SAMLContextProviderImpl relies on information available in the ExtendedMetadata and performs the following steps for creation of the context:
Locate entityId of the local SP by parsing part of the URL after /alias/ (e.g. myAlias in https://www.myserver.com/saml_extension/saml/sso/alias/myAlias?idp=myIdp) and matching it with property alias specified in the ExtendedMetadata. In case the URL doesn't contain any alias part the default service provider configured with property hostedSPName on the metadata bean is used.
Populate credential used to decrypt data sent to this service provider. In case ExtendedMetadata specifies property encryptionKey it will be used as an alias to lookup a private key from the keyManager bean. Otherwise defaultKey of the keyManager bean will be used.
Populate credential used for SSL/TLS client authentication. In case ExtendedMetadata specifies property tlsKey it will be used as an alias to lookup key from keyManager bean. Otherwise no credential will be provided for client authentication.
Populate trust engine for verification of signatures. Depending on securityProfile setting in the ExtendedMetadata trust engine based on either Section 8.2.1, “Metadata interoperability profile (MetaIOP)” or Section 8.2.2, “PKIX profile” is created.
Populate trust engine for verification of SSL/TLS connections. Depending on sslSecurityProfile setting in the ExtendedMetadata trust engine based on either Section 8.2.1, “Metadata interoperability profile (MetaIOP)” or Section 8.2.2, “PKIX profile” is created.
During initialization of SSO ContextProvider is also requested to provide metadata of the peer IDP. System performs these steps to locate peer IDP to use:
Load parameter idp of the HttpRequest object and try to locate peer IDP by the entityId. When there's no idp parameter provided system will either start IDP discovery process (when enabled in the ExtendedMetadata of the local SP) or use the default IDP specified in the metadata bean.
For security reasons system limits the time window enabling processing of SAML messages and assertions. The time window parameters can be customized with the following settings.
Validity of assertions processed during the signle sign-on process is limited to 3000 seconds. Value can be customized with property maxAssertionTime of the WebSSOProfileConsumerImpl bean.
System allows users to single sign-on for up to 7200 seconds since their initial authentication with the IDP (based on value AuthInstance of the Authentication statement). Some IDPs allow users to stay authenticated for longer periods than this and you might need to change the default value by setting maxAuthenticationAge of the WebSSOProfileConsumerImpl bean.
As clocks between IDP and SP machines may not be perfectly synchronized a tolerance of 60 seconds is applied for time comparisons. The tolerance value (time skew) can be customized by settings property responseSkew in beans WebSSOProfileConsumerImpl and SingleLogoutProfileImpl.
The following tables summarize all checks for time validity during processing of incoming SAML messages. Response skew refers to property responseSkew set on profile beans. Past indicates that validity window for checking of the value will be extended by responseSkew seconds to the past and correspondingly with the future value. Nullable values can be missing from the incoming messages.
Table 10.1. Time checks during processing of incoming SAML Response in WebSSO and WebSSO HoK profiles
response.issueInstant | |
Applied skew: | responseSkew (past + future) |
Nullable: | No |
Fails with: | Throws SAMLException |
Description: | Time when SAML response message was created. |
response.assertion.issueInstant | |
Applied skew: | responseSkew (past + future) + maxAssertionTime (future) |
Nullable: | No |
Fails with: | Throws SAMLException |
Description: | Time when SAML assertion was created, allows validity extension as assertion might be re-used by the caller. |
response.assertion.subject.subjectConfirmation.notOnOrAfter | |
Applied skew: | responseSkew (future) |
Nullable: | No |
Fails with: | Throws SAMLException |
Description: | Time when subject can no longer be confirmed. |
response.assertion.authnStatement.authnInstant | |
Applied skew: | responseSkew (past + future) + maxAuthenticationAge (future) |
Nullable: | No |
Fails with: | Throws CredentialsExpiredException |
Description: | Time when user authenticated to IDP, typically differs from time or response or assertion creation time. |
response.assertion.authnStatement.sessionNotOnOfAfter | |
Applied skew: | no skew |
Nullable: | Yes |
Fails with: | Throws CredentialsExpiredException |
Description: | Time when user's session expires and requires re-authentication, sessions are typically valid for longer period and therefore do not suffer from time synchronization problems. |
response.assertion.condition.notBefore | |
Applied skew: | responseSkew (past) |
Nullable: | Yes |
Fails with: | Throws SAMLException |
Description: | Time limit on validity of assertion. |
response.assertion.condition.notOnOrAfter | |
Applied skew: | responseSkew (future) |
Nullable: | Yes |
Fails with: | Throws SAMLException |
Description: | Time limit on validity of assertion. |
Table 10.2. Time checks during processing of incoming SAML LogoutRequest in Single Logout profile
response.issueInstant | |
Applied skew: | responseSkew (past + future) |
Nullable: | No |
Fails with: | Sends LogoutResponse with error Status "urn:oasis:names:tc:SAML:2.0:status:Requester" |
Description: | Time when SAML LogoutRequest message was created. |
Table 10.3. Time checks during processing of incoming SAML LogoutResponse in Single Logout profile
response.issueInstant | |
Applied skew: | responseSkew (past + future) |
Nullable: | No |
Fails with: | Throws SAMLException |
Description: | Time when SAML LogoutResponse message was created. |
Table 10.4. Time checks during processing of incoming SAML ArtifactResponse in Artifact Resolution profile
response.issueInstant | |
Applied skew: | responseSkew (past + future) |
Nullable: | No |
Fails with: | Throws MessageDecodingException |
Description: | Time when SAML LogoutResponse message was created. |
Support for enhanced client/proxy can be configured using property ecpEnabled of the service provider's extended metadata. Once enabled, ECP profile is automatically activated with requests containing HTTP headers Accept: application/vnd.paos+xml and PAOS: ver='urn:liberty:paos:2003-08'; 'urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp'. Binding used to server ECP profile is always automatically set to PAOS.
ECP can be enabled in combination with the automatic metadata generation using the following settings:
<bean class="org.springframework.security.saml.metadata.MetadataGenerator"> <property name="extendedMetadata"> <bean class="org.springframework.security.saml.metadata.ExtendedMetadata"> <property name="ecpEnabled" value="true"/> </bean> </property> </bean>
By default Spring SAML uses the following endpoints, which can optionally also contain information about entity alias of the local Service Provider:
Table 10.5. Endpoint overview
Profile | Binding | Endpoint |
---|---|---|
Web Single Sign-on | HTTP-POST, HTTP-Artifact, PAOS | scheme://server:port/contextPath/saml/SSO |
Web Single Sign-on Holder of Key | HTTP-POST, HTTP-Artifact | scheme://server:port/contextPath/saml/HoKSSO |
Single Logout | HTTP-POST, HTTP-Redirect | scheme://server:port/contextPath/saml/SingleLogout |
The default URLs can be altered with these steps:
change property filterProcessesUrl on the corresponding processing bean (samlWebSSOProcessingFilter, samlWebSSOHoKProcessingFilter, samlLogoutProcessingFilter or samlIDPDiscovery) to the new URL, for example /samlResponse
update the samlFilter bean and make sure that the modified processing filter is mapped to the correct pattern, for example /samlResponse/**, the /** part is only needed in case you're using the entity alias feature
re-generate metadata for your service provider, in case you are using automatic metadata generator the endpoints will be automatically generated with the new URLs
in case you are using pre-configured metadata you can perform changes manually in your existing metadata file
Endpoints of filters samlEntryPoint, samlLogoutFilter and metadataDisplayFilter can be changed using the same process and without need to re-generate the metadata.
Usage of HTTP-Artifact binding requires Spring SAML to make a direct SOAP call to the Identity Provider. Sometimes it's necessary to configure correct HTTP proxy for the call. This can be achieved by setting property hostConfiguration on HttpClient plugged to the artifactBinding bean. The following configuration demonstrates creation of the bean for the hostConfiguration:
<bean id="hostConfiguration" class="org.apache.commons.httpclient.HostConfiguration"/> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetObject" ref="hostConfiguration"/> <property name="targetMethod" value="setProxy"/> <property name="arguments"> <list> <value>testHost</value> <value>8080</value> </list> </property> </bean>
Another common use-case is situation when artifact resolution endpoint at IDP is secured using HTTP-Basic authentication. Authentication can be configured by setting HTTPClient's property state with the following bean:
<bean id="state" class="org.apache.commons.httpclient.HttpState"/> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetObject" ref="state"/> <property name="targetMethod" value="setCredentials"/> <property name="arguments"> <list> <util:constant static-field="org.apache.commons.httpclient.auth.AuthScope.ANY"/> <bean class="org.apache.commons.httpclient.UsernamePasswordCredentials"> <constructor-arg value="username"/> <constructor-arg value="password"/> </bean> </list> </property> </bean>