Skip to content

Commit

Permalink
Merge pull request #429 from ForgeRock/feat_ping-config_2966
Browse files Browse the repository at this point in the history
feat(javascript-sdk): add config.setAsync for wellknown endpoint support
  • Loading branch information
cerebrl authored Mar 11, 2024
2 parents 3796ac3 + 13e3b7a commit b71c0dd
Show file tree
Hide file tree
Showing 18 changed files with 1,463 additions and 5 deletions.
133 changes: 133 additions & 0 deletions e2e/autoscript-apps/src/authn-central-login-wellknown/autoscript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* @forgerock/javascript-sdk
*
* autoscript.ts
*
* Copyright (c) 2020 ForgeRock. All rights reserved.
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
// @ts-nocheck
import * as forgerock from '@forgerock/javascript-sdk';
import { delay as rxDelay, map, mergeMap } from 'rxjs/operators';
import { from } from 'rxjs';

async function autoscript() {
const delay = 0;

const url = new URL(window.location.href);
const code = url.searchParams.get('code') || '';
const error = url.searchParams.get('error') || '';
const state = url.searchParams.get('state') || '';
// in central login we use an auth query param for the return of our mock 401 request
// this is to prevent the evaluation of the page before we have technically authenticated
const auth = url.searchParams.get('auth') || false;
const acr_values = url.searchParams.get('acr') || 'SpecificTree';

let clientId = url.searchParams.get('clientId') || 'CentralLoginOAuthClient';
let realmPath = url.searchParams.get('realmPath') || 'root';
// The `revoke` scope is required for PingOne support
let scope = url.searchParams.get('scope') || 'openid profile me.read revoke';
let wellKnownUrl =
url.searchParams.get('wellKnownUrl') ||
'https://auth.example.com:9443/am/.well-known/oidc-configuration';

console.log('Configure the SDK');

if (wellKnownUrl) {
localStorage.setItem('wellknown', wellKnownUrl);
localStorage.setItem('clientId', clientId);
localStorage.setItem('realmPath', realmPath);
localStorage.setItem('scope', scope);
} else {
wellKnownUrl = localStorage.getItem('wellknown');
clientId = localStorage.getItem('clientId');
realmPath = localStorage.getItem('realmPath');
scope = localStorage.getItem('scope');
}
await forgerock.Config.setAsync({
clientId,
realmPath,
redirectUri: `${url.origin}/authn-central-login-wellknown/`,
scope,
serverConfig: {
wellknown: wellKnownUrl,
},
});

try {
forgerock.SessionManager.logout();
} catch (err) {
// Do nothing
}

console.log('Initiate first step with `undefined`');

// Wrapping in setTimeout to give the test time to bind listener to console.log
setTimeout(() => {
from([1])
.pipe(
mergeMap(() => {
let tokens;
// detect when in iframe as to not call `/authorize` needlessly
if (window.self !== window.top) {
return;
} else if (code && state) {
tokens = forgerock.TokenManager.getTokens({
login: 'redirect',
query: { code, state },
});
} else {
tokens = forgerock.TokenManager.getTokens({
login: 'redirect',
query: { acr_values },
});
}
return tokens;
}),
map((tokens) => {
if (tokens.accessToken) {
console.log('OAuth authorization successful');
document.body.innerHTML = '<p class="Logged_In">Login successful</p>';
} else {
throw new Error('Session_Error');
}
}),
rxDelay(delay),
mergeMap(() => {
console.log('Remove cookie');
document.cookie = '';
console.log('Initiate logout');
// You have to allow specific origins to CORS for OAuth client
return forgerock.FRUser.logout();
}),
)
.subscribe({
error: (err) => {
/*
* We added this because Playwright was too fast for the dom element.
* When we make a request to central login we have to force a 401 page to mimick the real life scenario of the page being requested
* If we do this, we append a query param of auth to make sure we don't complete the flow until we are redirected from that page
* By saying we have !auth query param value, we are essentially mimicking the idea that we are waiting for the central login redirect
* to complete the redirect.
*/
if (!auth) {
return;
}
console.log(`Error: ${err.message}`);
document.body.innerHTML = `<p class="Test_Complete">${err.message}</p>`;
},
complete: () => {
console.log('Test script complete');
document.body.innerHTML = `<p class="Test_Complete">Test script complete</p>`;
localStorage.removeItem('wellknown');
localStorage.removeItem('clientId');
localStorage.removeItem('realmPath');
localStorage.removeItem('scope');
},
});
}, 250);
}

autoscript();
export default autoscript;
33 changes: 33 additions & 0 deletions e2e/autoscript-apps/src/authn-central-login-wellknown/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<title>E2E Test | ForgeRock JavaScript SDK</title>

<!-- Needed only for automation with mock server -->
<meta name="referrer" content="unsafe-url" />

<link rel="shortcut icon" href="/fr-ico.png" type="image/png" />

<style>
@media (prefers-color-scheme: dark) {
html {
background-color: black;
color: white;
}
a {
color: lightblue;
}
a:visited {
color: lavender;
}
a:hover {
color: lightskyblue;
}
}
</style>
</head>

<body>
<script src="autoscript.js"></script>
</body>
</html>
2 changes: 0 additions & 2 deletions e2e/autoscript-apps/src/authn-central-login/autoscript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ function autoscript() {
const realmPath = url.searchParams.get('realmPath') || 'root';
const scope = url.searchParams.get('scope') || 'openid profile me.read';
const state = url.searchParams.get('state') || '';
const support = url.searchParams.get('support') || 'legacy';
const acr_values = url.searchParams.get('acr') || 'SpecificTree';
// in central login we use an auth query param for the return of our mock 401 request
// this is to prevent the evaluation of the page before we have technically authenticated
Expand All @@ -51,7 +50,6 @@ function autoscript() {
serverConfig: {
baseUrl: amUrl,
},
support,
tokenStore,
});

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
157 changes: 157 additions & 0 deletions e2e/autoscript-apps/src/authn-wellknown/autoscript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* @forgerock/javascript-sdk
*
* autoscript.ts
*
* Copyright (c) 2020 ForgeRock. All rights reserved.
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
// @ts-nocheck
import * as forgerock from '@forgerock/javascript-sdk';
import { delay as rxDelay, map, mergeMap } from 'rxjs/operators';
import { from } from 'rxjs';

async function autoscript() {
const delay = 0;
const tokenExpiredDelay = 2000;

const url = new URL(window.location.href);
const clientId = url.searchParams.get('clientId') || 'WebOAuthClient';
const realmPath = url.searchParams.get('realmPath') || 'root';
const scope = url.searchParams.get('scope') || 'openid profile me.read';
const un = url.searchParams.get('un') || 'sdkuser';
const pw = url.searchParams.get('pw') || 'password';
const tree = url.searchParams.get('tree') || 'UsernamePassword';
const oauthThreshold = url.searchParams.get('oauthThreshold');
const resourceOrigin =
url.searchParams.get('resourceOrigin') || 'https://api.example.com:9443/resource';
const igUrl = url.searchParams.get('igUrl'); // only use when testing against IG on different host
const wellKnownUrl =
url.searchParams.get('wellKnownUrl') ||
'https://auth.example.com:9443/am/.well-known/oidc-configuration';

console.log('Configure the SDK');
await forgerock.Config.setAsync({
clientId,
middleware: [
(req, action, next) => {
switch (action.type) {
case 'AUTHORIZE':
console.log('Calling authorize endpoint');
break;
case 'EXCHANGE_TOKEN':
console.log('Calling access token exchange endpoint');
break;
}
next();
},
],
redirectUri: `${url.origin}/_callback/`,
realmPath,
scope,
tree,
serverConfig: {
wellknown: wellKnownUrl,
},
oauthThreshold: oauthThreshold,
});

try {
forgerock.SessionManager.logout();
} catch (err) {
// Do nothing
}

console.log('Initiate first step with `undefined`');
from(forgerock.FRAuth.next())
.pipe(
mergeMap((step) => {
console.log('Set values on auth tree callbacks');
step.getCallbackOfType('NameCallback').setName(un);
step.getCallbackOfType('PasswordCallback').setPassword(pw);
return forgerock.FRAuth.next(step);
}),
rxDelay(delay),
mergeMap((step) => {
if (step.payload.status === 401) {
throw new Error('Auth_Error');
}
console.log('Auth tree successfully completed');
console.log('Get OAuth tokens');
const tokens = forgerock.TokenManager.getTokens();
return tokens;
}),
rxDelay(delay),
map((tokens) => {
if (tokens.accessToken) {
console.log('OAuth login successful');
document.body.innerHTML = '<p class="Logged_In">Login successful</p>';
} else {
throw new Error('Session_Error');
}
return tokens;
}),
rxDelay(delay),
mergeMap(
(tokens) => {
console.log('Get user info from OAuth endpoint');
const user = forgerock.UserManager.getCurrentUser();
return user;
},
(tokens, user) => {
console.log(`User's given name: ${user.family_name}`);
return tokens;
},
),
rxDelay(delay),
mergeMap(
(tokens) => {
console.log('Force renew OAuth tokens');
return forgerock.TokenManager.getTokens({ forceRenew: true });
},
(oldTokens, newTokens) => {
if (oldTokens.accessToken !== newTokens.accessToken) {
console.log('New OAuth tokens retrieved');
} else {
throw new Error('Force_Renew_Error');
}
return newTokens;
},
),
rxDelay(delay),
mergeMap(() => {
console.log('Initiate logout');
return forgerock.FRUser.logout();
}),
rxDelay(delay),
mergeMap(
(step) => {
return forgerock.TokenStorage.get();
},
(step, tokens) => {
if (!tokens) {
console.log('Logout successful');
document.body.innerHTML = '<p class="Logged_Out">Logout successful</p>';
} else {
throw new Error('Logout_Error');
}
return step;
},
),
rxDelay(delay),
)
.subscribe({
error: (err) => {
console.log(`Error: ${err.message}`);
document.body.innerHTML = `<p class="Test_Complete">${err.message}</p>`;
},
complete: () => {
console.log('Test script complete');
document.body.innerHTML = `<p class="Test_Complete">Test script complete</p>`;
},
});
}

autoscript();
export default autoscript;
35 changes: 35 additions & 0 deletions e2e/autoscript-apps/src/authn-wellknown/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<title>E2E Test | ForgeRock JavaScript SDK</title>

<!-- Needed only for automation with mock server -->
<meta name="referrer" content="unsafe-url" />

<link rel="shortcut icon" href="/fr-ico.png" type="image/png" />

<style>
@media (prefers-color-scheme: dark) {
html {
background-color: black;
color: white;
}
a {
color: lightblue;
}
a:visited {
color: lavender;
}
a:hover {
color: lightskyblue;
}
}
</style>
</head>

<body>
<!-- script src="/_polyfills/fast-text-encoder.js"></script -->

<script src="autoscript.js"></script>
</body>
</html>
1 change: 1 addition & 0 deletions e2e/autoscript-apps/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<a href="./authn-email-suspend/index.html">AuthN: Email Suspend</a><br />
<a href="./authn-no-session/index.html">AuthN: No Session</a><br />
<a href="./authn-oauth/index.html">AuthN: OAuth</a><br />
<a href="./authn-wellknown/index.html">AuthN: WellKnown</a><br />
<a href="./authn-platform/index.html">AuthN: Platform Login</a><br />
<a href="./authn-second-factor/index.html">AuthN: Second Factor</a><br />
<a href="./authn-saml/index.html">AuthN: SAML</a><br />
Expand Down
2 changes: 2 additions & 0 deletions e2e/autoscript-apps/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ of the MIT license. See the LICENSE file for details.
const pages = [
'authn-basic',
'authn-central-login',
'authn-central-login-wellknown',
'authn-device-profile',
'authn-protect',
'authn-email-suspend',
'authn-no-session',
'authn-oauth',
'authn-wellknown',
'authn-platform',
'authn-saml',
'authn-second-factor',
Expand Down
Loading

0 comments on commit b71c0dd

Please sign in to comment.