PingOne Authorize integration with PingGateway
Use PingOne Authorize with PingGateway to protect APIs and web applications. When you add a PingOneApiAccessManagementFilter to a route, PingGateway requests an authorization decision from PingOne Authorize.
About the example
This example uses PingOne as the IdP and OIDC provider. It uses PingOne Authorize API access management capabilities to protect a sample application path.
When a user tries to access a sample application resource, PingGateway directs the user to PingOne for authentication. On successful authentication, PingOne issues an ID token for the user and an access token that PingGateway uses when getting an access decision from PingOne Authorize. If PingGateway was protecting an API rather than a sample application page, the access token would act as the bearer token that an OAuth 2.0 API client application provides to access the API. In this example, however, PingGateway gets the access token because it’s acting as the client application.
PingOne Authorize either grants access or denies it and then PingGateway enforces the decision from PingOne Authorize.
In this example, the decision to authorize access depends on group membership. Learn more about a similar decision to authorize access that depends on group membership in the Controlling access to specific API operations tutorial in the PingOne Authorize documentation.
Before you begin
If you haven’t already done so:
-
Install PingGateway.
-
Install the sample application.
-
Create a PingOne environment.
Learn more in the PingGateway and PingOne examples.
Configure PingOne
Complete the tasks in this section to prepare the PingOne environment for this example.
On completing these tasks, you will have:
-
A group for users who can access the sample application
-
A test user who belongs to the group
-
A test user who doesn’t belong to the group
-
PingOne Authorize enabled in the environment
-
An OIDC client profile for PingGateway to authenticate users with PingOne
-
An API gateway account for PingGateway to authenticate to PingOne Authorize
-
An API service that PingOne Authorize uses to make access decisions
-
PingOne configured to issue access tokens to PingGateway alongside ID tokens for users
Add a group who can access to the sample application
In your PingOne environment, go to Directory > Groups and add a group named Full access
.
This group’s members get access to the sample application.
Learn more in Creating a group in the PingOne documentation.
Add a test user who gets access
If you haven’t already done so, add a test user.
-
Go to Directory > Users and add a user:
-
Given Name:
Wilhelm
-
Family Name:
Wolkig
-
Username:
wolkig
-
Email:
wolkig@example.com
-
Password: Click Generate Password and record the generated password.
Learn more in the PingOne documentation on Adding a user.
-
-
In the profile for
wolkig
, add the user to theFull access
group and save your work.In this example, PingOne Authorize will grant access to the sample application based on membership in this group.
Add a test user who doesn’t get access
-
Add a second test user:
-
Given Name:
Demo
-
Family Name:
User
-
Username:
demo
-
Email:
demo@example.com
-
Password: Click Generate Password and record the generated password.
-
-
Don’t add the
demo
user to theFull access
group.The
demo
user won’t get access to the sample application.
Add a PingGateway OIDC client profile
In this example, PingGateway acts as a PingOne OIDC client (RP) where PingOne is the OIDC provider for user identities and authentication.
Follow these steps to create a PingOne OIDC web application for PingGateway:
-
Go to Applications > Applications and click + to add a new application:
-
Application Name:
oidc_client
-
Application Type:
OIDC Web App
-
-
In the application Overview, click Protocol OpenID Connect , add a redirect URI, and save your work:
-
Redirect URIs:
https://ig.example.com:8443/home/sso/callback
.
-
-
Copy the following values from the application Overview and save them somewhere convenient for later use:
-
General > Client ID
-
General > Client Secret
-
Connection Details > OIDC Discovery Endpoint
You need the values to set up PingGateway.
-
-
Enable the application.
Add an API gateway
PingGateway uses a PingOne API gateway account to authenticate to PingOne Authorize:
-
Go to Authorization > API Gateways and click +.
-
Use
PingGateway
as the Name and save your work. -
Next to Credentials, click + and copy the API gateway credential somewhere convenient for later use.
You need the credential value to set up PingGateway.
Add an API service
PingOne Authorize bases authorization decisions on an API service definition. Follow these steps to add the API service:
-
Go to Authorization > API Services and add a new API service with the following values:
-
Name:
PingGateway
-
Base URLs:
https://app.example.com:8444
(for the sample application)
https://ig.example.com:8443
(for PingGateway)
-
-
Define an operation for protected access to the sample application.
This grants users in the
Full access
group access to the sample application page at/home/sso
:-
Method:
GET
-
Paths:
/home/sso
-
Rules: The user must be a member of any of these groups:
Full access
Learn more in the PingOne Authorize documentation on Defining operations for protected actions.
-
-
Click Deploy to deploy the new API service.
Make sure PingGateway gets an access token
When you added the PingGateway API service, PingOne Authorize automatically created a corresponding PingOne resource by default. Update the resource so PingOne issues access tokens to PingGateway.
To do so, set the audience claim (aud
) to the PingGateway URL and add a scope specifically for PingGateway:
-
Go to Applications > Resources and click the
PingGateway
resource. -
Edit the following settings and save your work:
-
Audience:
https://ig.example.com:8443
-
Scopes: Click Add Scope, add Scope Name:
gateway
, and click Save.
-
-
Go to Applications > Applications and click
oidc_client
, the OIDC application for PingGateway. -
Edit Allowed Scopes, select the gateway scope checkbox, and click Save.
PingOne is now ready to issue access tokens with the scope
gateway
to PingGateway. PingGateway uses the tokens when requesting PingOne Authorize access decisions.
Configure PingGateway
-
Prepare the secrets PingGateway needs to act as an OIDC RP and an API gateway when making requests to PingOne.
Base64-encode the API gateway’s credential and the OIDC application’s client secret and set both values as environment variables:
$ export GATEWAY_SECRET_ID='<base64-encoded-api-gateway-credential>' $ export OIDC_SECRET_ID='<base64-encoded-client-secret>'
-
Restart PingGateway to read the environment variables.
-
Add the following route to PingGateway, replacing the property values to match those from the environment:
- Linux
-
$HOME/.openig/config/routes/pingone-aam.json
- Windows
-
%appdata%\OpenIG\config\routes\pingone-aam.json
{ "name": "pingone-aam", "condition": "${find(request.uri.path, '^/home/sso')}", "baseURI": "https://app.example.com:8444", "properties": { "gatewayServiceUrl": "https://http-access-api.pingone.eu/v1/environments/test-environment-id", "oidcClientId": "oidc-client-id", "oidcWellKnownEndpoint": "https://auth.pingone.eu/test-environment-id/as/.well-known/openid-configuration" }, "heap": [ { "name": "BlindTrustReverseProxyHandler", "type": "ReverseProxyHandler", "comment": "For evaluation and testing only", "config": { "tls": { "type": "ClientTlsOptions", "config": { "trustManager": { "type": "TrustAllManager" }, "hostnameVerifier": "ALLOW_ALL" } } } }, { "name": "SystemAndEnvSecretStore-1", "type": "SystemAndEnvSecretStore" }, { "name": "AuthenticatedRegistrationHandler-1", "type": "Chain", "config": { "filters": [ { "name": "ClientSecretBasicAuthenticationFilter-1", "type": "ClientSecretBasicAuthenticationFilter", "config": { "clientId": "&{oidcClientId}", "clientSecretId": "oidc.secret.id", "secretsProvider": "SystemAndEnvSecretStore-1" } } ], "handler": "ForgeRockClientHandler" } } ], "handler": { "type": "Chain", "config": { "filters": [ { "type": "AuthorizationCodeOAuth2ClientFilter", "config": { "clientEndpoint": "/home/sso", "failureHandler": { "type": "StaticResponseHandler", "config": { "status": 500, "headers": { "Content-Type": [ "text/plain" ] }, "entity": "Error: ${contexts.oauth2Failure.error}\nDescription: ${contexts.oauth2Failure.description}" } }, "registrations": [ { "type": "ClientRegistration", "config": { "clientId": "&{oidcClientId}", "issuer": { "type": "Issuer", "config": { "wellKnownEndpoint": "&{oidcWellKnownEndpoint}" } }, "scopes": [ "openid", "gateway" ], "authenticatedRegistrationHandler": "AuthenticatedRegistrationHandler-1" } } ] } }, { "type": "PingOneApiAccessManagementFilter", "config": { "gatewayServiceUri": "&{gatewayServiceUrl}", "secretsProvider": "SystemAndEnvSecretStore-1", "gatewayCredentialSecretId": "gateway.secret.id", "accessToken": "${attributes.openid.access_token}", "_sidebandHandler": { "_comment": "s/_sidebandHandler/sidebandHandler/ to troubleshoot AAM decisions", "type": "ClientHandler", "capture": "all" } } } ], "handler": "BlindTrustReverseProxyHandler" } } }
Source: pingone-aam.json
Notice the following features of the route:
-
The route properties use the settings you collected from the PingOne environment.
-
The heap has:
-
A handler to trust the self-signed sample application certificate for HTTPS blindly.
For production applications and APIs, use certificates you don’t have to trust blindly. -
A
SystemAndEnvSecretStore
to get the base64-encoded secrets from the environment variables. -
A handler to get an ID token and access token.
-
-
The
AuthorizationCodeOAuth2ClientFilter
authenticates the end user. -
The
PingOneApiAccessManagementFilter
uses the access token when making the authorization decision request to PingOne Authorize. -
If PingOne Authorize grants access, the
BlindTrustReverseProxyHandler
gets the resource from the sample application.
Validation
Access granted to a group member
-
In your browser’s privacy or incognito mode, go to https://ig.example.com:8443/home/sso.
PingOne displays the sign-on page.
-
Sign on to PingOne as the
wolkig
test user.PingOne Authorize grants access and PingGateway displays the sample application home page:
Access denied for a non-member
-
In your browser’s privacy or incognito mode, go again to https://ig.example.com:8443/home/sso.
PingOne displays the sign-on page.
-
Sign on to PingOne as the
demo
test user.PingOne Authorize denies access to the sample application and the browser displays the result:
{ "id" : "<uuid>", "code" : "ACCESS_FAILED", "message" : "The request could not be completed. You do not have access to this resource." }
When PingOne Authorize denies access or the example route fails to get an access token, the browser displays text, which isn’t user-friendly.
If you are protecting web pages rather than an API, use a StaticResponseHandler to show a more friendly page to the user.
Troubleshooting
If you get unexpected errors, try these debugging options:
-
In the PingGateway route, update the
PingOneApiAccessManagementFilter
to enable the capture decorator.Change
"_sidebandHandler"
to"sidebandHandler"
and save your work to let PingGateway reload the route. -
In the PingOne environment, go to Authorization > Recent Decisions, select the PingGateway decision endpoint, and select a decision to visualize.
PingOne shows you how PingOne Authorize arrived at the authorization decision.
On the Request and Response tabs, you find detailed traces of the parameters for each. Learn more in Recent decisions in the PingOne Authorize documentation.