PingGateway 2025.3

Proxy Connect

With Proxy Connect, PingOne Advanced Identity Cloud provides a way to secure traffic to your tenant environments in seamless compliance with the security controls you apply to your company’s other network resources.

You use Proxy Connect rules to restrict access to a PingOne Advanced Identity Cloud tenant environment based on an IP address range or a required security header. If the request matches any of the rules, Proxy Connect lets the request through. If not, PingOne Advanced Identity Cloud responds with HTTP 404 Not Found. This affects the PingOne Advanced Identity Cloud UIs, too, as Proxy Connect prevents browser requests that don’t follow the rules.

For externally facing applications, Proxy Connect works well with a web application firewall (WAF). A WAF protects against distributed denial-of-service, cross-site scripting, and injection attacks. The WAF isn’t application-specific and so doesn’t make application-specific decisions.

Requests from PingGateway can go through the WAF, but they don’t always need to.

When PingGateway redirects the browser to an end-user UI page, such as the sign-on page, target the WAF. There’s nothing special to do in PingGateway other than redirect to the WAF instead of the tenant. This includes the following use cases, where you let the WAF add the required security header to the browser and PingGateway requests:

  • SSO and CDSSO

  • SAML v2.0

  • OpenID Connect

  • Step-up and transactional authorization where a policy can return advices

When PingGateway uses PingOne Advanced Identity Cloud APIs directly without redirecting the browser, you can skip the WAF. This includes headless interactions that involve direct REST requests, not redirects, where you let PingGateway decorate requests with the required security header:

Goals

The following example builds on the OAuth 2.0 use case.

It shows how to decorate requests to PingOne Advanced Identity Cloud with a security header for Proxy Connect.

Prerequisites

Tasks

Task 1: Configure an OAuth 2.0 profile

Configure an OAuth 2.0 client profile for PingGateway as a resource server:

  1. Sign on to the Advanced Identity Cloud admin UI as an administrator.

  2. Go to Applications > + Custom Application > OIDC - OpenId Connect > Web and add a web application with the following settings:

    Name

    oauth2-client

    Owners

    demo user

    Client Secret

    password

    Sign On > Grant Types

    Add Resource Owner Password Credentials

    Sign On > Scopes

    Add mail

Task 2: Configure PingGateway

  1. Configure PingGateway for HTTPS.

  2. Set an environment variable for the base64-encoded PingGateway agent password.

    The following command sets the variable to a base64-encoding of the string password.

    $ export AGENT_SECRET_ID='cGFzc3dvcmQ='

    A SystemAndEnvSecretStore in the route that follows reads the base64-encoded password.

  3. Restart PingGateway to reload admin.json and access the agent password.

  4. Add a route for token introspection that decorates requests with the security header.

    $HOME/.openig/config/routes/proxy-connect.json
    Show route
    {
      "name": "proxy-connect",
      "condition": "${find(request.uri.path, '^/proxy-connect')}",
      "properties": {
        "gatewayUsername": "ig_agent",
        "gatewayPasswordSecretId": "agent.secret.id",
        "amServiceUrl": "https://myTenant.forgeblocks.com/am"
      },
      "heap": [
        {
          "name": "SystemAndEnvSecretStore-1",
          "type": "SystemAndEnvSecretStore"
        },
        {
          "name": "SecurityHeaderFilter",
          "type": "HeaderFilter",
          "config": {
            "messageType": "REQUEST",
            "add": {
              "X-Security-Header": [
                "f1drybngmzqj5loposddd5p98z886jp9"
              ]
            },
            "_comment": "The Proxy Connect rule you configure matches this header."
          },
          "capture": "filtered_request"
        },
        {
          "name": "AmService-1",
          "type": "AmService",
          "config": {
            "url": "&{amServiceUrl}",
            "realm": "/alpha",
            "agent": {
              "username": "&{gatewayUsername}",
              "passwordSecretId": "&{gatewayPasswordSecretId}"
            },
            "secretsProvider": "SystemAndEnvSecretStore-1",
            "amHandler": {
              "type": "Chain",
              "config": {
                "filters": [
                  "SecurityHeaderFilter"
                ],
                "handler": "ForgeRockClientHandler"
              }
            },
            "notifications": {
              "_comment": "Avoid UpgradeRejectedException: WebSocket upgrade failure: 404",
              "enabled": false
            }
          }
        }
      ],
      "handler": {
        "type": "Chain",
        "config": {
          "filters": [
            {
              "name": "OAuth2ResourceServerFilter-1",
              "type": "OAuth2ResourceServerFilter",
              "config": {
                "scopes": [
                  "mail"
                ],
                "requireHttps": false,
                "accessTokenResolver": {
                  "name": "TokenIntrospectionAccessTokenResolver-1",
                  "type": "TokenIntrospectionAccessTokenResolver",
                  "config": {
                    "amService": "AmService-1",
                    "providerHandler": {
                      "type": "Chain",
                      "config": {
                        "filters": [
                          "SecurityHeaderFilter",
                          {
                            "type": "HttpBasicAuthenticationClientFilter",
                            "config": {
                              "username": "&{gatewayUsername}",
                              "passwordSecretId": "&{gatewayPasswordSecretId}",
                              "secretsProvider": "SystemAndEnvSecretStore-1"
                            }
                          }
                        ],
                        "handler": "ForgeRockClientHandler"
                      }
                    }
                  }
                }
              }
            }
          ],
          "handler": {
            "type": "StaticResponseHandler",
            "config": {
              "status": 200,
              "headers": {
                "Content-Type": [
                  "text/html; charset=UTF-8"
                ]
              },
              "entity": "<html><body><h2>Decoded access_token: ${contexts.oauth2.accessToken.info}</h2></body></html>"
            }
          }
        }
      }
    }
    json

    The Proxy Connect route:

  5. Update the route’s amServiceUrl setting to target the PingOne Advanced Identity Cloud tenant and save your work.

    PingGateway loads the route.

Task 3: Pre-validation

Before you add Proxy Connect rules to restrict access, verify the route works without restrictions.

  1. Get an access token using the resource owner password credentials flow:

    $ export ACCESS_TOKEN=$(curl \
    --request POST 'https://myTenant.forgeblocks.com/am/oauth2/realms/alpha/access_token' \
    --user 'oauth2-client:password' \
    --data 'grant_type=password' \
    --data 'username=demo' \
    --data 'password=Ch4ng3!t' \
    --data 'scope=mail' \
    --silent | jq -r ".access_token")

    You don’t need the security header until you configure a Proxy Connect header rule.

  2. Use the route to introspect the access token:

    $ curl \
    --request GET 'https://ig.example.com:8443/proxy-connect' \
    --insecure \
    --header "Authorization: Bearer ${ACCESS_TOKEN}"
    Output
    <html><body><h2>Decoded access_token:
    {active=true,
    scope=mail,
    realm=/alpha,
    client_id=oauth2-client,
    user_id=<uuid>,
    username=<uuid>,
    token_type=Bearer,
    exp=<seconds>,
    sub=<uuid>,
    iss=https://myTenant.forgeblocks.com:443/am/oauth2/realms/root/realms/alpha,
    subname=<uuid>,
    auth_level=0,
    authGrantId=<id>,
    auditTrackingId=<uuid>,
    expires_in=<seconds>}</h2></body></html>

Task 4: Set a Proxy Connect rule

Learn about this in the Proxy Connect documentation. Once you understand the steps:

  1. Configure a Proxy Connect rule to require the following security header, which is the same one set in the Proxy Connect route configuration:

    'X-Security-Header: f1drybngmzqj5loposddd5p98z886jp9'

    When you first update the header rules, the change is pending ("requestStatus": "PENDING"). PingOne Advanced Identity Cloud doesn’t check for the security header when the update is still pending.

  2. Poll the Proxy Connection configuration in PingOne Advanced Identity Cloud until the request has "requestStatus": "SUCCESS".

    Once the request is successful, you can’t use the Advanced Identity Cloud admin UI. Your browser doesn’t add the security header by default.

    If you must use the Advanced Identity Cloud admin UI again, either reset the header rules to {"enabled": false, "headers": []} or configure your browser to add the security header.

Validation

  1. Get an access token using the resource owner password credentials flow:

    $ export ACCESS_TOKEN=$(curl \
    --request POST 'https://myTenant.forgeblocks.com/am/oauth2/realms/alpha/access_token' \
    --user 'oauth2-client:password' \
    --data 'grant_type=password' \
    --data 'username=demo' \
    --data 'password=Ch4ng3!t' \
    --data 'scope=mail' \
    --header 'X-Security-Header: f1drybngmzqj5loposddd5p98z886jp9' \
    --silent | jq -r ".access_token")
  2. Use the route to introspect the access token:

    $ curl \
    --request GET 'https://ig.example.com:8443/proxy-connect' \
    --insecure \
    --header "Authorization: Bearer ${ACCESS_TOKEN}"
    Output
    <html><body><h2>Decoded access_token:
    {active=true,
    scope=mail,
    realm=/alpha,
    client_id=oauth2-client,
    user_id=<uuid>,
    username=<uuid>,
    token_type=Bearer,
    exp=<seconds>,
    sub=<uuid>,
    iss=https://myTenant.forgeblocks.com:443/am/oauth2/realms/root/realms/alpha,
    subname=<uuid>,
    auth_level=0,
    authGrantId=<id>,
    auditTrackingId=<uuid>,
    expires_in=<seconds>}</h2></body></html>
  3. In the PingGateway log, notice the filtered requests have the security header:

    [CONTINUED]--- (filtered-request) exchangeId:<uuid> - transactionId:<uuid> --->
    
    [CONTINUED]POST https://myTenant.forgeblocks.com/am/oauth2/realms/root/realms/alpha/introspect HTTP/1.1
    [CONTINUED]Accept: application/json
    [CONTINUED]Content-Length: 918
    [CONTINUED]Content-Type: application/x-www-form-urlencoded
    [CONTINUED]X-Security-Header: f1drybngmzqj5loposddd5p98z886jp9
    
    [CONTINUED]token=<token>&token_type_hint=access_token

    Change "capture" to "_capture" in the Proxy Connect route to avoid flooding the PingGateway logs.

You’ve successfully shown how to use PingGateway with Proxy Connect.