Password replay
Password replay brings SSO to legacy web applications without the need to edit, upgrade, or recode them.
Use PingGateway with an appropriate PingOne Advanced Identity Cloud journey to capture and replay username password credentials. PingGateway and PingOne Advanced Identity Cloud share a secret key to encrypt and decrypt the password and keep it safe.
When running AM in a self-hosted deployment, also refer to Password replay from AM.
Request flow
-
PingGateway intercepts the browser’s HTTP GET request.
-
PingGateway redirects the user to the appropriate PingOne Advanced Identity Cloud journey for authentication.
-
PingOne Advanced Identity Cloud authenticates the user and stores the encrypted password in a JWT.
-
PingOne Advanced Identity Cloud redirects the browser back to the protected application with the JWT.
-
PingGateway intercepts the browser’s HTTP GET request again:
-
The user is authenticated.
-
PingGateway gets the password from the JWT and decrypts it.
-
PingGateway gets the username from PingOne Advanced Identity Cloud based on the user
_id
.
-
-
PingGateway replaces the request with an HTTP POST to the application, taking the credentials from the context.
-
The sample application validates the credentials from the HTTP POST request.
-
The sample application responds with the user’s profile page.
-
PingGateway passes the response from the sample application to the browser.
Tasks
Before you start
-
Make sure you can access the PingOne Advanced Identity Cloud tenant as an administrator.
-
Choose the realm to use in the PingOne Advanced Identity Cloud tenant.
The following tasks use the
alpha
realm. -
Prepare hostnames for PingGateway and the sample application.
The following tasks use
ig.example.com
for PingGateway andapp.example.com
for the sample application.
Task 1: Run the sample application
-
Open a command-line window and start the sample application:
$ java -jar PingGateway-sample-application-2024.6.0-jar-with-dependencies.jar
The sample application runs in the foreground until you stop it.
-
Check you can access the sample application by browsing http://app.example.com:8081/login.
The sample application displays a login screen.
Task 2: Install PingGateway
This task installs PingGateway, but doesn’t configure it for password replay yet.
-
Set a top-level
session
field inadmin.json
alongside theheap
andconnections
:"session": { "cookie": { "sameSite": "none", "secure": true } }
PingOne Advanced Identity Cloud prompts the browser to send a session cookie on successful authentication.
-
When
sameSite
isstrict
orlax
, the browser does not send the session cookie with the nonce used in validation. If PingGateway doesn’t find the nonce, it assumes that the authentication failed. -
When
secure
isfalse
, the browser is likely to reject the session cookie.
-
-
Add a base configuration file.
Comment captures in the handler to avoid flooding the PingGateway log,
"_capture": "all"
. -
Configure static routes for use with the sample application.
-
Check you can access the sample application through PingGateway by browsing https://ig.example.com:8443/static.
You might have used a self-signed certificate for the PingGateway HTTPS configuration. If your browser doesn’t recognize the PingGateway certificate and flags it as a security risk, choose to continue.
PingGateway displays a basic profile page for the
demo
user.
PingGateway now has the configuration required as a basis on which to build password replay.
Task 3: Register PingGateway with PingOne Advanced Identity Cloud
If you have not yet registered PingGateway with PingOne Advanced Identity Cloud, follow these steps:
-
Configure an
Agent
journey PingGateway uses to authenticate with PingOne Advanced Identity Cloud. -
Register a profile for PingGateway.
Field Value Description ID
ig-agent
The PingGateway username when connecting to the
AmService
in PingOne Advanced Identity Cloud.Password
password
The PingGateway password when connecting to the
AmService
in PingOne Advanced Identity Cloud.In production tenants, use a strong password.
Redirect URLs
https://ig.example.com:8443/replay/redirect
The PingGateway endpoint to process the encrypted JWT from PingOne Advanced Identity Cloud.
PingOne Advanced Identity Cloud is now ready for PingGateway to connect. You will share the credentials with PingGateway in Task 6: Configure PingGateway.
Task 4: Prepare a shared secret
PingGateway and PingOne Advanced Identity Cloud share a secret symmetric key to encrypt and decrypt the password.
-
Generate a random AES 256-bit key to use as a shared secret.
How you generate the secret key is up to you; for example:
$ openssl rand -base64 32 YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd5eHowMTIzNDU=
Keep the secret safe.
-
Store the shared secret key as an ESV in PingOne Advanced Identity Cloud.
-
Log in to the PingOne Advanced Identity Cloud admin UI as an administrator and go to Tenant Settings > Global Settings > Environment Secrets & Variables.
-
Click Variables > + Add Variable.
-
In the Add a Variable modal window, enter the following settings:
Field Value Description Name
esv-ig-shared-secret
The ESV name for the secret.
Value
YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd5eHowMTIzNDU=
The base64-encoded random AES 256-bit key.
-
Click Save to create the variable.
PingOne Advanced Identity Cloud can now access the secret through the
esv.ig.shared.secret
system property. You will share the secret with PingGateway in Task 6: Configure PingGateway. -
Task 5: Prepare PingOne Advanced Identity Cloud
Update the PingOne Advanced Identity Cloud validation service for PingGateway, create a script to capture the password, and a journey to use the script.
-
Log in to the PingOne Advanced Identity Cloud admin UI as an administrator and go to Native Consoles > Access Management, select Services, and the following Valid goto URL Resources to the Validation Service:
-
https://ig.example.com:8443/*
-
https://ig.example.com:8443/*?*
-
-
Go to Scripts > Auth Scripts, click + New Script and create a Journey Decision Node script with the Legacy engine named
Password replay
and the following JavaScript content.The script adds a JWT encrypted with the shared secret key to the session:
Show script
var fr = JavaImporter( org.forgerock.openam.auth.node.api.Action, org.forgerock.openam.auth.node.api, javax.security.auth.callback.TextOutputCallback, org.forgerock.json.jose.builders.JwtBuilderFactory, org.forgerock.json.jose.jwt.JwtClaimsSet, org.forgerock.json.jose.jwe.JweAlgorithm, org.forgerock.json.jose.jwe.EncryptionMethod, javax.crypto.spec.SecretKeySpec, org.forgerock.secrets.SecretBuilder, org.forgerock.util.encode.Base64 ); var NodeOutcome = { ERROR: 'false', SUCCESS: 'true' }; var config = { encryptionKey: systemEnv.getProperty("esv.ig.shared.secret") }; function getKey () { logger.message("encKey: " + config.encryptionKey) return new fr.SecretKeySpec(fr.Base64.decode(config.encryptionKey), 'AES'); } function buildJwt (claims) { logger.message('Building response JWT'); var encryptionKey = getKey(); var jwtClaims = new fr.JwtClaimsSet; jwtClaims.setClaims(claims); var jwt = new fr.JwtBuilderFactory() .jwe(encryptionKey) .headers() .alg(fr.JweAlgorithm.DIRECT) .enc(fr.EncryptionMethod.A128CBC_HS256) .done() .claims(jwtClaims) .build(); return jwt; } try { password=nodeState.get("password").asString() var registrationClaims = { password: password }; passwordJwt = buildJwt(registrationClaims); action = fr.Action.goTo(NodeOutcome.SUCCESS).putSessionProperty("sunIdentityUserPassword", passwordJwt).build(); } catch (e) { logger.error('ERROR ' + e); action = fr.Action.send(new fr.TextOutputCallback(fr.TextOutputCallback.ERROR, e.toString())).build(); }
You can download the script as password-replay.js.
-
Go to Journeys, click + New Journey, and create a journey named
Password replay
whose Identity Object ismanaged/alpha_user
. -
Configure and save the journey with the nodes shown in this screenshot:
-
The Page node presents a page with input fields to prompt for the username and password.
-
The Platform Username node collects and injects the
userName
into the shared node state. -
The Platform Password node collects and injects the
password
into the shared node state.
-
-
The Data Store Decision node uses the username and password to determine whether authentication is successful.
-
The Scripted Decision node references your script and has the same outcomes:
true
andfalse
. -
The Increment Login Count node updates the login count on successful authentication.
-
-
In your browser’s privacy or incognito mode, go to the new journey and log in with the credentials of a known user in the
alpha
realm.PingOne Advanced Identity Cloud authenticates you and displays the user profile page.
You can now configure PingGateway to use the journey to capture the password.
Task 6: Configure PingGateway
The password replay configuration includes the PingGateway password to connect to PingOne Advanced Identity Cloud, the shared secret, and a route.
-
Set an environment variable locally on the computer running PingGateway to access the agent password:
# The base64-encoded PingGateway agent "password": $ export AGENT_SECRET_ID='cGFzc3dvcmQ='
PingGateway retrieves the password with a SystemAndEnvSecretStore, which requires it to be base64-encoded.
The password must match the agent profile password you set in PingOne Advanced Identity Cloud. PingGateway uses the password to connect to PingOne Advanced Identity Cloud.
-
Set an environment variable locally on the computer running PingGateway to access the shared secret key:
# The base64-encoded shared secret key: $ export AES_KEY='YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd5eHowMTIzNDU='
PingGateway retrieves the shared secret with a SystemAndEnvSecretStore, which requires it to be base64-encoded.
The shared secret key must match the secret key you stored in the PingOne Advanced Identity Cloud ESV. PingOne Advanced Identity Cloud uses the secret key to encrypt the password to replay. PingGateway uses the secret key to decrypt the password to replay.
-
Add a route for password replay.
-
Linux
-
Windows
$HOME/.openig/config/routes/04-replay-aic.json
%appdata%\OpenIG\config\routes\04-replay-aic.json
Show route
{ "name": "04-replay", "condition": "${find(request.uri.path, '^/replay')}", "properties": { "amInstanceUrl": "https://myTenant.forgeblocks.com/am/" }, "heap": [ { "name": "SystemAndEnvSecretStore-1", "type": "SystemAndEnvSecretStore", "config": { "mappings": [ { "secretId": "aes.key", "format": { "type": "SecretKeyPropertyFormat", "config": { "format": "BASE64", "algorithm": "AES" } } } ] } }, { "name": "AmService-1", "type": "AmService", "config": { "url": "&{amInstanceUrl}", "realm": "/alpha", "agent": { "username": "ig-agent", "passwordSecretId": "agent.secret.id" }, "secretsProvider": "SystemAndEnvSecretStore-1" }, "sessionCache": { "enabled": false } }, { "name": "CapturedUserPasswordFilter-1", "type": "CapturedUserPasswordFilter", "config": { "ssoToken": "${contexts.ssoToken.value}", "keySecretId": "aes.key", "keyType": "AES", "secretsProvider": "SystemAndEnvSecretStore-1", "amService": "AmService-1" } } ], "handler": { "type": "Chain", "config": { "filters": [ { "name": "CrossDomainSingleSignOnFilter-1", "type": "CrossDomainSingleSignOnFilter", "config": { "redirectEndpoint": "/replay/redirect", "authCookie": { "path": "/replay", "name": "ig-token-cookie" }, "amService": "AmService-1", "authenticationService": "Password replay" } }, { "name": "UserProfileFilter-1", "type": "UserProfileFilter", "config": { "username": "${contexts.ssoToken.info.uid}", "userProfileService": { "type": "UserProfileService", "config": { "amService": "AmService-1", "profileAttributes": [ "username" ] } } } }, { "name": "PasswordReplayFilter-1", "type": "PasswordReplayFilter", "config": { "loginPage": "${true}", "credentials": "CapturedUserPasswordFilter-1", "request": { "method": "POST", "uri": "http://app.example.com:8081/login", "form": { "username": [ "${contexts.userProfile.username}" ], "password": [ "${contexts.capturedPassword.value}" ] } } }, "capture": [ "all" ] } ], "handler": "ReverseProxyHandler" } } }
You can download the route as 04-replay.json.
The route:
-
Matches requests whose path starts with
/replay
. -
Sets an
amInstanceUrl
property to the access management service in PingOne Advanced Identity Cloud.Update the URL to target your tenant.
-
Loads the
aes.key
secret key from the localAES_KEY
environment variable. -
Connects to PingOne Advanced Identity Cloud as
ig-agent
with theagent.secret.id
password from the localAGENT_SECRET_ID
environment variable. -
Extracts the captured password from the SSO token context and decrypts it with the
aes.key
secret key. -
Uses a CrossDomainSingleSignOnFilter to redirect to the PingOne Advanced Identity Cloud
Password replay
journey for authentication, getting the authentication information from theig-token-cookie
. -
Queries the access management service in PingOne Advanced Identity Cloud to retrieve the username for logging in.
You can retrieve other profile attributes with the UserProfileFilter, such as the email address or first and last names. The sample application expects the username in this example, so the route gets the username.
-
Logs in to the sample application with the username and password.
-
Returns the result to the browser.
In production, remove
"capture": ["all"]
from the PasswordReplayFilter to avoid recording credentials in the logs. -
-
Restart PingGateway to read the secrets from the environment and load the new route.
In the PingGateway output, make sure the route loaded successfully with no errors or warnings:
@system - Loaded the route with id '04-replay-aic' registered with the name '04-replay-aic'
.
Task 7: Create a test user in PingOne Advanced Identity Cloud
The sample application validates the credentials for password replay. It must recognize the username and password you use.
The sample application has built-in username-password combinations. The username and password credentials shown in the following steps are one of the built-in pairs.
-
In your browser’s privacy or incognito mode, go to the default login journey for the realm you’re using.
For example,
https://myTenant.forgeblocks.com/am/XUI/?realm=/alpha#/
. -
Click the Create an account link and enter the following settings in the Sign Up page:
Field Value Username
wolkig
First name
Wilhelm
Last name
Wolkig
Email Address
wolkig@example.com
Password
Geh3imnis!
Select a security question
What’s your favorite color?
Answer
Red
-
Click Next to complete account creation and view the user profile.
-
Sign out.
Validation
-
In your browser’s privacy or incognito mode, go to https://ig.example.com:8443/replay/.
PingGateway redirects to the PingOne Advanced Identity Cloud journey.
-
Log in as user
wolkig
with passwordGeh3imnis!
.PingGateway successfully replays the credentials against the sample application. The sample application displays its user profile page:
-
Review the PingGateway output.
On success, the output displays the credentials and the profile page:
...INFO o.f.o.d.c.C.c.PasswordReplayFilter-1 @04-replay-aic - [CONTINUED]--- (filtered-request) exchangeId:<id> - transactionId:<id> ---> [CONTINUED]POST http://app.example.com:8081/login HTTP/1.1 [CONTINUED]Content-Length: 37 [CONTINUED]Content-Type: application/x-www-form-urlencoded [CONTINUED]password=Geh3imnis%21&username=wolkig ...INFO o.f.o.d.c.C.c.PasswordReplayFilter-1 @04-replay-aic - [CONTINUED]<--- (response) exchangeId:<id> - transactionId:<id> --- [CONTINUED]HTTP/1.1 200 OK ... [CONTINUED]<!DOCTYPE html> ...
You have successfully demonstrated password replay with PingGateway and PingOne Advanced Identity Cloud.
If password replay fails, consider the outcome of the HTTP POST from PingGateway to the sample application:
- HTTP 401 Unauthorized
-
PingGateway is not replaying the credentials.
Review the PingGateway output to determine whether the username or password is missing when PingGateway replays the credentials.
If the password is missing, make sure PingGateway and PingOne Advanced Identity Cloud share the same AES secret key.
- HTTP 403 Forbidden
-
PingGateway is not replaying the right credentials.
Make sure you’re using a username-password combination known to the sample application.