Implementing SAML-based Single Sign-On (SSO) with Spring Security allows applications to delegate authentication to external Identity Providers (IdPs) like Okta, ADFS, or Azure AD. This guide explains how to configure Spring Security’s SAML Extension, set up local and remote metadata, and map user attributes for seamless integration.


1. Configuring Spring Security SAML Extension

Prerequisites

  • Java 8+
  • Spring Boot 2.x/3.x
  • spring-security-saml2-service-provider dependency

Step 1: Add Dependencies

Include the following in your pom.xml (Maven) or build.gradle (Gradle):

Maven:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-saml2-service-provider</artifactId>
    <version>5.7.0</version>
</dependency>

Gradle:

implementation 'org.springframework.security:spring-security-saml2-service-provider:5.7.0'

Step 2: Configure SAML in application.yml

Define the SAML properties in your configuration file:

spring:
  security:
    saml2:
      relyingparty:
        registration:
          idp-name:
            identityprovider:
              entity-id: urn:example:idp
              singlesignon.url: https://idp.example.com/saml2/sso
              verification.credentials:
                - certificate-location: classpath:idp-certificate.pem

Step 3: Enable SAML in Security Configuration

Extend WebSecurityConfigurerAdapter (Spring Boot 2.x) or use SecurityFilterChain (Spring Boot 3.x):

Spring Boot 3.x Example:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain samlFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .anyRequest().authenticated()
            )
            .saml2Login(saml2 -> saml2
                .relyingParty(rp -> rp
                    .registration(registration -> registration
                        .entityId("urn:example:sp")
                        .assertingParty(party -> party
                            .entityId("urn:example:idp")
                            .singleSignOnServiceLocation("https://idp.example.com/saml2/sso")
                            .verificationCredentials(c -> c
                                .certificateLocation("classpath:idp-certificate.pem")
                            )
                        )
                    )
                )
            );
        return http.build();
    }
}

2. Local and Remote Metadata Setup

Local Metadata (SP Metadata)

Spring Security can generate SP metadata dynamically or use a static file.

Generate Dynamically:
Access /saml2/service-provider-metadata/{registrationId} (e.g., /saml2/service-provider-metadata/idp-name).

Static Metadata File:

  1. Create an XML file (e.g., sp-metadata.xml) with your SP details.
  2. Configure it in application.yml:
spring:
  security:
    saml2:
      relyingparty:
        registration:
          idp-name:
            serviceprovider:
              entity-id: urn:example:sp
              metadata-location: classpath:sp-metadata.xml

Remote Metadata (IdP Metadata)

Provide the IdP’s metadata URL or file:

Via URL:

spring:
  security:
    saml2:
      relyingparty:
        registration:
          idp-name:
            identityprovider:
              metadata-uri: https://idp.example.com/metadata.xml

Via File:

metadata-location: classpath:idp-metadata.xml

3. User Attribute Mapping (AttributeMapping)

SAML assertions include user attributes (e.g., email, name). Map these to Spring Security’s Principal:

Default Attribute Mapping

Spring Security automatically maps:

  • http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddressPrincipal.getName()
  • http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givennamePrincipal.getAttribute("given_name")

Custom Mapping

Override defaults in SecurityConfig:

.saml2Login(saml2 -> saml2
    .relyingParty(...)
    .userDetailsService(userDetailsService())
    .attributeMapping(attrs -> attrs
        .name("email") // Maps NameID or specified attribute to Principal
        .samlAttribute("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress")
    )
)

Example: Extract Roles from SAML

.saml2Login(saml2 -> saml2
    .attributeMapping(attrs -> attrs
        .roles("http://schemas.microsoft.com/ws/2008/06/identity/claims/role")
    )
)

4. Full Flow Example with Metadata

  1. User Visits /login:

    • Redirects to IdP’s SSO URL (https://idp.example.com/saml2/sso).
  2. IdP Authenticates User:

    • Returns a SAML response to /saml2/acs (Assertion Consumer Service).
  3. Spring Security Validates Assertion:

    • Verifies the signature using the IdP’s certificate.
    • Maps attributes to Principal.
  4. User Granted Access:

    • Authenticated session established.

Conclusion

Spring Security’s SAML extension simplifies integration with SAML-based IdPs. Key steps include:

  1. Configuring dependencies and properties.
  2. Setting up SP/IdP metadata (local or remote).
  3. Customizing attribute mapping for user details.

For advanced scenarios, refer to the Spring Security SAML Documentation.