SAML 2.0 authentication

Learn how to set up and authenticate end-users (not AEM authors) to a SAML 2.0 compatible IDP of your choosing.

What SAML for AEM as a Cloud Service?

SAML 2.0 integration with AEM Publish (or Preview), allows end users of an AEM-based web experience to authenticate to a non-Adobe IDP (Identity Provider), and access AEM as a named, authorized user.

AEM Author AEM Publish
SAML 2.0 support
 Understand the SAML 2.0 flow with AEM

The typical flow of an AEM Publish SAML integration is as follows:

  1. User makes a request to AEM Publish the indicates authentication is required.
    • User requests a CUGs/ACL protected resource.
    • User requests a resource that is subject to an Authentication Requirement.
    • User follows a link to AEM’s login endpoint (i.e. /system/sling/login) that explicitly requests the login action.
  2. AEM makes an AuthnRequest to the IDP, requesting IDP to start authentication process.
  3. User authenticates to IDP.
    • User is prompted by the IDP for credentials.
    • User is already authenticated with the IDP and does not have to provide further credentials.
  4. IDP generates a SAML assertion containing the user’s data, and signs it using the IDP’s private certificate.
  5. IDP sends the SAML assertion via HTTP POST, by way of the user’s web browser, to AEM Publish.
  6. AEM Publish receives the SAML assertion, and validates the SAML assertion’s integrity and authenticity using the IDP public certificate.
  7. AEM Publish manages the AEM user record based on the SAML 2.0 OSGi configuration, and the contents of the SAML Assertion.
    • Creates user
    • Synchronizes user attributes
    • Updates AEM user group membership
  8. AEM Publish sets the AEM login-token cookie on the HTTP response, which is used to authenticate subsequent requests to AEM Publish.
  9. AEM Publish redirects user to URL on AEM Publish as specified by the saml_request_path cookie.

Configuration walk-through

This video walks through of setting up SAML 2.0 integration with AEM as a Cloud Service Publish service, and using Okta as the IDP.

Prerequisites

The following are required when setting up SAML 2.0 authentication:

  • Deployment Manager access to Cloud Manager
  • AEM Administrator access to AEM as a Cloud Service environment
  • Administrator access to the IDP
  • Optionally, access to a public/private keypair used to encryption SAML payloads

SAML 2.0 is only supported to authenticate uses to AEM Publish or Preview. To manage the authentication of AEM Author using and IDP, integrate the IDP with Adobe IMS.

Install IDP public certificate on AEM

The IDP’s public certificate is added to AEM’s Global Trust Store, and used to validate the SAML assertion sent by the IDP is valid.

 SAML assertion signing flow

SAML 2.0 - IDP SAML Assertion signing

  1. User authenticates to IDP.
  2. IDP generates a SAML assertion containing the user’s data.
  3. IDP signs the SAML assertion using the IDP’s private certificate.
  4. IDP initiates a client-side HTTP POST to AEM Publish’s SAML endpoint (.../saml_login) that includes the signed SAML assertion.
  5. AEM Publish receives the HTTP POST containing the signed SAML assertion, can validate the signature using the IDP public certificate.

Add the IDP public certificate to the Global Trust Store

  1. Obtain the public certificate file from the IDP. This certificate allows AEM to validate the SAML assertion provided to AEM by the IDP.

    The certificate is in PEM format, and should resemble:

    -----BEGIN CERTIFICATE-----
    MIIC4jCBAcoCCQC33wnybT5QZDANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJV
    ...
    m0eo2USlSRTVl7QHRTuiuSThHpLKQQ==
    -----END CERTIFICATE-----
    
  2. Log in to AEM Author as an AEM Administrator.

  3. Navigate to Tools > Security > Trust Store.

  4. Create or open the Global Trust Store. If creating a Global Trust Store, store the password some place safe.

  5. Expand Add certificate from CER file.

  6. Select Select Certificate File, and upload the certificate file provided by the IDP.

  7. Leave Map Certificate to User blank.

  8. Select Submit.

  9. The newly added certificate appears above the Add certificate from CRT file section.

  10. Make note of the alias, as this value is used in the SAML 2.0 Authentication Handler OSGi configuration.

  11. Select Save & Close.

The Global Trust Store is configured with the IDP’s public certificate on AEM Author, but since SAML is only used on AEM Publish, the Global Trust Store must be replicated to AEM Publish for the IDP public certificate to be accessible there.

Replicate the Global Trust Store to AEM Publish

  1. Navigate to Tools > Deployment > Packages.
  2. Create a package
    • Package name: Global Trust Store
    • Version: 1.0.0
    • Group: com.your.company
  3. Edit the new Global Trust Store package.
  4. Select the Filters tab, and add a filter for the root path /etc/truststore.
  5. Select Done and then Save.
  6. Select the Build button for the Global Trust Store package.
  7. Once built, select More > Replicate to activate the Global Trust Store node (/etc/truststore) to AEM Publish.

Create authentication-service keystore

Creating a keystore for authentication-service is required when the SAML 2.0 authentication handler OSGi configuration property handleLogout is set to true or when AuthnRequest signing/SAML assertion ecryption is required

  1. Log in to AEM Author as an AEM Administrator, to upload the private key.
  2. Navigate to Tools > Security > Trust Store, and select authentication-service user, and select Properties from the top action bar.
  3. Navigate to Tools > Security > Users, and select authentication-service user, and select Properties from the top action bar.
  4. Select the Keystore tab.
  5. Create or open the keystore. If creating a keystore, keep the password safe.
  6. Select Save & Close.
  7. Select authentication-service user, and select Activate from the top action bar.

Install AEM public/private key pair

Installing the AEM public/private key pair is optional

AEM Publish can be configured to sign AuthnRequests (to IDP), and encrypt SAML assertions (to AEM). This is achieved by providing a private key to AEM Publish, and it’s matching public key to the IDP.

 Understand the AuthnRequest signing flow (optional)

The AuthnRequest (the request to the IDP from AEM Publish that initiates the login process) can be signed by AEM Publish. To do this, AEM Publish signs the AuthnRequest using the private key, that the IDP then validates the signature using the public key. This guarantees to the IDP that AuthnRequest was initiated, and requested by AEM Publish, and not a malicious third party.

SAML 2.0 - SP AuthnRequest signing

  1. User makes an HTTP request to AEM Publish that results in an SAML authentication request to the IDP.
  2. AEM Publish generates the SAML request to send to the IDP.
  3. AEM Publish signs the SAML request using AEM’s private key.
  4. AEM Publish initiates the AuthnRequest, an HTTP client-side redirect to the IDP that contains the signed SAML request.
  5. IDP receives the AuthnRequest, and validates the signature using AEM’s public key, guaranteeing AEM Publish initiated the AuthnRequest.
  6. AEM Publish then validates the decrypted SAML assertion’s integrity and authenticity using the IDP public certificate.
 Understand the SAML assertion encryption flow (optional)

All HTTP communication between IDP and AEM Publish should be over HTTPS, and thus secure by default. However, as required, SAML assertions can be encrypted in the event extra confidentiality is required on top of that provided by HTTPS. To do this, the IDP encrypts the SAML Assertion data using the private key, and AEM Publish decrypts the SAML assertion using the private key.

SAML 2.0 - SP SAML Assertion encryption

  1. User authenticates to IDP.
  2. IDP generates a SAML assertion containing the user’s data, and signs it using the IDP’s private certificate.
  3. IDP then encrypts the SAML assertion with AEM’s public key, which requires the AEM private key to decrypt.
  4. The encrypted SAML assertion is sent, by way of the user’s web browser to AEM Publish.
  5. AEM Publish receives the SAML assertion, and decrypts it using AEM’s private key.
  6. IDP prompts user to authenticate.

Both AuthnRequest signing, and SAML assertion encryption are optional, however they are both enabled, using the SAML 2.0 authentication handler OSGi configuration property useEncryption, meaning both or neither can be used.

AEM authentication-service key store

  1. Obtain the public key, private key (PKCS#8 in DER format), and certificate chain file (this may be the public key) used to sign the AuthnRequest, and encrypt the SAML assertion. The keys are typically provided by the IT organization’s security team.

    • A self-signed key pair can be generated using openssl:
    $ openssl req -x509 -sha256 -days 365 -newkey rsa:4096 -keyout aem-private.key -out aem-public.crt
    
    # Provide a password (keep in safe place), and other requested certificate information
    
    # Convert the keys to AEM's required format
    $ openssl rsa -in aem-private.key -outform der -out aem-private.der
    $ openssl pkcs8 -topk8 -inform der -nocrypt -in aem-private.der -outform der -out aem-private-pkcs8.der
    
  2. Upload the public key to the IDP.

    • Using the openssl method above, the public key is the aem-public.crt file.
  3. Log in to AEM Author as an AEM Administrator, to upload the private key.

  4. Navigate to Tools > Security > Trust Store, and select authentication-service user, and select Properties from the top action bar.

  5. Navigate to Tools > Security > Users, and select authentication-service user, and select Properties from the top action bar.

  6. Select the Keystore tab.

  7. Create or open the keystore. If creating a keystore, keep the password safe.

  8. Select Add private key from DER file, and add the private key and chain file to AEM:

    • Alias: Provide a meaningful name, often the name of the IDP.
    • Private key file: Upload the private key file (PKCS#8 in DER format).
      • Using the openssl method above, this is the aem-private-pkcs8.der file
    • Select certificate chain file: Upload the accompanying chain file (this may be the public key).
      • Using the openssl method above, this is the aem-public.crt file
    • Select Submit
  9. The newly added certificate appears above the Add certificate from CRT file section.

  10. Select Save & Close.

  11. Select authentication-service user, and select Activate from the top action bar.

Configure SAML 2.0 authentication handler

AEM’s SAML configuration is performed via the Adobe Granite SAML 2.0 Authentication Handler OSGi configuration.
The configuration is an OSGi factory configuration, meaning a single AEM as a Cloud Service Publish service may have multiple SAML configuration’s covering discrete resources trees of the repository; this is useful for multi-site AEM deployments.

 SAML 2.0 Authentication Handler OSGi configuration glossary

Adobe Granite SAML 2.0 Authentication Handler OSGi configuration

OSGi property Required Value format Default value Description
Paths path String array / AEM paths this authentication handler is used for.
IDP URL idpUrl String IDP URL the SAML authentication request is sent.
IDP certificate alias idpCertAlias String The alias of the IDP certificate found in the AEM’s Global Trust Store
IDP HTTP redirect idpHttpRedirect Boolean false Indicates if an HTTP Redirect to the IDP URL instead of sending an AuthnRequest. Set to true for IDP initiated authentication.
IDP identifier idpIdentifier String Unique IDP Id to ensure AEM user and group uniqueness. If empty, the serviceProviderEntityId is used instead.
Assertion consumer service URL assertionConsumerServiceURL String The AssertionConsumerServiceURL URL attribute in the AuthnRequest specifying where the <Response> message must be sent to AEM.
SP entity Id serviceProviderEntityId String Uniquely identifies AEM to the IDP; usually the AEM host name.
SP encryption useEncryption Boolean true Indicates if the IDP encrypts SAML assertions. Requires spPrivateKeyAlias and keyStorePassword to be set.
SP private key alias spPrivateKeyAlias String The alias of the private key in the authentication-service user’s key store. Required if useEncryption is set to true.
SP key store password keyStorePassword String The password of ‘authentication-service’ user’s keys store. Required if useEncryption is set to true.
Default redirect defaultRedirectUrl String / The default redirect URL after successful authentication. Can be relative to the AEM host (for example, /content/wknd/us/en/html).
User Id attribute userIDAttribute String uid The name of the SAML assertion attribute containing the user ID of the AEM user. Leave empty to use the Subject:NameId.
Auto-create AEM users createUser Boolean true Indicates if AEM users are created on successful authentication.
AEM user intermediate path userIntermediatePath String When creating AEM users, this value is used as the intermediate path (for example, /home/users/<userIntermediatePath>/jane@wknd.com). Requires createUser to be set to true.
AEM user attributes synchronizeAttributes String array List of SAML attribute mappings to store on the AEM user, in the format [ "saml-attribute-name=path/relative/to/user/node" ] (for example, [ "firstName=profile/givenName" ]). See the full list of native AEM attributes.
Add user to AEM groups addGroupMemberships Boolean true Indicates if an AEM user is automatically added to AEM user groups after successful authentication.
AEM group membership attribute groupMembershipAttribute String groupMembership The name of the SAML assertion attribute containing a list of AEM user groups the user should be added to. Requires addGroupMemberships to be set to true.
Default AEM groups defaultGroups String array A list of AEM user groups authenticated users are always added to (for example, [ "wknd-user" ]). Requires addGroupMemberships to be set to true.
NameIDPolicy Format nameIdFormat String urn:oasis:names:tc:SAML:2.0:nameid-format:transient The value of the NameIDPolicy format parameter to send in the AuthnRequest message.
Store SAML response storeSAMLResponse Boolean false Indicates if the samlResponse value is stored on the AEM cq:User node.
Handle logout handleLogout Boolean false Indicates if logout request is handled by this SAML authentication handler. Requires logoutUrl to be set.
Logout URL logoutUrl String IDP’s URL where the SAML logout request is sent to. Required if handleLogout is set to true.
Clock tolerance clockTolerance Integer 60 IDP and AEM (SP) clock skew tolerance when validating SAML assertions.
Digest method digestMethod String http://www.w3.org/2001/04/xmlenc#sha256 The digest algorithm that the IDP uses when signing a SAML message.
Signature method signatureMethod String http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 The signature algorithm that the IDP uses when signing a SAML message.
Identity sync type identitySyncType default or idp default Do not change from default for AEM as a Cloud Service.
Service ranking service.ranking Integer 5002 Higher ranking configurations are preferred for the same path.

AEM user attributes

AEM uses the following user attributes, which can be populated via the synchronizeAttributes property in the Adobe Granite SAML 2.0 Authentication Handler OSGi configuration. Any IDP attributes can be synchronized to any AEM user property, however mapping to AEM use attribute properties (listed below) allows AEM to naturally use them.

User attribute Relative property path from rep:User node
Title (for example, Mrs) profile/title
Given name (i.e. first name) profile/givenName
Family name (i.e. last name) profile/familyName
Job title profile/jobTitle
Email address profile/email
Street address profile/street
City profile/city
Postal code profile/postalCode
Country profile/country
Phone number profile/phoneNumber
About me profile/aboutMe
  1. Create an OSGi configuration file in your project at /ui.config/src/main/content/jcr_root/wknd-examples/osgiconfig/config.publish/com.adobe.granite.auth.saml.SamlAuthenticationHandler~saml.cfg.json and open in your IDE.

    • Change /wknd-examples/ to your /<project name>/
    • The identifier after the ~ in the filename should uniquely identify this configuration, so it may be the name of the IDP, such as ...~okta.cfg.json. The value should be alphanumeric with hyphens.
  2. Paste the following JSON into the com.adobe.granite.auth.saml.SamlAuthenticationHandler~...cfg.json file, and update the wknd references as needed.

    {
        "path": [ "/content/wknd", "/content/dam/wknd" ],
        "idpCertAlias": "$[env:SAML_IDP_CERT_ALIAS;default=certalias___1652125559800]",
        "idpIdentifier": "$[env:SAML_IDP_ID;default=http://www.okta.com/exk4z55r44Jz9C6am5d7]",
        "idpUrl": "$[env:SAML_IDP_URL;default=https://dev-5511372.okta.com/app/dev-5511372_aemasacloudservice_1/exk4z55r44Jz9C6am5d7/sso/saml]",
        "serviceProviderEntityId": "$[env:SAML_AEM_ID;default=https://publish-p123-e456.adobeaemcloud.com]",
        "useEncryption": false,
        "createUser": true,
        "userIntermediatePath": "wknd/idp",
        "synchronizeAttributes":[
            "firstName=profile/givenName"
        ],
        "addGroupMemberships": true,
        "defaultGroups": [
            "wknd-users"
        ]
    }
    
  3. Update the values as required by your project. See the SAML 2.0 Authentication Handler OSGi configuration glossary above for configuration property descriptions

  4. It is recommended, but not required, to use OSGi environment variables and secrets, when values may change out of sync with the release cycle, or when the values different between similar environment types/service tiers. Default values can be set using the $[env:..;default=the-default-value]" syntax as shown above.

OSGi configurations per environment (config.publish.dev, config.publish.stage, and config.publish.prod) can be defined with specific attributes if the SAML configuration varies between environments.

Use encryption

When encrypting the AuthnRequest and SAML assertion, the following properties are required: useEncryption, spPrivateKeyAlias, and keyStorePassword. The keyStorePassword contains a password therefore the value must not be stored in the OSGi configuration file, but rather injected using secret configuration values

 Optionally, update the OSGi configuration to use encryption
  1. Open /ui.config/src/main/content/jcr_root/wknd-examples/osgiconfig/config.publish/com.adobe.granite.auth.saml.SamlAuthenticationHandler~saml.cfg.json in your IDE.

  2. Add the three properties useEncryption, spPrivateKeyAlias, and keyStorePassword as shown below.

    {
    "path": [ "/content/wknd", "/content/dam/wknd" ],
    "idpCertAlias": "$[env:SAML_IDP_CERT_ALIAS;default=certalias___1234567890]",
    "idpIdentifier": "$[env:SAML_IDP_ID;default=http://www.okta.com/abcdef1235678]",
    "idpUrl": "$[env:SAML_IDP_URL;default=https://dev-5511372.okta.com/app/dev-123567890_aemasacloudservice_1/abcdef1235678/sso/saml]",
    "serviceProviderEntityId": "$[env:SAML_AEM_ID;default=https://publish-p123-e456.adobeaemcloud.com]",
    "useEncryption": true,
    "spPrivateKeyAlias": "$[env:SAML_AEM_KEYSTORE_ALIAS;default=aem-saml-encryption]",
    "keyStorePassword": "$[secret:SAML_AEM_KEYSTORE_PASSWORD]",
    "createUser": true,
    "userIntermediatePath": "wknd/idp"
    "synchronizeAttributes":[
        "firstName=profile/givenName"
    ],
    "addGroupMemberships": true,
    "defaultGroups": [
        "wknd-users"
    ]
    }
    
  3. The three OSGi configuration properties required for encryption are:

  • useEncryption set to true
  • spPrivateKeyAlias contains the keystore entry alias for the private key used by the SAML integration.
  • keyStorePassword contains an OSGi secret configuration variable containing the authentication-service user keystore’s password.

Configure Referrer filter

During the SAML authentication process, the IDP initiates a client-side HTTP POST to AEM Publish’s .../saml_login end point. If the IDP and AEM Publish exist on different origin, AEM Publish’s Referrer Filter is configured via OSGi configuration to allow HTTP POSTs from the IDP’s origin.

  1. Create (or edit) an OSGi configuration file in your project at /ui.config/src/main/content/jcr_root/wknd-examples/osgiconfig/config.publish/org.apache.sling.security.impl.ReferrerFilter.cfg.json.

    • Change /wknd-examples/ to your /<project name>/
  2. Ensure the allow.empty value is set to true, the allow.hosts (or if you prefer, allow.hosts.regexp) contains the IDP’s origin, and filter.methods includes POST. The OSGi configuration should be similar to:

    {
        "allow.empty": true,
        "allow.hosts.regexp": [ ],
        "allow.hosts": [
            "$[env:SAML_IDP_REFERRER;default=dev-123567890.okta.com]"
        ],
        "filter.methods": [
            "POST",
        ],
        "exclude.agents.regexp": [ ]
    }
    

AEM Publish supports a single Referrer filter configuration, so merge the SAML configuration requirements, with any existing configurations.

OSGi configurations per environment (config.publish.dev, config.publish.stage, and config.publish.prod) can be defined with specific attributes if the allow.hosts (or allow.hosts.regex) vary between environments.

Configure Cross-Origin Resource Sharing (CORS)

During the SAML authentication process, the IDP initiates a client-side HTTP POST to AEM Publish’s .../saml_login end point. If the IDP and AEM Publish exist on different hosts/domains, AEM Publish’s CRoss-Origin Resource Sharing (CORS) must be configured to allow HTTP POSTs from the IDP’s host/domain.

This HTTP POST request’s Origin header usually has a different value than the AEM Publish host, thus requiring CORS configuration.

When testing SAML authentication on the local AEM SDK (localhost:4503), the IDP may set the Origin header to null. If so, add "null" to the alloworigin list.

  1. Create an OSGi configuration file in your project at /ui.config/src/main/content/jcr_root/wknd-examples/osgiconfig/config.publish/com.adobe.granite.cors.impl.CORSPolicyImpl~saml.cfg.json
    • Change /wknd-examples/ to your project name
    • The identifier after the ~ in the filename should uniquely identify this configuration, so it may be the name of the IDP, such as ...CORSPolicyImpl~okta.cfg.json. The value should be alphanumeric with hyphens.
  2. Paste the following JSON into the com.adobe.granite.cors.impl.CORSPolicyImpl~...cfg.json file.
{
    "alloworigin": [
        "$[env:SAML_IDP_ORIGIN;default=https://dev-1234567890.okta.com]",
        "null"
    ],
    "allowedpaths": [
        ".*/saml_login"
    ],
    "supportedmethods": [
        "POST"
    ]
}

OSGi configurations per environment (config.publish.dev, config.publish.stage, and config.publish.prod) can be defined with specific attributes if the alloworigin and allowedpaths varies between environments.

Configure AEM Dispatcher to allow SAML HTTP POSTs

After successful authentication to the IDP, the IDP will orchestrate an HTTP POST back to AEM’s registered /saml_login end point (configured in the IDP). This HTTP POST to /saml_login is blocked by default at Dispatcher, so it must be explicitly allowed using the following Dispatcher rule:

  1. Open dispatcher/src/conf.dispatcher.d/filters/filters.any in your IDE.
  2. Add to the bottom of the file, an allow rule for HTTP POSTs to URLs that end with /saml_login.
...

# Allow SAML HTTP POST to ../saml_login end points
/0190 { /type "allow" /method "POST" /url "*/saml_login" }

If URL rewriting at the Apache webserver is configured (dispatcher/src/conf.d/rewrites/rewrite.rules), ensure that requests to the .../saml_login end points are not accidentally mangled.

Enable data synchronization and encapsulate tokens

Once the SAML authentication flow creates a user in AEM Publish, the AEM user node authenticatable across the AEM Publish service tier.
This requires data synchronization and encapsulated tokens to be enabled by Adobe Support on the AEM Publish service.

Send a request to Adobe Customer Support (via AdminConsole > Support) requesting:

Data synchronization and encapsulated tokens are enabled on AEM Publish service for Program X and Environment Y.

Deploying SAML configuration

The OSGi configurations must be committed to Git and deployed to AEM as a Cloud Service using Cloud Manager.

$ git remote -v
adobe   https://git.cloudmanager.adobe.com/myOrg/myCloudManagerGit/ (fetch)
adobe   https://git.cloudmanager.adobe.com/myOrg/myCloudManagerGit/ (push)
$ git add .
$ git commit -m "SAML 2.0 configurations"
$ git push adobe saml-auth:develop

Deploy the target Cloud Manager Git branch (in this example, develop), using a Full Stack deployment pipeline.

On this page