PingGateway 2024.9

Pass runtime data downstream in a JWT

This example sets up PingOne Advanced Identity Cloud as an identity provider, to pass identity or other runtime information downstream, in a JWT signed with a PEM.

For more information about using runtime data, refer to Pass data along the chain. To help with development, the sample application includes a /jwt endpoint to display the JWT, verify its signature, and decrypt it.

Before you start, prepare PingOne Advanced Identity Cloud, PingGateway, and the sample application as described in Example installation for this guide.

  1. Set up secrets:

    1. Locate a directory for secrets, and go to it:

      $ cd /path/to/secrets
    2. Create the following secret key and certificate pair as PEM files:

      $ openssl req \
      -newkey rsa:2048 \
      -new \
      -nodes \
      -x509 \
      -days 3650 \
      -subj "/CN=ig.example.com/OU=example/O=com/L=fr/ST=fr/C=fr" \
      -keyout ig.example.com-key.pem \
      -out ig.example.com-certificate.pem

      Two PEM files are created, one for the secret key, and another for the associated certificate.

    3. Map the key and certificate to the same secret ID in PingGateway:

      $ cat ig.example.com-key.pem ig.example.com-certificate.pem > key.manager.secret.id.pem
    4. Generate PEM files to sign and verify the JWT:

      $ openssl req \
      -newkey rsa:2048 \
      -new \
      -nodes \
      -x509 \
      -days 3650 \
      -subj "/CN=ig.example.com/OU=example/O=com/L=fr/ST=fr/C=fr" \
      -keyout id.key.for.signing.jwt.pem \
      -out id.key.for.verifying.jwt.pem
    5. Make sure the following files have been added to your secrets directory:

      • id.key.for.signing.jwt.pem

      • id.key.for.verifying.jwt.pem

      • key.manager.secret.id.pem

      • ig.example.com-certificate.pem

      • ig.example.com-key.pem

  2. Set up PingOne Advanced Identity Cloud:

    1. Log in to the PingOne Advanced Identity Cloud admin UI as an administrator.

    2. Go to group Identities > Manage > settings_system_daydream Alpha realm - Users, and add a user with the following values:

      • Username: demo

      • First name: demo

      • Last name: user

      • Email Address: demo@example.com

      • Password: Ch4ng3!t

    3. Register a PingGateway agent with the following values, as described in Register a PingGateway agent in PingOne Advanced Identity Cloud:

      • ID: ig_agent_jwt

      • Password: password

      • Redirect URLs: https://ig.example.com:8443/jwt/redirect

    4. (Optional) Authenticate a PingGateway agent to PingOne Advanced Identity Cloud.

      PingGateway agents are automatically authenticated to PingOne Advanced Identity Cloud by a deprecated authentication module in PingOne Advanced Identity Cloud. This step is currently optional, but will be required when authentication chains and modules are removed in a future release of PingOne Advanced Identity Cloud.
    5. Add a Validation Service:

      1. In PingOne Advanced Identity Cloud, select open_in_new Native Consoles > Access Management. The AM admin UI is displayed.

      2. Select Services, and add a validation service with the following Valid goto URL Resources:

        • https://ig.example.com:8443/*

        • https://ig.example.com:8443/*?*

  3. Set up PingGateway:

    1. Set up TLS by adding the following file to PingGateway, replacing the value for the property secretsDir:

      • Linux

      • Windows

      $HOME/.openig/config/admin.json
      %appdata%\OpenIG\config\admin.json
      {
        "mode": "DEVELOPMENT",
        "properties": {
          "secretsDir": "/path/to/secrets"
        },
        "connectors": [
          {
            "port": 8080
          },
          {
            "port": 8443,
            "tls": "ServerTlsOptions-1"
          }
        ],
        "session": {
          "cookie": {
            "sameSite": "none",
            "secure": true
          }
        },
        "heap": [
          {
            "name": "ServerTlsOptions-1",
            "type": "ServerTlsOptions",
            "config": {
              "keyManager": {
                "type": "SecretsKeyManager",
                "config": {
                  "signingSecretId": "key.manager.secret.id",
                  "secretsProvider": "ServerIdentityStore"
                }
              }
            }
          },
          {
            "name": "ServerIdentityStore",
            "type": "FileSystemSecretStore",
            "config": {
              "format": "PLAIN",
              "directory": "&{secretsDir}",
              "suffix": ".pem",
              "mappings": [{
                "secretId": "key.manager.secret.id",
                "format": {
                  "type": "PemPropertyFormat"
                }
              }]
            }
          }
        ]
      }
    2. Set an environment variable for the PingGateway agent password, and then restart PingGateway:

      $ export AGENT_SECRET_ID='cGFzc3dvcmQ='

      The password is retrieved by a SystemAndEnvSecretStore, and must be base64-encoded.

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

      • Linux

      • Windows

      $HOME/.openig/config/routes/00-static-resources.json
      %appdata%\OpenIG\config\routes\00-static-resources.json
      {
        "name" : "00-static-resources",
        "baseURI" : "http://app.example.com:8081",
        "condition": "${find(request.uri.path,'^/css') or matchesWithRegex(request.uri.path, '^/.*\\\\.ico$') or matchesWithRegex(request.uri.path, '^/.*\\\\.gif$')}",
        "handler": "ReverseProxyHandler"
      }
    4. Add the following route to PingGateway, replacing the value for the properties secretsDir and amInstanceUrl:

      • Linux

      • Windows

      $HOME/.openig/config/routes/jwt-idc.json
      %appdata%\OpenIG\config\routes\jwt-idc.json
      {
        "name": "jwt-idc",
        "condition": "${find(request.uri.path, '/jwt')}",
        "baseURI": "http://app.example.com:8081",
        "properties": {
          "secretsDir": "/path/to/secrets",
          "amInstanceUrl": "https://myTenant.forgeblocks.com/am"
        },
        "heap": [
          {
            "name": "SystemAndEnvSecretStore-1",
            "type": "SystemAndEnvSecretStore"
          },
          {
            "name": "AmService-1",
            "type": "AmService",
            "config": {
              "url": "&{amInstanceUrl}",
              "realm": "/alpha",
              "agent": {
                "username": "ig_agent_jwt",
                "passwordSecretId": "agent.secret.id"
              },
              "secretsProvider": "SystemAndEnvSecretStore-1",
              "sessionCache": {
                "enabled": false
              }
            }
          },
          {
            "name": "pemPropertyFormat",
            "type": "PemPropertyFormat"
          },
          {
            "name": "FileSystemSecretStore-1",
            "type": "FileSystemSecretStore",
            "config": {
              "format": "PLAIN",
              "directory": "&{secretsDir}",
              "suffix": ".pem",
              "mappings": [{
                "secretId": "id.key.for.signing.jwt",
                "format": "pemPropertyFormat"
              }]
            }
          }
        ],
        "handler": {
          "type": "Chain",
          "config": {
            "filters": [
              {
                "name": "CrossDomainSingleSignOnFilter-1",
                "type": "CrossDomainSingleSignOnFilter",
                "config": {
                  "redirectEndpoint": "/jwt/redirect",
                  "authCookie": {
                    "path": "/jwt",
                    "name": "ig-token-cookie"
                  },
                  "amService": "AmService-1"
                }
              },
              {
                "name": "UserProfileFilter",
                "type": "UserProfileFilter",
                "config": {
                  "username": "${contexts.ssoToken.info.uid}",
                  "userProfileService": {
                    "type": "UserProfileService",
                    "config": {
                      "amService": "AmService-1"
                    }
                  }
                }
              },
              {
                "name": "JwtBuilderFilter-1",
                "type": "JwtBuilderFilter",
                "config": {
                  "template": {
                    "name": "${contexts.userProfile.commonName}",
                    "email": "${contexts.userProfile.rawInfo.mail[0]}"
                  },
                  "secretsProvider": "FileSystemSecretStore-1",
                  "signature": {
                    "secretId": "id.key.for.signing.jwt",
                    "algorithm": "RS512"
                  }
                }
              },
              {
                "name": "HeaderFilter-1",
                "type": "HeaderFilter",
                "config": {
                  "messageType": "REQUEST",
                  "add": {
                    "x-openig-user": ["${contexts.jwtBuilder.value}"]
                  }
                }
              }
            ],
            "handler": "ReverseProxyHandler"
          }
        }
      }
  4. Test the setup:

    1. Go to https://ig.example.com:8443/jwt.

      If you receive warnings that the site is not secure, respond to the warnings to access the site. The PingOne Advanced Identity Cloud login page is displayed.

    2. Log in to PingOne Advanced Identity Cloud as user demo, password Ch4ng3!t. The sample app displays the signed JWT along with its header and payload.

    3. In USE PEM FILE, enter the absolute path to id.key.for.verifying.jwt.pem to verify the JWT signature.