Skip to content

AIS Springboot + SAML2 Authentication

Tip:
If your application requires only HawkID based authentication, it is recommended to use autoconfigure-auth-oidc instead.

Description

autoconfigure-auth-saml2 is a library designed to help its consumers use the SAML2 SSO for their application. It uses Spring Security which provides comprehensive SAML2 support.[4]
This module is compatible with ais-nuxt module.

Acronyms

This section provides definitions for the acronyms used throughout this document.

  • SSO[3]:
    • Single sign-on (SSO) is a technology which combines several different application login screens into one.
    • With SSO, a user only has to enter their login credentials (hawk-id, password) one time on a single page to access all of their SaaS applications.
  • SAML1,2:
    • Security Assertion Markup Language (SAML), is a standardized way to tell external applications and services that a user is who they say they are.
    • SAML makes SSO technology possible by providing a way to authenticate a user once and then communicate that authentication to multiple applications.
  • SAML Assertion:
    A special token format containing the result of an authentication event plus any accompanying information about the user who authenticated.
  • Shibboleth: An open-source software consortium that makes a variety of packages to handle the different steps of a SAML login flow. People often use the word Shibboleth interchangeably with SAML itself, or any of the packages that they provide.
  • Relying Party (RP) or Service Provider (SP):
    NOTE: SP and RP are synonymous and this is what your application will be.
    An application that receives and parses identity information sent to it by an Identity Provider in a SAML assertion. Typically installed as a piece of middleware in front of any application you'd like to integrate with HawkID authentication.
  • Identity Provider (IdP) or Asserting Party (AP):
    NOTE: IdP and AP are synonymous.
    An application that handles authenticating users after a request from a Service Provider by validating their username and password, gathering identity information, and sending the result back in a SAML assertion. Managed on our campus by ITS - IAM team and other institution's IAM team. More info on this below.
  • EntityID:
    A formal name for an SP, typically based on the application's URL for ease of recognition and to avoid namespace conflicts, but theoretically it could be any unused string. Once chosen, an EntityID should never be changed.

Flow

Prerequisites

1. Include this library

//gradle example
repositories {
    ...
    maven { url "https://build.shibboleth.net/nexus/content/repositories/releases/" }
}
dependencies {
    ...
    implementation 'uiowa.springboot:autoconfigure-web'
    implementation 'uiowa.springboot:autoconfigure-auth-saml2'
}

2. Generate SHA256 base certificate

  • If you don’t have OpenSSL installed, install it via homebrew or download and install it first.
    shell
    brew install openssl
  • Run the command given below to generate SHA256 Keypair (feel free to use a different filenames).
    shell
    openssl req -x509 -sha256 -days 3650 -nodes -newkey rsa:2048 -keyout bor-datasets-sp.key -out bor-datasets-sp.cert

    NOTE: bor-datasets-sp.cert (certificate file or content) will be shared to the IdPs.

  • Place certificates to your application's resources folder.
    Feel free to customize the folder structure, just remember to update the application properties accordingly. All the examples list below would follow the below structure.
    bor-datasets-service
    └── src
        └── main
            └── resources
                ├── saml
                │   ├── metadata
                │   │   └── ...
                │   ├── bor-datasets-sp.cert
                │   └── bor-datasets-sp.key
                └── ...

3. Register Application with IdP(s)

A crucial step to using this library is to register your application with identity providers (depending on how many your application supports).

Email the ITS IAM team (its-iam@uiowa.edu) with the below information, so that they can register your application within the identity provider.

NOTE: Below is just an example, and not a set template. Please update/replace as per your requirements.


Generate Application's metadata files

Applications to support

EnvironmentApplication URL (includes base url)
LOCALhttp://localhost:8008/bor-datasets
DEVhttps://bor-datasets-dev.ais.its.uiowa.edu/bor-datasets
TESThttps://bor-datasets-test.ais.its.uiowa.edu/bor-datasets
PRODhttps://bor-datasets.ais.its.uiowa.edu/bor-datasets

Base Endpoints (where uiowa is the registration-id, and <APP_URL> will be the application URL from above table)

TypeEndpoint
EntityID<APP_URL>/saml2/service-provider-metadata/uiowa
Assertion Consumer Service (ACS) URL<APP_URL>/login/saml2/sso/uiowa
Single Logout Service (SLO) URL<APP_URL>/logout/saml2/slo

Attributes required by the application

  • First Name
  • Last Name
  • Email

Add any additional attributes required by your application.


IAM Team's response

Once configured, the IAM team will reply back with the IdP metadata files(.xml), and attributes mapping.
We will need to add these later to our application configuration/properties.

Register Application with other IdP(s)

This will be very similar to the above request, with change just to the registration-id.

UniversityContact Details
University of Iowa (UIOWA)its-iam@uiowa.edu
Iowa State University (ISU)shibboleth@iastate.edu, prabathd@iastate.edu
University of Northern Iowa (UNI)shibboleth@uni.edu, jeff.chapin@uni.edu

Usage

Configure Application

Please refer to the applications implementing this library for additional examples on how to configure the application.

  1. Add SAML2 IdP Metadata Files

    Place files (provided by the IAM team) to your application's resources folder.
    Feel free to customize the folder structure, just remember to update the application properties accordingly. All the examples list below would follow the below structure.

    bor-datasets-service
    └── src
        └── main
            └── resources
                ├── saml
                │   └── metadata
                │       ├── uiowa_idp_prod_metadata.xml
                │       └── uiowa_idp_test_metadata.xml
                ├── application.yml
                ├── application.dev.yml
                ├── application.prod.yml
                └── application.test.yml
  2. Update SAML2 Properties

    Common Properties
    yaml
    #### application.yml ####
    common-properties:
      credentials: &common-credentials
        - private-key-location: classpath:saml/bor-datasets-sp.key
          certificate-location: classpath:saml/bor-datasets-sp.cert
      relying-party-registration: &common-relying-party-registration
        signing.credentials: *common-credentials
        decryption.credentials: *common-credentials
        singlelogout:
          binding: POST
          url: "{baseUrl}/logout/saml2/slo"
    
    spring:
      security:
        saml2:
          relyingparty:
            registration:
              uiowa:
                << : *common-relying-party-registration
                assertingparty:
                  metadata-uri: classpath:saml/metadata/uiowa_idp_test_metadata.xml
                  singlelogout:
                    binding: POST
              isu: # Assuming that that app is registered by ISUs IdP
                <<: *common-relying-party-registration
                assertingparty:
                  metadata-uri: classpath:saml/metadata/isu_idp_test_metadata.xml
                  singlelogout:
                    binding: POST
              #... other registered IdPs

    OR if you prefer .properties (NOTE - below properties are not tested)

    properties
    #### application.properties ###
    spring.security.saml2.relyingparty.registration.uiowa.signing.credentials[0].certificate-location=classpath:saml/bor-datasets-sp.cert
    spring.security.saml2.relyingparty.registration.uiowa.signing.credentials[0].private-key-location=classpath:saml/bor-datasets-sp.key
    spring.security.saml2.relyingparty.registration.uiowa.decryption.credentials[0].private-key-location=classpath:saml/bor-datasets-sp.key
    spring.security.saml2.relyingparty.registration.uiowa.decryption.credentials[0].certificate-location=classpath:saml/bor-datasets-sp.cert
    spring.security.saml2.relyingparty.registration.uiowa.singlelogout.binding=REDIRECT
    spring.security.saml2.relyingparty.registration.uiowa.assertingparty.metadata-uri= classpath:saml/metadata/uiowa_idp_test_metadata.xml
    spring.security.saml2.relyingparty.registration.uiowa.assertingparty.singlelogout.binding=REDIRECT
    # Assuming that that app is registered by ISUs IdP
    spring.security.saml2.relyingparty.registration.isu.signing.credentials[0].certificate-location=classpath:saml/bor-datasets-sp.cert
    spring.security.saml2.relyingparty.registration.isu.signing.credentials[0].private-key-location=classpath:saml/bor-datasets-sp.key
    spring.security.saml2.relyingparty.registration.isu.decryption.credentials[0].private-key-location=classpath:saml/bor-datasets-sp.key
    spring.security.saml2.relyingparty.registration.isu.decryption.credentials[0].certificate-location=classpath:saml/bor-datasets-sp.cert
    spring.security.saml2.relyingparty.registration.isu.singlelogout.binding=REDIRECT
    spring.security.saml2.relyingparty.registration.isu.assertingparty.metadata-uri= classpath:saml/metadata/isu_idp_test_metadata.xml
    spring.security.saml2.relyingparty.registration.isu.assertingparty.singlelogout.binding=REDIRECT
    #... other registered IdPs
    DEV Properties
    yaml
    #### application.dev.yml ####
    # Using TEST's entity-id as we have configured LOCAL and DEVs ACS and SLO endpoints in TEST's service provider. 
    spring:
      security:
        saml2:
          relyingparty:
            registration:
              uiowa:
                entity-id: https://bor-datasets-test.ais.its.uiowa.edu/bor-datasets/saml2/service-provider-metadata/uiowa

    OR if you prefer .properties

    properties
    #### application.dev.properties ###
    # Using TEST's entity-id as we have configured LOCAL and DEVs ACS and SLO endpoints in TEST's service provider.
    spring.security.saml2.relyingparty.registration.uiowa.entity-id=https://bor-datasets-test.ais.its.uiowa.edu/bor-datasets/saml2/service-provider-metadata/uiowa
    PROD Properties
    yaml
    #### application.prod.yml ####
    spring:
     security:
       saml2:
         relyingparty:
           registration:
             uiowa:
               assertingparty:
                 metadata-uri: classpath:saml/metadata/uiowa_idp_prod_metadata.xml

    OR if you prefer .properties

    properties
    #### application.prod.properties ###
    spring.security.saml2.relyingparty.registration.uiowa.assertingparty.metadata-uri=classpath:saml/metadata/uiowa_idp_prod_metadata.xml
  3. Update SAML2 Attributes

    With reference to the registered attributes, we need to map these so that the library is able to map them to the AisUser (which can then be use for authentication).

    yaml
    uiowa:
      ais:
        auth:
          saml2:
            attribute-keys:
              uiowa: # registration-id
                #Key: Value(provided by IAM team)
                universityId: "urn:oid:8.0.008.80000008.800.0.8"

    NOTE: email, hawkid, lastname, and firstname are registered by default and need not be added here. Refer to Saml2AuthProperties.getDefaultAttributeKeys to see the default attributes

  4. Implement AisUserDetailsService Interface

    java
    @Service
    public class UserDetailService implements AisUserDetailService {
        @Override
        @Transactional(readonly = true)
        public AisUser getUser(AisUser aisUser) throws AisUserNotFoundException {
            String email = aisUser.email();
            /*
             * Add your logic here.
             * eg:
             *    - Use aisUser to check if it's a valid application user
             *    - Get roles from the backend, etc.
             */
            try {
                return new AisUser.Builder()
                    .fromAisUser(aisUser)
                    .roles(Set.of("ADMIN_ROLE"))
                    .build();
            } catch (Exception ex) {
                throw new AisUserNotFoundException(ex);
            }
            
        }
    }
  5. Implement OnLogin Interface (Optional)

    java
    @Service
    public class OnLoginService implements OnLogin {
        @Override
        public void execute(AisUser aisUser, HttpServletRequest httpServletRequest) throws Exception {
            // Logic for post successful login.
            // Update user's last login, etc...
        }
    }

Hopefully after this step you should be able to start your application and perform SAML2 authentication.

In case of any issues/concerns please feel free to reach out to our slack support channel: #tool-ais-springboot.

Applications implementing this library

References