Set Up SAML 2.0 SSO and Federation

For examples of the federation configuration files, see "Example Fedlet Files". To set up multiple SPs, work through this section, and then SAML 2.0 and Multiple Applications.

  1. Set up the network:

    1. Add sp.example.com to your /etc/hosts file:

      127.0.0.1 localhost openam.example.com openig.example.com app.example.com sp.example.com

      Traffic to the application is proxied through IG, using the host name sp.example.com.

  2. Configure a Java Fedlet:

    For more information about Java Fedlets, see Creating and Configuring the Fedlet in AM's SAML v2.0 Guide.

    1. Copy and unzip the fedlet zip file, Fedlet-7.0.1.zip, delivered with the AM installation, into a local directory.

      $ unzip $HOME/openam/Fedlet-7.0.1.zip
      Archive:  Fedlet-7.0.0-SNAPSHOT.zip
      creating: conf/
      inflating: README
      inflating: conf/FederationConfig.properties
      inflating: conf/fedlet.cot-template
      inflating: conf/idp-extended.xml-template
      inflating: conf/sp-extended.xml-template
      inflating: conf/sp.xml-template
      inflating: fedlet.war
    2. For AM 6.5.2 and earlier versions, add the following lines to FederationConfig.properties:

      # Specifies implementation for
      # org.forgerock.openam.federation.plugin.rooturl.RootUrlProvider interface.
      # This property defines the default base url provider.
      com.sun.identity.plugin.root.url.class.default=org.forgerock.openam.federation.plugin.rooturl.impl.FedletRootUrlProvider
    3. In each file, search and replace the following properties:

      • IDP_ENTITY_ID: replace with openam

      • FEDLET_ENTITY_ID: replace with sp

      • FEDLET_PROTOCOL://FEDLET_HOST:FEDLET_PORT/FEDLET_DEPLOY_URI: replace with http://sp.example.com:8080/saml

      • fedletcot and FEDLET_COT: replace with Circle of Trust

      • sp.example.com:8080/saml/fedletapplication: replace with sp.example.com:8080/saml/fedletapplication/metaAlias/sp

    4. Save the files as .xml, without the -template extension.

    By default, AM as an IDP uses the NameID format urn:oasis:names:tc:SAML:2.0:nameid-format:transient to communicate about a user. For information about using a different NameID format, see "Using a Non-Transient NameID Format".

  3. Set up AM:

    1. Select Identities, and add a user with the following values:

      • ID/username: george

      • First name: george

      • Last name: C0stanza

        Note that, for this example, the last name must be the same as the password.

      • Password: C0stanza

    2. Select Applications > Federation > Circles of Trust, and add a circle of trust called Circle of Trust, with the default settings.

    3. Set up a remote service provider:

      1. Select Applications > Federation > Entity Providers, and add a remote entity provider.

      2. Drag in or import sp.xml created in Step 2.

      3. Select Circles of Trust: Circle of Trust

    4. Set up a hosted identity provider:

      1. Select Applications > Federation > Entity Providers, and add a hosted entity provider with the following values:

        • Entity ID: openam

        • Entity Provider Base URL: http://openam.example.com:8088/openam

        • Identity Provider Meta Alias: idp

        • Circles of Trust: Circle of Trust

      2. Select Assertion Processing > Attribute Mapper, map the following SAML attribute keys and values, and then save your changes:

        • SAML Attribute: cn, Local Attribute: cn

        • SAML Attribute: sn, Local Attribute: sn

      3. In a terminal, export the XML-based metadata for the IPD:

        $ curl -v \
        --output idp.xml \
        "http://openam.example.com:8088/openam/saml2/jsp/exportmetadata.jsp?entityid=openam"

        The idp.xml file is created locally.

  4. Set up IG:

    1. Retrieve the Fedlet configuration files:

      1. Copy the edited fedlet files, and the exported idp.xml file into the IG configuration, at $HOME/.openig/SAML.

        $ ls -l $HOME/.openig/SAML
        FederationConfig.properties
        fedlet.cot
        idp-extended.xml
        idp.xml
        sp-extended.xml
        sp.xml
    2. In config.json, comment out or remove the baseURI:

      {
        "handler": {
          "_baseURI": "http://app.example.com:8081",
          ...

      Requests to the SamlFederationHandler must not be rebased, because the request URI must match the endpoint in the SAML metadata.

    3. Add the following route to IG, to serve .css and other static resources for the sample application:

      $HOME/.openig/config/routes/static-resources.json
      %appdata%\OpenIG\config\routes\static-resources.json
      {
        "name" : "sampleapp_resources",
        "baseURI" : "http://app.example.com:8081",
        "condition": "${matches(request.uri.path,'^/css')}",
        "handler": "ReverseProxyHandler"
      }
    4. Add the following route to IG:

      $HOME/.openig/config/routes/saml.json
      %appdata%\OpenIG\config\routes\saml.json
      {
        "name": "saml",
        "condition": "${matches(request.uri.path, '^/saml')}",
        "session": "JwtSession",
        "handler": {
          "type": "SamlFederationHandler",
          "config": {
            "assertionMapping": {
              "username": "cn",
              "password": "sn"
            },
            "subjectMapping": "sp-subject-name",
            "redirectURI": "/home/federate"
          }
        }
      }
      

      Notice the following features of the route:

      • The route matches requests to /saml.

      • After authentication, the SamlFederationHandler extracts cn and sn from the SAML assertion, and maps them to the SessionContext, at session.username and session.password.

      • The handler stores the subject name as a string in the session field session.sp-subject-name, which is named by the subjectMapping property. By default, the subject name is stored in the session field session.subjectName.

      • The handler redirects the request to the /federate route.

      • The route uses the JwtSession implementation, meaning it stores encrypted session information in a browser cookie. The name is a reference to the JwtSession object defined in config.json. For details, see "JwtSession".

    5. Add the following route to IG:

      $HOME/.openig/config/routes/federate.json
      %appdata%\OpenIG\config\routes\federate.json
      {
        "name": "federate",
        "condition": "${matches(request.uri.path, '^/home/federate')}",
        "session": "JwtSession",
        "baseURI": "http://app.example.com:8081",
        "handler": {
          "type": "DispatchHandler",
          "config": {
            "bindings": [
              {
                "condition": "${empty session.username}",
                "handler": {
                  "type": "StaticResponseHandler",
                  "config": {
                    "status": 302,
                    "reason": "Found",
                    "headers": {
                      "Location": [
                        "http://sp.example.com:8080/saml/SPInitiatedSSO?metaAlias=/sp"
                      ]
                    }
                  }
                }
              },
              {
                "handler": {
                  "type": "Chain",
                  "config": {
                    "filters": [
                      {
                        "type": "HeaderFilter",
                        "config": {
                          "messageType": "REQUEST",
                          "add": {
                            "x-username": ["${session.username[0]}"],
                            "x-password": ["${session.password[0]}"]
                          }
                        }
                      }
                    ],
                    "handler": "ReverseProxyHandler"
                  }
                }
              }
            ]
          }
        }
      }
      

      Notice the following features of the route:

      • The route matches requests to /home/federate.

      • If the user is not authenticated with AM, the username is not populated in the context. The DispatchHandler then dispatches the request to the StaticResponseHandler, which redirects it to the SP-initiated SSO endpoint.

        If the credentials are in the context, or after successful authentication, the DispatchHandler dispatches the request to the Chain.

      • The HeaderFilter adds headers for the first value for the username and password attributes of the SAML assertion.

      • The route uses the JwtSession implementation, meaning it stores encrypted session information in a browser cookie. The name is a reference to the JwtSession object defined in config.json. For details, see "JwtSession".

      Tip

      For more control over the URL where the user agent is redirected, use the RelayState query string parameter in the URL of the redirect Location header. RelayState specifies where to redirect the user when the SAML 2.0 web browser SSO process is complete. It overrides the redirectURI set in the SamlFederationHandler.

      The RelayState value must be URL-encoded. When using an expression, use a function to encode the value. For example, use ${urlEncodeQueryParameterNameOrValue(contexts.router.originalUri)}.

      In the following example, the user is finally redirected to the original URI from the request:

      "headers": {
        "Location": [
          "http://openig.example.com:8080/saml/SPInitiatedSSO?RelayState=${urlEncodeQueryParameterNameOrValue(contexts.router.originalUri)}"
        ]
      }
    6. Restart IG.

  5. Test the setup:

    1. Log out of AM, and test the setup with the following links:

    2. Log in to AM with username george and password C0stanza.

      IG returns the response page showing that the George has logged in.

Read a different version of :