---
title: SP adapter
description: Use the SP adapter to make changes during the processing of the authentication request, such as updating the SPNameQualifier attribute, or during assertion processing after a response has been received.
component: pingam
version: 8.1
page_id: pingam:am-saml2:custom-sp-adapter
canonical_url: https://docs.pingidentity.com/pingam/8.1/am-saml2/custom-sp-adapter.html
keywords: ["SAML 2.0", "Single Sign-on (SSO)", "Federation", "Customization", "Java", "Scripts"]
page_aliases: ["plugins-sp-adapter.adoc", "saml2-guide:custom-sp-adapter.adoc"]
section_ids:
  java_example: Java example
  scripted_examples: Scripted examples
  example-sp-adapter-legacy: Redirect a journey using a legacy script
  example-sp-adapter-nextgen: Set session properties using a next-generation script
---

# SP adapter

Use the SP adapter to make changes during the processing of the authentication request, such as updating the `SPNameQualifier` attribute, or during assertion processing after a response has been received.

These steps assume your environment is already correctly configured for SSO using SAML 2.0, where AM is the hosted SP.

The SP adapter provides hooks at the following points:

| Extension point            | Description                                                                                           |
| -------------------------- | ----------------------------------------------------------------------------------------------------- |
| preSingleSignOnRequest     | Invoked before AM sends the SSO request to the IdP.                                                   |
| preSingleSignOnProcess     | Invoked before SSO processing begins on the SP side, when AM receives the response from the IdP.      |
| postSingleSignOnSuccess    | Invoked when SSO processing succeeds.                                                                 |
| postSingleSignOnFailure    | Invoked when SSO processing fails.                                                                    |
| postNewNameIDSuccess       | Invoked when the processing of a new name identifier succeeds.                                        |
| postTerminateNameIDSuccess | Invoked when the association of a name identifier between an SP and IdP is successfully terminated.   |
| preSingleLogoutProcess     | Invoked before the SLO process starts on the SP side, while the authenticated session is still valid. |
| postSingleLogoutProcess    | Invoked after the SLO process succeeds when the authenticated session has been invalidated.           |

## Java example

To create a custom SP adapter in Java, follow these high-level steps:

1. Include the `openam-federation-library` as a dependency in your Maven project.

2. Write a Java class that implements the [org.forgerock.openam.saml2.plugins.SPAdapter](../_attachments/apidocs/org/forgerock/openam/saml2/plugins/SPAdapter.html) interface.

3. Add code to one or more of the methods described in the [extension points table](#sp-adapter-points) to customize the authentication journey.

4. Package your custom class in a JAR file and copy to the `/WEB-INF/lib` folder where you deployed AM.

5. Configure AM to use the new Java plugin.

   1. In the AM admin UI, go to Realms > *realm name* > Applications > Federation > Entity Providers > *hosted SP* > Assertion Processing.

   2. In the Adapter field, type the fully qualified name of your custom class.

   3. Save your changes.

6. Restart AM or the container in which it runs.

7. Test your changes.

## Scripted examples

Learn about SP adapter scripts from the following resources:

* Legacy example script

  [SAML2 SP Adapter Script](../am-scripting/sample-scripts.html#saml2-sp-adapter-js)

* Next-generation example script

  [SAML2 SP Adapter Script (Next Gen)](../am-scripting/sample-scripts.html#saml2-sp-adapter-nextgen-js)

* Scripting API

  [SP adapter scripting API](../am-scripting/saml2-sp-adapter-api.html)

### Redirect a journey using a legacy script

Complete the following steps to implement an example SP adapter script that updates the `SPNameQualifier` attribute in the authentication request.

1. In the AM admin UI, go to Realms > *realm name* > Scripts, and click SAML2 SP Adapter Script. Alternatively, [create a new script](../am-scripting/manage-scripts-console.html) of type `Saml2 SP Adapter`.

2. In the Script field, add code to the `preSingleSignOnRequest` function to change the value of `SPNameQualifier` in the authentication request. Optionally, add code to redirect a successful login in the `postSingleSignOnSuccess` function.

   For example:

   ```javascript
   function preSingleSignOnRequest() {
     logger.error("In preSingleSignOnRequest");
     authnRequest.getNameIDPolicy().setSPNameQualifier("mySP-Updated");
   }

   function postSingleSignOnSuccess() {
       logger.error("In postSingleSignOnSuccess");
       response.sendRedirect("https://example.com");
       return true;
   }
   ```

3. Validate and save your changes.

4. Configure AM to use the updated SP adapter script.

   1. In the AM admin UI, go to Realms > *realm name* > Applications > Federation > Entity Providers > *hosted SP* > Assertion Processing.

   2. Under Adapter, select your customized script from the Adapter Script drop-down list.

   3. Save your changes.

5. Test your changes using an SP-initiated flow.

   Verify that the SAML2.0 request contains the updated value (`SPNameQualifier="mySP-Updated"`) and that the user is redirected to `https://example.com` on successful login.

### Set session properties using a next-generation script

This example uses a next-generation script to set SAML attributes in the current session and conditionally redirects the authenticated user to a website.

1. In the AM admin UI, [create a new script](../am-scripting/manage-scripts-console.html) on the hosted SP with the following values:

   * Name

     `Example Next-Generation SP Adapter`

   * Script Type

     `Saml2 SP Adapter`

   * Evaluator Version

     `Next Generation`

2. In the Script field, replace the `postSingleSignOnSuccess` function with the following script:

   ```javascript
   function postSingleSignOnSuccess() {

     var redirectOccurred = false;

     try {

       if (!ssoResponse || !session) {
         logger.error("Missing ssoResponse or session object.");
         return false;
       }

       // Set response attributes as session properties
       var issueInstant = ssoResponse.issueInstant;
       var issuer = ssoResponse.issuer ? ssoResponse.issuer.value : "Unknown";
       session.setProperty("issueInstant", issueInstant);
       session.setProperty("issuer", issuer);
       logger.info("[issueInstant]: " + issueInstant + " [issuer]: " + issuer);

       // get address from assertion's attribute statement
       var assertion = ssoResponse.assertion[0];

       if (assertion && assertion.attributeStatements) {
         var statements = assertion.attributeStatements;

         for (var i = 0; i < statements.length; i++) {
           var attributes = statements[i].attribute;

           if (attributes && attributes.length > 0) {
             // Look for the 'Address' attribute
             for (var j = 0; j < attributes.length; j++) {

               if (attributes[j].name === "Address") {
                 var addressValue = attributes[j].attributeValueString;

                 if (addressValue && addressValue.length > 0) {
                   var address = addressValue[0];
                   logger.info("[postaladdress]: " + address);
                   session.setProperty("address", address);

                   // Redirect based on SAML address attribute
                   if (responseHelper) {
                     if (address === 'UK') {
                       responseHelper.sendRedirect("https://loremipsum.io/");
                     } else {
                       responseHelper.sendRedirect("https://example.com/");
                     }
                     redirectOccurred = true;
                   }
                   return redirectOccurred;
                 }
               }
             }
           }
         }
       }
     } catch (e) {
       logger.error("Error in postSingleSignOnSuccess: " + e.toString());
     }
     return redirectOccurred;
   }
   ```

3. On the remote IdP, map the attributes required for the script:

   1. Go to Realms > *realm name* > Applications > Federation > Entity Providers > *hosted IdP* > Assertion Processing.

   2. Add the following mapping to the Attribute Map:

      * SAML Attribute

        `Address`

      * Local Attribute

        `postaladdress`

   3. Save your changes.

4. Update a test user and set their address to `UK`:

   1. Click Identities > *test user* and set the following attribute:

      * Home Address

        `UK`

5. To test your changes, perform an SP-initated SSO flow using your UK test user.

   Verify that the user is redirected to `https://loremipsum.io` and that the logging output contains values for the SSO response attributes, for example:

   `INFO: [issueInstant]: 1770649129000 [issuer]: identityprovider1` `INFO: [postaladdress]: UK`
