This is an Spring Security module for authentication and authorization with Security Assertion Markup Language. It uses the OpenSAML library from Internet2.
This documentation contains references to identity providers in a closed development environment. Replace them with the URLs and certificates of your own identity provider.
Add the following dependency to your project (check this project for the latest version)
<dependency>
<groupId>org.surfnet.coin</groupId>
<artifactId>spring-security-opensaml</artifactId>
<version>${spring-security-opensaml.version}</version>
</dependency>
When a user logs in, your application can create or update its existing profile.
Create a class that implements the nl.surfnet.spring.security.opensaml.Provisioner
interface.
Next, create a bean of this class in your Spring context.
<bean id="samlProvisioner" class="org.example.project.provisioning.SAMLProvisioner"/>
<bean id="samlCertificateStore" class="nl.surfnet.spring.security.opensaml.CertificateStoreImpl">
<property name="certificates">
<map>
<entry key="https://engine.dev.surfconext.nl/authentication/idp/metadata" value="MIID/jCCAuYCCQCs7BsDR2N8tjANBgkqhkiG9w0BAQUFADCBwDELMAkGA1UEBhMCTkwxEDAOBgNVBAgTB1V0cmVjaHQxEDAOBgNVBAcTB1V0cmVjaHQxJTAjBgNVBAoTHFNVUkZuZXQgQlYgLSBUaGUgTmV0aGVybGFuZHMxHzAdBgNVBAsTFkNvbGxhYm9yYXRpb24gU2VydmljZXMxGDAWBgNVBAMTD1NVUkZjb25leHQtdGVzdDErMCkGCSqGSIb3DQEJARYcc3VyZmNvbmV4dC1iZWhlZXJAc3VyZm5ldC5ubDAeFw0xMTA2MjcxNTM0NDFaFw0yMTA2MjQxNTM0NDFaMIHAMQswCQYDVQQGEwJOTDEQMA4GA1UECBMHVXRyZWNodDEQMA4GA1UEBxMHVXRyZWNodDElMCMGA1UEChMcU1VSRm5ldCBCViAtIFRoZSBOZXRoZXJsYW5kczEfMB0GA1UECxMWQ29sbGFib3JhdGlvbiBTZXJ2aWNlczEYMBYGA1UEAxMPU1VSRmNvbmV4dC10ZXN0MSswKQYJKoZIhvcNAQkBFhxzdXJmY29uZXh0LWJlaGVlckBzdXJmbmV0Lm5sMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA27T+ALNpoU9PAvRYj2orOXaEVcy1fHSU/rZEakpgNzOFIEL9UB6BvtWdRbO5FT84yN+x2Qzpu6WLpwU7JFb36aRwPmBmabxUx95DhNQNFGA3ZkHu6DOA81GiG0Ll9p9S/EV2fmHGJdJjh5BP1v0/y7bJ/2JmvdzH+cFhEhFk0Ex9HNbC0Hmy9Sn8EXbg3RQO5/2e51wSv4uGALkyGM6lrOG/R1GenoAI8Ys7LNxj3NGkhKRUtpwHoIViWU5cOy26kG9VOG9bAVk51l0LNayMqyieX9UrCp1akQuP3Ir/ogtbKo2zg63Ho1cc43tHHdLZTHp2TWRRGEgnskvGZLddzwIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQB8eUq/0ArBGnPZHNn2o2ip+3i0U4r0swKXjuYL/o2VXqo3eI9j/bCvWw5NOLQVbk/Whc6dSeYIt1oVW/ND4iQZ7LHZr9814IOE3KLGIMeZgjPsXH15o9W4aLC0npPYilw96dfIAq49tOn44jhsRHrdR8z/NFPXE09ehAEb7fOIrxdlf7YDGYx+gXLEnsJo75E6LwCr/y/MBd13DDJNc1HUViiEz+Mkfo4FEKe/5HgEvDy2XjuE1juDCqJ/07pBPHBd0DtM7uaxGw+Zt/Fc4uE0NvtlCZqShFUvMmqHL5oENOlfTmBSWJMbBAGs2O/JQirG2aYcULqXYoCGIPUF49Z6"/>
<entry key="https://mujina-idp.dev.surfconext.nl/" value="MIICHzCCAYgCCQD7KMJ17XQa7TANBgkqhkiG9w0BAQUFADBUMQswCQYDVQQGEwJOTDEQMA4GA1UECAwHVXRyZWNodDEQMA4GA1UEBwwHVXRyZWNodDEQMA4GA1UECgwHU3VyZm5ldDEPMA0GA1UECwwGQ29uZXh0MB4XDTEyMDMwODA4NTQyNFoXDTEzMDMwODA4NTQyNFowVDELMAkGA1UEBhMCTkwxEDAOBgNVBAgMB1V0cmVjaHQxEDAOBgNVBAcMB1V0cmVjaHQxEDAOBgNVBAoMB1N1cmZuZXQxDzANBgNVBAsMBkNvbmV4dDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2slVe459WUDL4RXxJf5h5t5oUbPkPlFZ9lQysSoS3fnFTdCgzA6FzQzGRDcfRj0HnWBdA1YH+LxBjNcBIJ/nBc7Ssu4e4rMO3MSAV5Ouo3MaGgHqVq6dCD47f52b98df6QTAA3C+7sHqOdiQ0UDCAK0C+qP5LtTcmB8QrJhKmV8CAwEAATANBgkqhkiG9w0BAQUFAAOBgQCvPhO0aSbqX7g7IkR79IFVdJ/P7uSlYFtJ9cMxec85cYLmWL1aVgF5ZFFJqC25blyPJu2GRcSxoVwB3ae8sPCECWwqRQA4AHKIjiW5NgrAGYR++ssTOQR8mcAucEBfNaNdlJoy8GdZIhHZNkGlyHfY8kWS3OWkGzhWSsuRCLl78A=="/>
</map>
</property>
</bean>
<opensaml:service-provider id="samlAuthenticationProvider"
message-handler-ref="samlMessageHandler"
preauth-filter-ref="samlPreAuthFilter"
entity-id="${ISSUING_ENTITY_ID}"
assertion-consumer-uri="${ASSERTION_CONSUMER_URI}"
provisioner-ref="samlProvisioner"
certificatestore-ref="samlCertificateStore"
authentication-manager-ref="authenticationManager" />
Within <security:http>
add the following configuration
<security:custom-filter position="PRE_AUTH_FILTER" ref="samlPreAuthFilter" />
<security:intercept-url pattern="/OpenSAML.sso/Login" access="permitAll"/>
<security:intercept-url pattern="${ASSERTION_CONSUMER_URI}" access="hasAnyRole(ROLE_ANONYMOUS,ROLE_ADMIN,ROLE_USER)"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="samlAuthenticationProvider"/>
</security:authentication-manager>
<bean id="authnRequestController" class="nl.surfnet.spring.security.opensaml.controller.AuthnRequestController">
<property name="SAMLMessageHandler" ref="samlMessageHandler" />
<property name="assertionConsumerServiceURL" value="${ASSERTION_CONSUMER_URL}" />
<property name="entityID" value="${ISSUING_ENTITY_ID}"/>
<property name="credentialResolver" ref="samlKeyStoreCredentialResolverDelegate" />
<property name="metaDataProperties" value ="metadata.test.properties"/>
</bean>
The last property is the name of the properties file on the classpath to override the default metadata. An example:
service-name-en=SelfService
service-name-nl=SelfService
service-description-en=SelfService application
service-description-nl=SelfService applicatie
contact-person-administrative-given-name=SURFConext
contact-person-administrative-sur-name=SURFConext
[email protected]
contact-person-technical-given-name=SURFConext
contact-person-technical-sur-name=SURFConext
[email protected]
contact-person-support-given-name=SURFConext
contact-person-support-sur-name=SURFConext
[email protected]
The actual matadata is available on the endpoint: "http://hostname/applicationroot/OpenSAML.sso/Metadata"
Add a properties file for the Spring Security OpenSAML configuration (in this example opensaml.properties
):
ISSUING_ENTITY_ID=http://local-myapp
WEB_APPLICATION_CHANNEL=http
WEB_APPLICATION_HOST_AND_PORT=localhost:8080
WEB_APPLICATION_CONTEXT_PATH=/myapp
ASSERTION_CONSUMER_URI=/AssertionConsumerService
ASSERTION_CONSUMER_URL=${WEB_APPLICATION_CHANNEL}://${WEB_APPLICATION_HOST_AND_PORT}${WEB_APPLICATION_CONTEXT_PATH}${ASSERTION_CONSUMER_URI}
MAX_PARSER_POOL_SIZE=2
REPLAY_CACHE_LIFE_IN_MILLIS=14400000
ISSUE_INSTANT_CHECK_CLOCK_SKEW_IN_SECONDS=90
ISSUE_INSTANT_CHECK_VALIDITY_TIME_IN_SECONDS=300
Load this property file from your application context:
<bean id="propertyResolver" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:opensaml.properties"/>
</bean>
Create an opensaml-dispatcher-servlet.xml
file inside the WEB-INF
folder with the following contents:
<bean id="openSAMLDispatcherProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:opensaml.properties</value>
</list>
</property>
</bean>
<mvc:annotation-driven/>
<bean id="authnRequestController" class="nl.surfnet.spring.security.opensaml.controller.AuthnRequestController">
<property name="assertionConsumerServiceURL" value="${ASSERTION_CONSUMER_URL}" />
<property name="SAMLMessageHandler" ref="samlMessageHandler" />
<property name="entityID" value="${ISSUING_ENTITY_ID}"/>
</bean>
Add a filter-mapping for the Spring Security filter chain and the servlet-mapping for the OpenSAML.sso/Login url:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>opensaml-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>opensaml-dispatcher</servlet-name>
<url-pattern>/OpenSAML.sso/Login</url-pattern>
</servlet-mapping>
When your application requires a user is logged in you can redirect it to the AuthN request controller.
For a single identity provider add the following rule in the security filter chain:
<security:form-login login-page="/OpenSAML.sso/Login?target=https://engine.dev.surfconext.nl/authentication/idp/single-sign-on" default-target-url="/" />
When you connect with multiple identity providers, you can show a Where Are You From (WAYF) page.
<security:intercept-url pattern="/myloginpage.jsp" access="permitAll"/>
<security:form-login login-page="/myloginpage.jsp" default-target-url="/" />
Example of myloginpage.jsp:
<a href="OpenSAML.sso/Login?target=https://engine.dev.surfconext.nl/authentication/idp/single-sign-on">
Login at surfconext
</a>
<a href="OpenSAML.sso/Login?target=https://openidp.feide.no/simplesaml/saml2/idp/SSOService.php">
Login at feido.no
</a>
<a href="OpenSAML.sso/Login?target=https://mujina-idp.dev.surfconext.nl/SingleSignOnService">
Login at Mujina
</a>