How to connect Okta SAML and Spring Boot using saml2Login, part 2

This is the second article in the series. For the first article, visit here.

Multiple Okta SAML Identity Providers

spring:
security:
saml2:
relyingparty:
registration:
okta1:
identityprovider:
metadata-uri: https://dev-#######.okta.com/app/XXXXXXXXXXXXXXXXXXXX/sso/saml/metadata
okta2:
identityprovider:
metadata-uri: https://dev-#######.okta.com/app/XXXXXXXXXXXXXXXXXXXX/sso/saml/metadata

It’s that simple. The properties are briefly introduced in the Spring Security documentation (5.4.2), and I haven’t been able to find a more detailed description. As typical for Spring Boot, there’s some magic and defaults that kick in when explicit configuration isn’t given, so if it’s not behaving as expected, check out the Saml2RelyingPartyProperties source code.

Note that okta1 and okta2 are the Relying Party registrationIds, which for our example are used primarily for the Okta SSO URL and Audience Restriction URI which are configured in the Okta User Interface.

SSO URL: http://localhost:8080/login/saml2/sso/okta1

Audience Restriction URI: http://localhost:8080/saml2/service-provider-metadata/okta1

Now when you launch your app, you will see the following login page — without having to do any extra work!

Spring Security’s default login page shows the available SAML IDPs
Spring Security’s default login page shows the available SAML IDPs
Spring Security’s default login page shows the available SAML IDPs

Simply choose which Okta instance to use, sign in, and you will be returned to the application. I’ve created a sample application at https://github.com/joshuatcasey/okta-boot-and-saml2login, all you need to do is substitute the correct Okta metadata URLs in application.yaml.

Map SAML attributes to Identity and Authorization

Configure identity and group information in the Okta SAML Assertion
Configure identity and group information in the Okta SAML Assertion
Configure identity and group information in the Okta SAML Assertion

How is this information represented in Spring Security? Identity is contained in the Principal and authorities are contained in the Authorities. For more information, see the links below. But how do we link a SAML Subject into a Spring Security Principal? How do we translate SAML Groups Attribute into Spring Security Authorities?

First, let’s pick a terminology for Identity. Should my name “Joshua” be my first name, given name, or forename? Should my name “Casey” be my last name, family name, or surname? I’ll select SCIM as the common labeling methodology. For today, all we will use is userName, name.givenName, name.familyName, and emails from the SCIM specification.

We need a way to map the attributes from SAML to our SCIM attributes. This will depend on the SAML provider and how it is implemented, so we’ll have to link it to the registrationId. As an example, let’s specify this mapping in our properties:

spring:
security:
saml2:
relyingparty:
authorityMapping:
okta1: Groups
okta2: Groups
identityMapping:
okta1:
givenName: FirstName
familyName: LastName
email: Email
okta2:
givenName: FirstName
familyName: LastName
email: Email

Under authorityMapping, we can specify which SAML attribute to use for authorities. In this case, it’s Groups for both Okta instances.

Under identityMapping, we can specify a list of attributes to map from SAML to SCIM. In this case, the FirstName SAML attribute will map to name.givenName SCIM attribute and so on.

If you run the sample application, and visit the /whoami endpoint you should see something like the following JSON. Also, if you create a group in Okta called Admins and put the user groups in a SAML attribute called Groups, you should be able to visit the /admins endpoint as well.

{
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User"
],
"id": null,
"externalId": null,
"meta": null,
"userName": "<your email>",
"name": {
"formatted": null,
"familyName": "Casey",
"givenName": "Joshua",
"middleName": null,
"honorificPrefix": null,
"honorificSuffix": null
},
"displayName": null,
"nickName": null,
"profileUrl": null,
"title": null,
"userType": null,
"preferredLanguage": null,
"locale": null,
"timezone": null,
"active": null,
"password": null,
"emails": [
{
"value": "<your email>",
"display": null,
"type": null,
"primary": true
}
],
"phoneNumbers": null,
"ims": null,
"photos": null,
"addresses": null,
"groups": null,
"entitlements": null,
"roles": null,
"x509Certificates": null
}

I hope this helps you to understand how identity and authorization are configured in Okta and Spring Boot! Let me know if I can add clarifying information or more examples.