diff --git a/.vscode/launch.json b/.vscode/launch.json index e3de1c338..d31b387d3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,7 +11,7 @@ "request": "launch", "name": "Run Frodo CLI", "program": "${workspaceFolder}/src/app.ts", - "args": ["config-manager", "push", "themes", "demo1"], + "args": ["config-manager", "push", "terms-and-conditions", "dev"], "outFiles": [ "${workspaceFolder}/dist/**/*.(m|c|)js", "${workspaceFolder}/node_modules/@rockcarver/frodo-lib/dist/**/*.(m|c|)js" diff --git a/src/cli/config-manager/config-manager-push/config-manager-push-terms-and-conditions.ts b/src/cli/config-manager/config-manager-push/config-manager-push-terms-and-conditions.ts new file mode 100644 index 000000000..be4aff43b --- /dev/null +++ b/src/cli/config-manager/config-manager-push/config-manager-push-terms-and-conditions.ts @@ -0,0 +1,52 @@ +import { Option } from 'commander'; + +import { configManagerImportTermsAndConditions } from '../../../configManagerOps/FrConfigTermsAndConditionsOps'; +import { getTokens } from '../../../ops/AuthenticateOps'; +import { printMessage, verboseMessage } from '../../../utils/Console'; +import { FrodoCommand } from '../../FrodoCommand'; + +const deploymentTypes = ['cloud', 'forgeops']; + +export default function setup() { + const program = new FrodoCommand( + 'frodo config-manager push terms-and-conditions', + [], + deploymentTypes + ); + + program + .description('Import ui-configuration objects.') + .addOption( + new Option( + '-f, --file [file]', + 'Fr-config-manager format file to import.' + ) + ) + .action(async (host, realm, user, password, options, command) => { + command.handleDefaultArgsAndOpts( + host, + realm, + user, + password, + options, + command + ); + + if (await getTokens(false, true, deploymentTypes)) { + verboseMessage('Exporting config entity ui-configuration'); + const outcome = await configManagerImportTermsAndConditions(); + if (!outcome) process.exitCode = 1; + } + // unrecognized combination of options or no options + else { + printMessage( + 'Unrecognized combination of options or no options...', + 'error' + ); + program.help(); + process.exitCode = 1; + } + }); + + return program; +} diff --git a/src/cli/config-manager/config-manager-push/config-manager-push-themes.ts b/src/cli/config-manager/config-manager-push/config-manager-push-themes.ts index 711398dd9..df9ebe82d 100644 --- a/src/cli/config-manager/config-manager-push/config-manager-push-themes.ts +++ b/src/cli/config-manager/config-manager-push/config-manager-push-themes.ts @@ -1,4 +1,3 @@ - import { configManagerImportThemes } from '../../../configManagerOps/FrConfigThemeOps'; import { getTokens } from '../../../ops/AuthenticateOps'; import { printMessage, verboseMessage } from '../../../utils/Console'; @@ -28,7 +27,7 @@ export default function setup() { if (await getTokens(false, true, deploymentTypes)) { verboseMessage('Importing themes'); const outcome = await configManagerImportThemes(); - + if (!outcome) process.exitCode = 1; } // unrecognized combination of options or no options else { @@ -42,4 +41,3 @@ export default function setup() { }); return program; } - diff --git a/src/cli/config-manager/config-manager-push/config-manager-push-uiConfig.ts b/src/cli/config-manager/config-manager-push/config-manager-push-uiConfig.ts index ae882496b..5752d5f8e 100644 --- a/src/cli/config-manager/config-manager-push/config-manager-push-uiConfig.ts +++ b/src/cli/config-manager/config-manager-push/config-manager-push-uiConfig.ts @@ -1,9 +1,9 @@ +import { Option } from 'commander'; + import { configManagerImportUiConfig } from '../../../configManagerOps/FrConfigUiConfigOps'; import { getTokens } from '../../../ops/AuthenticateOps'; import { printMessage, verboseMessage } from '../../../utils/Console'; import { FrodoCommand } from '../../FrodoCommand'; -import { Option } from 'commander'; - const deploymentTypes = ['cloud', 'forgeops']; @@ -16,7 +16,12 @@ export default function setup() { program .description('Import ui-configuration objects.') - .addOption(new Option('-f, --file [file]', 'Fr-config-manager format file to import.')) + .addOption( + new Option( + '-f, --file [file]', + 'Fr-config-manager format file to import.' + ) + ) .action(async (host, realm, user, password, options, command) => { command.handleDefaultArgsAndOpts( host, @@ -44,4 +49,4 @@ export default function setup() { }); return program; -} \ No newline at end of file +} diff --git a/src/cli/config-manager/config-manager-push/config-manager-push.ts b/src/cli/config-manager/config-manager-push/config-manager-push.ts index a8b337b55..a797d8490 100644 --- a/src/cli/config-manager/config-manager-push/config-manager-push.ts +++ b/src/cli/config-manager/config-manager-push/config-manager-push.ts @@ -1,17 +1,16 @@ import { FrodoStubCommand } from '../../FrodoCommand'; +import TermsAndConditions from './config-manager-push-terms-and-conditions'; import Themes from './config-manager-push-themes'; import UiConfig from './config-manager-push-uiConfig'; export default function setup() { - const program = new FrodoStubCommand('frodo config-manager pull').description( + const program = new FrodoStubCommand('push').description( 'Export cloud configuration using fr-config-manager.' ); - program.addCommand(Themes().name('themes')); program.addCommand(UiConfig().name('ui-config')); + program.addCommand(TermsAndConditions().name('terms-and-conditions')); return program; } - - diff --git a/src/cli/config-manager/config-manager.ts b/src/cli/config-manager/config-manager.ts index 5b730b0cf..d5e71fca6 100644 --- a/src/cli/config-manager/config-manager.ts +++ b/src/cli/config-manager/config-manager.ts @@ -2,16 +2,13 @@ import { FrodoStubCommand } from '../FrodoCommand'; import PullCmd from './config-manager-pull/config-manager-pull'; import PushCmd from './config-manager-push/config-manager-push'; - export default function setup() { const program = new FrodoStubCommand('config-manager').description( 'Manage cloud configuration using fr-config-manager.' ); - program.addOption; program.addCommand(PullCmd().name('pull')); program.addCommand(PushCmd().name('push')); - return program; } diff --git a/src/configManagerOps/FrConfigTermsAndConditionsOps.ts b/src/configManagerOps/FrConfigTermsAndConditionsOps.ts index 6c256eb31..be3dca9ab 100644 --- a/src/configManagerOps/FrConfigTermsAndConditionsOps.ts +++ b/src/configManagerOps/FrConfigTermsAndConditionsOps.ts @@ -1,10 +1,11 @@ import { frodo } from '@rockcarver/frodo-lib'; +import fs from 'fs'; import { extractFrConfigDataToFile } from '../utils/Config'; import { printError } from '../utils/Console'; const { saveJsonToFile, getFilePath } = frodo.utils; -const { readConfigEntity } = frodo.idm.config; +const { readConfigEntity, importConfigEntities } = frodo.idm.config; /** * Export terms and conditions to file @@ -37,3 +38,27 @@ export async function configManagerExportTermsAndConditions(): Promise return false; } } + +export async function configManagerImportTermsAndConditions(): Promise { + try { + const mainFile = getFilePath('terms-conditions/terms-conditions.json'); + const readMain = fs.readFileSync(mainFile, 'utf8') as any; + let importData = JSON.parse(readMain) as any; + const id = importData._id; + importData = { idm: { [id]: importData } }; + for (const version of importData.idm[id].versions) { + for (const [language] of Object.entries(version.termsTranslations)) { + const languageFileName = `${version.version}/${language}.html`; + const directoryName = `terms-conditions`; + const fileDir = getFilePath(`${directoryName}/${languageFileName}`); + version.termsTranslations[language] = fs.readFileSync(fileDir, 'utf8'); + } + } + await importConfigEntities(importData); + + return true; + } catch (error) { + printError(error); + return false; + } +} diff --git a/src/configManagerOps/FrConfigThemeOps.ts b/src/configManagerOps/FrConfigThemeOps.ts index 987d51c65..584ac0b4d 100644 --- a/src/configManagerOps/FrConfigThemeOps.ts +++ b/src/configManagerOps/FrConfigThemeOps.ts @@ -3,10 +3,9 @@ import { ThemeSkeleton } from '@rockcarver/frodo-lib/types/ops/ThemeOps'; import fs from 'fs'; import { printError, printMessage } from '../utils/Console'; -import { decodeOrNot } from '../utils/FrConfig'; -import { encodeOrNot } from '../utils/FrConfig' +import { decodeOrNot, encodeOrNot } from '../utils/FrConfig'; -const { saveJsonToFile, getFilePath, getRealmPath } = frodo.utils; +const { saveJsonToFile, getFilePath } = frodo.utils; const { readRealms } = frodo.realm; const { readThemes, importThemes } = frodo.theme; @@ -67,6 +66,8 @@ export async function configManagerExportThemes(): Promise { try { const realms = await readRealms(); for (const realm of realms) { + // fr-config-manager doesn't support root themes + if (realm.name === '/') continue; state.setRealm(realm.name); const themes = await readThemes(); const exportDir = getFilePath(`realms/${realm.name}/themes`, true); @@ -86,45 +87,49 @@ export async function configManagerExportThemes(): Promise { } export async function processTheme(theme: ThemeSkeleton, themePath: string) { - // create the for loop that will read and iterate through each realm to find the themes for (const field of THEME_HTML_FIELDS) { if (!theme[field.name]) continue; - - if (typeof theme[field.name] === 'object' && typeof (theme[field.name]as any).file === 'string' ) { - const fileName = (theme[field.name] as any).file + + if ( + typeof theme[field.name] === 'object' && + typeof (theme[field.name] as any).file === 'string' + ) { + const fileName = (theme[field.name] as any).file; const filePath = `${themePath}/${fileName}`; const fileContent = fs.readFileSync(filePath, 'utf8'); const encodedContent = encodeOrNot(fileContent, field.encoded); theme[field.name] = encodedContent; - } - } + } + } } - + export async function configManagerImportThemes(): Promise { try { const realms = await readRealms(); for (const realm of realms) { + // fr-config-manager doesn't support root themes + if (realm.name === '/') continue; state.setRealm(realm.name); - const importDir = getFilePath(`realms${realm.name === '/' ? '' : realm.parentPath + realm.name}/themes`, true); - const themesDir = fs.readdirSync(importDir, { withFileTypes: true}) - .filter(dirent => dirent.isDirectory()) - .map(dirent => dirent.name); + const importDir = getFilePath( + `realms${realm.parentPath + realm.name}/themes` + ); + const themesDir = fs + .readdirSync(importDir, { withFileTypes: true }) + .filter((dirent) => dirent.isDirectory()) + .map((dirent) => dirent.name); const themeMap: Record = {}; - + for (const themeName of themesDir) { const themeDir = `${importDir}/${themeName}`; const themeJsonPath = `${themeDir}/${themeName}.json`; - const theme: ThemeSkeleton = JSON.parse(fs.readFileSync(themeJsonPath, 'utf8')); + const theme: ThemeSkeleton = JSON.parse( + fs.readFileSync(themeJsonPath, 'utf8') + ); processTheme(theme, themeDir); themeMap[theme._id] = theme; - } - - // Import all themes for this realm - // await importThemes( - // { theme: themeMap } - // ); + } - saveJsonToFile( { theme: themeMap }, 'export.json'); + await importThemes({ theme: themeMap }); } return true; } catch (error) { diff --git a/src/configManagerOps/FrConfigUiConfigOps.ts b/src/configManagerOps/FrConfigUiConfigOps.ts index b3c78130b..9bc071405 100644 --- a/src/configManagerOps/FrConfigUiConfigOps.ts +++ b/src/configManagerOps/FrConfigUiConfigOps.ts @@ -1,11 +1,12 @@ import { frodo } from '@rockcarver/frodo-lib'; import fs from 'fs'; import path from 'path'; + import { getIdmImportExportOptions } from '../ops/IdmOps'; -import { printError } from '../utils/Console'; import { errorHandler } from '../ops/utils/OpsUtils'; +import { printError } from '../utils/Console'; -const { exportConfigEntity, importConfigEntities} = frodo.idm.config; +const { exportConfigEntity, importConfigEntities } = frodo.idm.config; const { getFilePath, saveJsonToFile } = frodo.utils; /** @@ -43,10 +44,7 @@ export async function configManagerImportUiConfig( validate: boolean = false ): Promise { try { - const fileData = fs.readFileSync( - path.resolve(process.cwd(), file), - 'utf8' - ); + const fileData = fs.readFileSync(path.resolve(process.cwd(), file), 'utf8'); let importData = JSON.parse(fileData); importData = { idm: { [importData._id]: importData } }; //saveJsonToFile (importData, './frconfigtestfile.json'); @@ -54,7 +52,7 @@ export async function configManagerImportUiConfig( await importConfigEntities( importData, - "ui/configuration", + 'ui/configuration', { envReplaceParams: options.envReplaceParams, entitiesToImport: undefined, @@ -62,10 +60,9 @@ export async function configManagerImportUiConfig( }, errorHandler ); - return true - } - catch (error) { + return true; + } catch (error) { printError(error); } - return false -} \ No newline at end of file + return false; +} diff --git a/test/client_cli/en/__snapshots__/config-manager-push-terms-and-conditions.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-push-terms-and-conditions.test.js.snap new file mode 100644 index 000000000..3864388ee --- /dev/null +++ b/test/client_cli/en/__snapshots__/config-manager-push-terms-and-conditions.test.js.snap @@ -0,0 +1,126 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CLI help interface for 'config-manager push terms-and-conditions' should be expected english 1`] = ` +"Usage: frodo config-manager push terms-and-conditions [options] [host] [realm] [username] [password] + +Import ui-configuration objects. + +Arguments: + host AM base URL, e.g.: + https://cdk.iam.example.com/am. To use a + connection profile, just specify a + unique substring. + realm Realm. Specify realm as '/' for the root + realm or 'realm' or '/parent/child' + otherwise. (default: "alpha" for + Identity Cloud tenants, "/" otherwise.) + username Username to login with. Must be an admin + user with appropriate rights to manage + authentication journeys/trees. + password Password. + +Options: + --curlirize Output all network calls in curl format. + -D, --directory Set the working directory. + --debug Debug output during command execution. + If specified, may or may not produce + additional output helpful for + troubleshooting. + -f, --file [file] Fr-config-manager format file to import. + --flush-cache Flush token cache. + -h, --help Help + --idm-host IDM base URL, e.g.: + https://cdk.idm.example.com/myidm. Use + only if your IDM installation resides in + a different domain and/or if the base + path differs from the default + "/openidm". + -k, --insecure Allow insecure connections when using + SSL/TLS. Has no effect when using a + network proxy for https + (HTTPS_PROXY=http://:), in + that case the proxy must provide this + capability. (default: Don't allow + insecure connections) + --login-client-id Specify a custom OAuth2 client id to use + a your own oauth2 client for IDM API + calls in deployments of type "cloud" or + "forgeops". Your custom client must be + configured as a public client and allow + the authorization code grant using the + "openid fr:idm:*" scope. Use the + "--redirect-uri" parameter if you have + configured a custom redirect uri + (default: + "/platform/appAuthHelperRedirect.html"). + --login-redirect-uri Specify a custom redirect URI to use + with your custom OAuth2 client (efault: + "/platform/appAuthHelperRedirect.html"). + -m, --type Override auto-detected deployment type. + Valid values for type: + classic: A classic Access + Management-only deployment with custom + layout and configuration. + cloud: A ForgeRock Identity Cloud + environment. + forgeops: A ForgeOps CDK or CDM + deployment. + The detected or provided deployment type + controls certain behavior like obtaining + an Identity Management admin token or + not and whether to export/import + referenced email templates or how to + walk through the tenant admin login flow + of Identity Cloud and handle MFA + (choices: "classic", "cloud", + "forgeops") + --no-cache Disable token cache for this operation. + --passphrase The passphrase for the Amster private + key if it is encrypted. + --private-key File containing the private key for + authenticating with Amster. Supported + formats include PEM (both PKCS#1 and + PKCS#8 variants), OpenSSH, DNSSEC, and + JWK. + --retry Retry failed operations. Valid values + for strategy: + everything: Retry all failed operations. + + network: Retry only network-related + failed operations. + nothing: Do not retry failed + operations. + The selected retry strategy controls how + the CLI handles failures. (choices: + "nothing", "everything", "network", + default: Do not retry failed + operations.) + --sa-id Service account id. + --sa-jwk-file File containing the JSON Web Key (JWK) + associated with the the service account. + --verbose Verbose output during command execution. + If specified, may or may not produce + additional output. + +Environment Variables: + FRODO_HOST: AM base URL. Overridden by 'host' argument. + FRODO_IDM_HOST: IDM base URL. Overridden by '--idm-host' option. + FRODO_REALM: Realm. Overridden by 'realm' argument. + FRODO_USERNAME: Username. Overridden by 'username' argument. + FRODO_PASSWORD: Password. Overridden by 'password' argument. + FRODO_LOGIN_CLIENT_ID: OAuth2 client id for IDM API calls. Overridden by '--login-client-id' option. + FRODO_LOGIN_REDIRECT_URI: Redirect Uri for custom OAuth2 client id. Overridden by '--login-redirect-uri' option. + FRODO_SA_ID: Service account uuid. Overridden by '--sa-id' option. + FRODO_SA_JWK: Service account JWK. Overridden by '--sa-jwk-file' option but takes the actual JWK as a value, not a file name. + FRODO_AMSTER_PASSPHRASE: Passphrase for the Amster private key if it is encrypted. Overridden by '--passphrase' option. + FRODO_AMSTER_PRIVATE_KEY: Amster private key. Overridden by '--private-key' option but takes the actual private key as a value (i.e. the file contents), not a file name. Supported formats include PEM (both PKCS#1 and PKCS#8 variants), OpenSSH, DNSSEC, and JWK. + FRODO_NO_CACHE: Disable token cache. Same as '--no-cache' option. + FRODO_TOKEN_CACHE_PATH: Use this token cache file instead of '~/.frodo/TokenCache.json'. + FRODO_CONNECTION_PROFILES_PATH: Use this connection profiles file instead of '~/.frodo/Connections.json'. + FRODO_AUTHENTICATION_SERVICE: Name of a login journey to use. When using an Amster private key, specifies which journey to use for Amster authentication as opposed to the default 'amsterService' journey. + FRODO_DEBUG: Set to any value to enable debug output. Same as '--debug'. + FRODO_MASTER_KEY_PATH: Use this master key file instead of '~/.frodo/masterkey.key' file. + FRODO_MASTER_KEY: Use this master key instead of what's in '~/.frodo/masterkey.key'. Takes precedence over FRODO_MASTER_KEY_PATH. + +" +`; diff --git a/test/client_cli/en/__snapshots__/config-manager-push-themes.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-push-themes.test.js.snap new file mode 100644 index 000000000..ec90c3137 --- /dev/null +++ b/test/client_cli/en/__snapshots__/config-manager-push-themes.test.js.snap @@ -0,0 +1,125 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CLI help interface for 'config-manager push themes' should be expected english 1`] = ` +"Usage: frodo config-manager push themes [options] [host] [realm] [username] [password] + +Import themes. + +Arguments: + host AM base URL, e.g.: + https://cdk.iam.example.com/am. To use a + connection profile, just specify a + unique substring. + realm Realm. Specify realm as '/' for the root + realm or 'realm' or '/parent/child' + otherwise. (default: "alpha" for + Identity Cloud tenants, "/" otherwise.) + username Username to login with. Must be an admin + user with appropriate rights to manage + authentication journeys/trees. + password Password. + +Options: + --curlirize Output all network calls in curl format. + -D, --directory Set the working directory. + --debug Debug output during command execution. + If specified, may or may not produce + additional output helpful for + troubleshooting. + --flush-cache Flush token cache. + -h, --help Help + --idm-host IDM base URL, e.g.: + https://cdk.idm.example.com/myidm. Use + only if your IDM installation resides in + a different domain and/or if the base + path differs from the default + "/openidm". + -k, --insecure Allow insecure connections when using + SSL/TLS. Has no effect when using a + network proxy for https + (HTTPS_PROXY=http://:), in + that case the proxy must provide this + capability. (default: Don't allow + insecure connections) + --login-client-id Specify a custom OAuth2 client id to use + a your own oauth2 client for IDM API + calls in deployments of type "cloud" or + "forgeops". Your custom client must be + configured as a public client and allow + the authorization code grant using the + "openid fr:idm:*" scope. Use the + "--redirect-uri" parameter if you have + configured a custom redirect uri + (default: + "/platform/appAuthHelperRedirect.html"). + --login-redirect-uri Specify a custom redirect URI to use + with your custom OAuth2 client (efault: + "/platform/appAuthHelperRedirect.html"). + -m, --type Override auto-detected deployment type. + Valid values for type: + classic: A classic Access + Management-only deployment with custom + layout and configuration. + cloud: A ForgeRock Identity Cloud + environment. + forgeops: A ForgeOps CDK or CDM + deployment. + The detected or provided deployment type + controls certain behavior like obtaining + an Identity Management admin token or + not and whether to export/import + referenced email templates or how to + walk through the tenant admin login flow + of Identity Cloud and handle MFA + (choices: "classic", "cloud", + "forgeops") + --no-cache Disable token cache for this operation. + --passphrase The passphrase for the Amster private + key if it is encrypted. + --private-key File containing the private key for + authenticating with Amster. Supported + formats include PEM (both PKCS#1 and + PKCS#8 variants), OpenSSH, DNSSEC, and + JWK. + --retry Retry failed operations. Valid values + for strategy: + everything: Retry all failed operations. + + network: Retry only network-related + failed operations. + nothing: Do not retry failed + operations. + The selected retry strategy controls how + the CLI handles failures. (choices: + "nothing", "everything", "network", + default: Do not retry failed + operations.) + --sa-id Service account id. + --sa-jwk-file File containing the JSON Web Key (JWK) + associated with the the service account. + --verbose Verbose output during command execution. + If specified, may or may not produce + additional output. + +Environment Variables: + FRODO_HOST: AM base URL. Overridden by 'host' argument. + FRODO_IDM_HOST: IDM base URL. Overridden by '--idm-host' option. + FRODO_REALM: Realm. Overridden by 'realm' argument. + FRODO_USERNAME: Username. Overridden by 'username' argument. + FRODO_PASSWORD: Password. Overridden by 'password' argument. + FRODO_LOGIN_CLIENT_ID: OAuth2 client id for IDM API calls. Overridden by '--login-client-id' option. + FRODO_LOGIN_REDIRECT_URI: Redirect Uri for custom OAuth2 client id. Overridden by '--login-redirect-uri' option. + FRODO_SA_ID: Service account uuid. Overridden by '--sa-id' option. + FRODO_SA_JWK: Service account JWK. Overridden by '--sa-jwk-file' option but takes the actual JWK as a value, not a file name. + FRODO_AMSTER_PASSPHRASE: Passphrase for the Amster private key if it is encrypted. Overridden by '--passphrase' option. + FRODO_AMSTER_PRIVATE_KEY: Amster private key. Overridden by '--private-key' option but takes the actual private key as a value (i.e. the file contents), not a file name. Supported formats include PEM (both PKCS#1 and PKCS#8 variants), OpenSSH, DNSSEC, and JWK. + FRODO_NO_CACHE: Disable token cache. Same as '--no-cache' option. + FRODO_TOKEN_CACHE_PATH: Use this token cache file instead of '~/.frodo/TokenCache.json'. + FRODO_CONNECTION_PROFILES_PATH: Use this connection profiles file instead of '~/.frodo/Connections.json'. + FRODO_AUTHENTICATION_SERVICE: Name of a login journey to use. When using an Amster private key, specifies which journey to use for Amster authentication as opposed to the default 'amsterService' journey. + FRODO_DEBUG: Set to any value to enable debug output. Same as '--debug'. + FRODO_MASTER_KEY_PATH: Use this master key file instead of '~/.frodo/masterkey.key' file. + FRODO_MASTER_KEY: Use this master key instead of what's in '~/.frodo/masterkey.key'. Takes precedence over FRODO_MASTER_KEY_PATH. + +" +`; diff --git a/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap b/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap new file mode 100644 index 000000000..5a6938745 --- /dev/null +++ b/test/client_cli/en/__snapshots__/config-manager-push.test.js.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CLI help interface for 'config-manager push' should be expected english 1`] = ` +"Usage: frodo config-manager push [options] [command] + +Export cloud configuration using fr-config-manager. + +Options: + -h, --help Help + +Commands: + help display help for command + terms-and-conditions Import ui-configuration objects. + themes Import themes. + ui-config Import ui-configuration objects. +" +`; diff --git a/test/client_cli/en/config-manager-push-terms-and-conditions.test.js b/test/client_cli/en/config-manager-push-terms-and-conditions.test.js new file mode 100644 index 000000000..a6e13f1c1 --- /dev/null +++ b/test/client_cli/en/config-manager-push-terms-and-conditions.test.js @@ -0,0 +1,10 @@ +import cp from 'child_process'; +import { promisify } from 'util'; + +const exec = promisify(cp.exec); +const CMD = 'frodo config-manager push terms-and-conditions --help'; +const { stdout } = await exec(CMD); + +test("CLI help interface for 'config-manager push terms-and-conditions' should be expected english", async () => { + expect(stdout).toMatchSnapshot(); +}); diff --git a/test/client_cli/en/config-manager-push-themes.test.js b/test/client_cli/en/config-manager-push-themes.test.js new file mode 100644 index 000000000..cb9d2e8ee --- /dev/null +++ b/test/client_cli/en/config-manager-push-themes.test.js @@ -0,0 +1,10 @@ +import cp from 'child_process'; +import { promisify } from 'util'; + +const exec = promisify(cp.exec); +const CMD = 'frodo config-manager push themes --help'; +const { stdout } = await exec(CMD); + +test("CLI help interface for 'config-manager push themes' should be expected english", async () => { + expect(stdout).toMatchSnapshot(); +}); diff --git a/test/client_cli/en/config-manager-push.test.js b/test/client_cli/en/config-manager-push.test.js new file mode 100644 index 000000000..7e575b7fd --- /dev/null +++ b/test/client_cli/en/config-manager-push.test.js @@ -0,0 +1,10 @@ +import cp from 'child_process'; +import { promisify } from 'util'; + +const exec = promisify(cp.exec); +const CMD = 'frodo config-manager push --help'; +const { stdout } = await exec(CMD); + +test("CLI help interface for 'config-manager push' should be expected english", async () => { + expect(stdout).toMatchSnapshot(); +}); diff --git a/test/e2e/exports/fr-config-manager/access-config/access.json b/test/e2e/exports/fr-config-manager/access-config/access.json new file mode 100644 index 000000000..6816b27b1 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/access-config/access.json @@ -0,0 +1,334 @@ +{ + "_id": "access", + "configs": [ + { + "actions": "", + "methods": "read", + "pattern": "health", + "roles": "*" + }, + { + "actions": "*", + "methods": "read", + "pattern": "info/*", + "roles": "*" + }, + { + "actions": "login,logout", + "methods": "read,action", + "pattern": "authentication", + "roles": "*" + }, + { + "actions": "*", + "methods": "read", + "pattern": "config/ui/themeconfig", + "roles": "*" + }, + { + "actions": "*", + "methods": "read", + "pattern": "config/ui/themerealm", + "roles": "*" + }, + { + "actions": "*", + "methods": "read", + "pattern": "config/ui/theme-*", + "roles": "*" + }, + { + "actions": "*", + "methods": "read", + "pattern": "config/uilocale/*", + "roles": "*" + }, + { + "actions": "*", + "methods": "read", + "pattern": "config/fieldPolicy/*", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "*", + "methods": "read", + "pattern": "info/uiconfig", + "roles": "*" + }, + { + "actions": "*", + "methods": "read", + "pattern": "config/ui/dashboard", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "*", + "methods": "query", + "pattern": "info/features", + "roles": "*" + }, + { + "actions": "listPrivileges", + "methods": "action", + "pattern": "privilege", + "roles": "*" + }, + { + "actions": "*", + "methods": "read", + "pattern": "privilege/*", + "roles": "*" + }, + { + "actions": "validate", + "methods": "action", + "pattern": "util/validateQueryFilter", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "*", + "customAuthz": "checkIfAnyFeatureEnabled('kba')", + "methods": "read", + "pattern": "selfservice/kba", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "", + "customAuthz": "isMyProfile()", + "methods": "read,query", + "pattern": "profile/*", + "roles": "*" + }, + { + "actions": "*", + "methods": "read", + "pattern": "schema/*", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "*", + "methods": "action,query", + "pattern": "consent", + "roles": "internal/role/openidm-authorized" + }, + { + "customAuthz": "checkIfApiRequest()", + "methods": "read", + "pattern": "*", + "roles": "internal/role/openidm-admin" + }, + { + "methods": "read", + "pattern": "*", + "roles": "~rcsclient-authorized", + "servlet": "openicf" + }, + { + "actions": "*", + "excludePatterns": "repo,repo/*,file/iwa/*", + "methods": "*", + "pattern": "*", + "roles": "internal/role/openidm-admin" + }, + { + "actions": "", + "methods": "create,read,update,delete,patch,query", + "pattern": "system/*", + "roles": "internal/role/openidm-admin" + }, + { + "actions": "*", + "methods": "script", + "pattern": "system/*", + "roles": "internal/role/openidm-admin" + }, + { + "actions": "test,testConfig,createconfiguration,liveSync,authenticate", + "methods": "action", + "pattern": "system/*", + "roles": "internal/role/openidm-admin" + }, + { + "actions": "*", + "customAuthz": "disallowCommandAction()", + "methods": "*", + "pattern": "repo", + "roles": "internal/role/openidm-admin" + }, + { + "actions": "*", + "customAuthz": "disallowCommandAction()", + "methods": "*", + "pattern": "repo/*", + "roles": "internal/role/openidm-admin" + }, + { + "actions": "command", + "customAuthz": "request.additionalParameters.commandId === 'delete-mapping-links'", + "methods": "action", + "pattern": "repo/link", + "roles": "internal/role/openidm-admin" + }, + { + "methods": "create,read,query,patch", + "pattern": "managed/*", + "roles": "internal/role/platform-provisioning" + }, + { + "methods": "read,query", + "pattern": "internal/role/*", + "roles": "internal/role/platform-provisioning" + }, + { + "actions": "*", + "methods": "create,read,action,update", + "pattern": "profile/*", + "roles": "internal/role/platform-provisioning" + }, + { + "actions": "*", + "methods": "read,action", + "pattern": "policy/*", + "roles": "internal/role/platform-provisioning" + }, + { + "methods": "read", + "pattern": "schema/*", + "roles": "internal/role/platform-provisioning" + }, + { + "actions": "*", + "methods": "action,query", + "pattern": "consent", + "roles": "internal/role/platform-provisioning" + }, + { + "methods": "read", + "pattern": "selfservice/kba", + "roles": "internal/role/platform-provisioning" + }, + { + "methods": "read", + "pattern": "selfservice/terms", + "roles": "internal/role/platform-provisioning" + }, + { + "methods": "read", + "pattern": "identityProviders", + "roles": "internal/role/platform-provisioning" + }, + { + "actions": "sendTemplate", + "methods": "action", + "pattern": "external/email", + "roles": "internal/role/platform-provisioning" + }, + { + "actions": "authenticate", + "methods": "action", + "pattern": "system/*", + "roles": "internal/role/platform-provisioning" + }, + { + "actions": "*", + "methods": "read,action", + "pattern": "policy/*", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "*", + "methods": "read", + "pattern": "config/ui/*", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "bind,unbind", + "customAuthz": "ownDataOnly()", + "methods": "read,action,delete", + "pattern": "*", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "patch", + "customAuthz": "ownDataOnly() && onlyEditableManagedObjectProperties('user', [])", + "methods": "update,patch,action", + "pattern": "*", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "*", + "methods": "read", + "pattern": "endpoint/getprocessesforuser", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "*", + "methods": "query", + "pattern": "endpoint/gettasksview", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "complete", + "customAuthz": "isMyTask()", + "methods": "action", + "pattern": "workflow/taskinstance/*", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "*", + "customAuthz": "canUpdateTask()", + "methods": "read,update", + "pattern": "workflow/taskinstance/*", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "*", + "customAuthz": "isAllowedToStartProcess()", + "methods": "create", + "pattern": "workflow/processinstance", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "read", + "customAuthz": "isOneOfMyWorkflows()", + "methods": "*", + "pattern": "workflow/processdefinition/*", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "patch", + "customAuthz": "isQueryOneOf({'managed/user': ['for-userName']}) && restrictPatchToFields(['password'])", + "methods": "patch,action", + "pattern": "managed/user", + "roles": "internal/role/openidm-cert" + }, + { + "actions": "*", + "customAuthz": "ownRelationshipProperty('_meta', false)", + "methods": "read", + "pattern": "internal/usermeta/*", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "*", + "customAuthz": "ownRelationshipProperty('_notifications', true)", + "methods": "read,delete", + "pattern": "internal/notification/*", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "*", + "customAuthz": "ownRelationshipCollection(['_meta','_notifications'])", + "methods": "read,query", + "pattern": "managed/user/*", + "roles": "internal/role/openidm-authorized" + }, + { + "actions": "deleteNotificationsForTarget", + "customAuthz": "request.additionalParameters.target === (context.security.authorization.component + '/' + context.security.authorization.id)", + "methods": "action", + "pattern": "notification", + "roles": "internal/role/openidm-authorized" + } + ] +} diff --git a/test/e2e/exports/fr-config-manager/audit/audit.json b/test/e2e/exports/fr-config-manager/audit/audit.json new file mode 100644 index 000000000..98cb44d9c --- /dev/null +++ b/test/e2e/exports/fr-config-manager/audit/audit.json @@ -0,0 +1,139 @@ +{ + "_id": "audit", + "auditServiceConfig": { + "availableAuditEventHandlers": [ + "org.forgerock.audit.handlers.csv.CsvAuditEventHandler", + "org.forgerock.audit.handlers.jms.JmsAuditEventHandler", + "org.forgerock.audit.handlers.json.JsonAuditEventHandler", + "org.forgerock.audit.handlers.json.stdout.JsonStdoutAuditEventHandler", + "org.forgerock.openidm.audit.impl.RepositoryAuditEventHandler", + "org.forgerock.openidm.audit.impl.RouterAuditEventHandler", + "org.forgerock.audit.handlers.syslog.SyslogAuditEventHandler" + ], + "caseInsensitiveFields": [ + "/access/http/request/headers", + "/access/http/response/headers" + ], + "filterPolicies": { + "value": { + "excludeIf": [ + "/access/http/request/cookies/&{com.iplanet.am.cookie.name}", + "/access/http/request/cookies/session-jwt", + "/access/http/request/headers/&{com.sun.identity.auth.cookieName}", + "/access/http/request/headers/&{com.iplanet.am.cookie.name}", + "/access/http/request/headers/accept-encoding", + "/access/http/request/headers/accept-language", + "/access/http/request/headers/Authorization", + "/access/http/request/headers/cache-control", + "/access/http/request/headers/connection", + "/access/http/request/headers/content-length", + "/access/http/request/headers/content-type", + "/access/http/request/headers/proxy-authorization", + "/access/http/request/headers/X-OpenAM-Password", + "/access/http/request/headers/X-OpenIDM-Password", + "/access/http/request/queryParameters/access_token", + "/access/http/request/queryParameters/IDToken1", + "/access/http/request/queryParameters/id_token_hint", + "/access/http/request/queryParameters/Login.Token1", + "/access/http/request/queryParameters/redirect_uri", + "/access/http/request/queryParameters/requester", + "/access/http/request/queryParameters/sessionUpgradeSSOTokenId", + "/access/http/request/queryParameters/tokenId", + "/access/http/response/headers/Authorization", + "/access/http/response/headers/Set-Cookie", + "/access/http/response/headers/X-OpenIDM-Password" + ], + "includeIf": [] + } + }, + "handlerForQueries": "json" + }, + "eventHandlers": [ + { + "class": "org.forgerock.audit.handlers.json.JsonAuditEventHandler", + "config": { + "buffering": { + "maxSize": 100000, + "writeInterval": "100 millis" + }, + "enabled": { + "$bool": "&{openidm.audit.handler.json.enabled|true}" + }, + "logDirectory": "&{idm.data.dir}/audit", + "name": "json", + "topics": [ + "access", + "activity", + "sync", + "authentication", + "config" + ] + } + }, + { + "class": "org.forgerock.openidm.audit.impl.RepositoryAuditEventHandler", + "config": { + "enabled": { + "$bool": "&{openidm.audit.handler.repo.enabled|false}" + }, + "name": "repo", + "topics": [ + "access", + "activity", + "sync", + "authentication", + "config" + ] + } + }, + { + "class": "org.forgerock.audit.handlers.json.stdout.JsonStdoutAuditEventHandler", + "config": { + "elasticsearchCompatible": false, + "enabled": { + "$bool": "&{openidm.audit.handler.stdout.enabled|false}" + }, + "name": "json-stdout", + "topics": [ + "config", + "activity", + "authentication", + "access", + "sync" + ] + } + } + ], + "eventTopics": { + "activity": { + "filter": { + "actions": [ + "create", + "update", + "delete", + "patch", + "action" + ] + }, + "passwordFields": [ + "password" + ], + "watchedFields": [] + }, + "config": { + "filter": { + "actions": [ + "create", + "update", + "delete", + "patch", + "action" + ] + } + } + }, + "exceptionFormatter": { + "file": "bin/defaults/script/audit/stacktraceFormatter.js", + "type": "text/javascript" + } +} diff --git a/test/e2e/exports/fr-config-manager/cors/cors-config.json b/test/e2e/exports/fr-config-manager/cors/cors-config.json new file mode 100644 index 000000000..3efaf3a75 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/cors/cors-config.json @@ -0,0 +1,68 @@ +{ + "corsServiceGlobal": { + "_id": "", + "_rev": "515901845", + "_type": { + "_id": "CorsService", + "collection": false, + "name": "CORS Service" + }, + "enabled": true + }, + "corsServices": [ + { + "_id": "cors", + "_type": { + "_id": "configuration", + "collection": true, + "name": "Cors Configuration" + }, + "acceptedHeaders": [ + "authorization", + "x-openidm-username", + "if-none-match", + "x-openidm-nosession", + "x-openidm-password", + "accept-api-version", + "x-requested-with", + "content-type", + "if-match", + "cache-control" + ], + "acceptedMethods": [ + "HEAD", + "DELETE", + "POST", + "GET", + "PUT", + "PATCH" + ], + "acceptedOrigins": [ + "http://localhost:8083", + "http://localhost:8888", + "http://localhost:8082" + ], + "allowCredentials": true, + "enabled": true, + "exposedHeaders": [ + "WWW-Authenticate" + ], + "maxAge": 600 + } + ], + "idmCorsConfig": { + "_id": "servletfilter/cors", + "filterClass": "org.eclipse.jetty.ee10.servlets.CrossOriginFilter", + "initParams": { + "allowCredentials": false, + "allowedHeaders": "authorization,accept,content-type,origin,x-requested-with,cache-control,accept-api-version,if-match,if-none-match", + "allowedMethods": "GET,POST,PUT,DELETE,PATCH", + "allowedOrigins": "*", + "chainPreflight": false, + "exposedHeaders": "WWW-Authenticate" + }, + "urlPatterns": [ + "/*" + ] + } +} diff --git a/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.css b/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.css new file mode 100644 index 000000000..a2f62ac42 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.css @@ -0,0 +1 @@ +body{background-color:#324054;color:#5e6d82;padding:60px;text-align:center}a{text-decoration:none;color:#109cf1}.content{background-color:#fff;border-radius:4px;margin:0 auto;padding:48px;width:235px} diff --git a/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.en.html b/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.en.html new file mode 100644 index 000000000..dfe8c4d7d --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.en.html @@ -0,0 +1 @@ +{{#if object.userName}}

Your username is '{{object.userName}}'.

{{else}}If you received this email in error, please disregard.{{/if}}

Click here to login

diff --git a/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.en.md b/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.en.md new file mode 100644 index 000000000..59a3cf2b8 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.en.md @@ -0,0 +1 @@ +

{{#if object.userName}}Your username is '{{object.userName}}'.

{{else}}If you received this email in error, please disregard.{{/if}}

Click here to login

diff --git a/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.fr.html b/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.fr.html new file mode 100644 index 000000000..9d3a88dc4 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.fr.html @@ -0,0 +1 @@ +{{#if object.userName}}

Votre nom d'utilisateur est '{{object.userName}}'.

{{else}}Si vous avez reçu cet e-mail par erreur, veuillez ne pas en tenir compte.{{/if}}

Cliquez ici pour vous connecter

diff --git a/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.fr.md b/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.fr.md new file mode 100644 index 000000000..8285f61aa --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.fr.md @@ -0,0 +1 @@ +
{{#if object.userName}}

Votre nom d'utilisateur est '{{object.userName}}'.

{{else}}Si vous avez reçu cet e-mail par erreur, veuillez ne pas en tenir compte.{{/if}}

Cliquez ici pour vous connecter

diff --git a/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.json b/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.json new file mode 100644 index 000000000..17f415d9f --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/forgottenUsername/forgottenUsername.json @@ -0,0 +1,30 @@ +{ + "_id": "emailTemplate/forgottenUsername", + "defaultLocale": "en", + "enabled": true, + "from": "", + "html": { + "en": { + "file": "forgottenUsername.en.html" + }, + "fr": { + "file": "forgottenUsername.fr.html" + } + }, + "message": { + "en": { + "file": "forgottenUsername.en.md" + }, + "fr": { + "file": "forgottenUsername.fr.md" + } + }, + "mimeType": "text/html", + "styles": { + "file": "forgottenUsername.css" + }, + "subject": { + "en": "Account Information - username", + "fr": "Informations sur le compte - nom d'utilisateur" + } +} diff --git a/test/e2e/exports/fr-config-manager/email-templates/registration/registration.css b/test/e2e/exports/fr-config-manager/email-templates/registration/registration.css new file mode 100644 index 000000000..a2f62ac42 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/registration/registration.css @@ -0,0 +1 @@ +body{background-color:#324054;color:#5e6d82;padding:60px;text-align:center}a{text-decoration:none;color:#109cf1}.content{background-color:#fff;border-radius:4px;margin:0 auto;padding:48px;width:235px} diff --git a/test/e2e/exports/fr-config-manager/email-templates/registration/registration.en.html b/test/e2e/exports/fr-config-manager/email-templates/registration/registration.en.html new file mode 100644 index 000000000..734225401 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/registration/registration.en.html @@ -0,0 +1 @@ +

This is your registration email.

Email verification link

diff --git a/test/e2e/exports/fr-config-manager/email-templates/registration/registration.en.md b/test/e2e/exports/fr-config-manager/email-templates/registration/registration.en.md new file mode 100644 index 000000000..48cd9cfb4 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/registration/registration.en.md @@ -0,0 +1 @@ +

Click to reset your password

Password reset link

diff --git a/test/e2e/exports/fr-config-manager/email-templates/registration/registration.fr.html b/test/e2e/exports/fr-config-manager/email-templates/registration/registration.fr.html new file mode 100644 index 000000000..a722e280a --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/registration/registration.fr.html @@ -0,0 +1 @@ +

Ceci est votre mail d'inscription.

Lien de vérification email

diff --git a/test/e2e/exports/fr-config-manager/email-templates/registration/registration.fr.md b/test/e2e/exports/fr-config-manager/email-templates/registration/registration.fr.md new file mode 100644 index 000000000..e1b6620c1 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/registration/registration.fr.md @@ -0,0 +1 @@ +

Cliquez pour réinitialiser votre mot de passe

Mot de passe lien de réinitialisation

diff --git a/test/e2e/exports/fr-config-manager/email-templates/registration/registration.json b/test/e2e/exports/fr-config-manager/email-templates/registration/registration.json new file mode 100644 index 000000000..827e616c3 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/registration/registration.json @@ -0,0 +1,30 @@ +{ + "_id": "emailTemplate/registration", + "defaultLocale": "en", + "enabled": true, + "from": "", + "html": { + "en": { + "file": "registration.en.html" + }, + "fr": { + "file": "registration.fr.html" + } + }, + "message": { + "en": { + "file": "registration.en.md" + }, + "fr": { + "file": "registration.fr.md" + } + }, + "mimeType": "text/html", + "styles": { + "file": "registration.css" + }, + "subject": { + "en": "Register new account", + "fr": "Créer un nouveau compte" + } +} diff --git a/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.css b/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.css new file mode 100644 index 000000000..a2f62ac42 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.css @@ -0,0 +1 @@ +body{background-color:#324054;color:#5e6d82;padding:60px;text-align:center}a{text-decoration:none;color:#109cf1}.content{background-color:#fff;border-radius:4px;margin:0 auto;padding:48px;width:235px} diff --git a/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.en.html b/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.en.html new file mode 100644 index 000000000..f4dafcd19 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.en.html @@ -0,0 +1 @@ +

Click to reset your password

Password reset link

diff --git a/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.en.md b/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.en.md new file mode 100644 index 000000000..48cd9cfb4 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.en.md @@ -0,0 +1 @@ +

Click to reset your password

Password reset link

diff --git a/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.fr.html b/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.fr.html new file mode 100644 index 000000000..bbac16071 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.fr.html @@ -0,0 +1 @@ +

Cliquez pour réinitialiser votre mot de passe

Mot de passe lien de réinitialisation

diff --git a/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.fr.md b/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.fr.md new file mode 100644 index 000000000..e1b6620c1 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.fr.md @@ -0,0 +1 @@ +

Cliquez pour réinitialiser votre mot de passe

Mot de passe lien de réinitialisation

diff --git a/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.json b/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.json new file mode 100644 index 000000000..3934c14fb --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/resetPassword/resetPassword.json @@ -0,0 +1,30 @@ +{ + "_id": "emailTemplate/resetPassword", + "defaultLocale": "en", + "enabled": true, + "from": "", + "html": { + "en": { + "file": "resetPassword.en.html" + }, + "fr": { + "file": "resetPassword.fr.html" + } + }, + "message": { + "en": { + "file": "resetPassword.en.md" + }, + "fr": { + "file": "resetPassword.fr.md" + } + }, + "mimeType": "text/html", + "styles": { + "file": "resetPassword.css" + }, + "subject": { + "en": "Reset your password", + "fr": "Réinitialisez votre mot de passe" + } +} diff --git a/test/e2e/exports/fr-config-manager/email-templates/updatePassword/updatePassword.css b/test/e2e/exports/fr-config-manager/email-templates/updatePassword/updatePassword.css new file mode 100644 index 000000000..a2f62ac42 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/updatePassword/updatePassword.css @@ -0,0 +1 @@ +body{background-color:#324054;color:#5e6d82;padding:60px;text-align:center}a{text-decoration:none;color:#109cf1}.content{background-color:#fff;border-radius:4px;margin:0 auto;padding:48px;width:235px} diff --git a/test/e2e/exports/fr-config-manager/email-templates/updatePassword/updatePassword.en.html b/test/e2e/exports/fr-config-manager/email-templates/updatePassword/updatePassword.en.html new file mode 100644 index 000000000..6c570f8d1 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/updatePassword/updatePassword.en.html @@ -0,0 +1 @@ +

Verify email to update password

Update password link

diff --git a/test/e2e/exports/fr-config-manager/email-templates/updatePassword/updatePassword.en.md b/test/e2e/exports/fr-config-manager/email-templates/updatePassword/updatePassword.en.md new file mode 100644 index 000000000..58f5c3df8 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/updatePassword/updatePassword.en.md @@ -0,0 +1 @@ +

Verify email to update password

Update password link

diff --git a/test/e2e/exports/fr-config-manager/email-templates/updatePassword/updatePassword.json b/test/e2e/exports/fr-config-manager/email-templates/updatePassword/updatePassword.json new file mode 100644 index 000000000..35714cf1e --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/updatePassword/updatePassword.json @@ -0,0 +1,23 @@ +{ + "_id": "emailTemplate/updatePassword", + "defaultLocale": "en", + "enabled": true, + "from": "", + "html": { + "en": { + "file": "updatePassword.en.html" + } + }, + "message": { + "en": { + "file": "updatePassword.en.md" + } + }, + "mimeType": "text/html", + "styles": { + "file": "updatePassword.css" + }, + "subject": { + "en": "Update your password" + } +} diff --git a/test/e2e/exports/fr-config-manager/email-templates/welcome/welcome.css b/test/e2e/exports/fr-config-manager/email-templates/welcome/welcome.css new file mode 100644 index 000000000..a2f62ac42 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/welcome/welcome.css @@ -0,0 +1 @@ +body{background-color:#324054;color:#5e6d82;padding:60px;text-align:center}a{text-decoration:none;color:#109cf1}.content{background-color:#fff;border-radius:4px;margin:0 auto;padding:48px;width:235px} diff --git a/test/e2e/exports/fr-config-manager/email-templates/welcome/welcome.en.html b/test/e2e/exports/fr-config-manager/email-templates/welcome/welcome.en.html new file mode 100644 index 000000000..e0ddd3350 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/welcome/welcome.en.html @@ -0,0 +1 @@ +

Welcome to OpenIDM. Your username is '{{object.userName}}'.

diff --git a/test/e2e/exports/fr-config-manager/email-templates/welcome/welcome.en.md b/test/e2e/exports/fr-config-manager/email-templates/welcome/welcome.en.md new file mode 100644 index 000000000..e77c911f9 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/welcome/welcome.en.md @@ -0,0 +1 @@ +

Welcome to OpenIDM. Your username is '{{object.userName}}'.

diff --git a/test/e2e/exports/fr-config-manager/email-templates/welcome/welcome.json b/test/e2e/exports/fr-config-manager/email-templates/welcome/welcome.json new file mode 100644 index 000000000..ce5e0eefc --- /dev/null +++ b/test/e2e/exports/fr-config-manager/email-templates/welcome/welcome.json @@ -0,0 +1,23 @@ +{ + "_id": "emailTemplate/welcome", + "defaultLocale": "en", + "enabled": true, + "from": "", + "html": { + "en": { + "file": "welcome.en.html" + } + }, + "message": { + "en": { + "file": "welcome.en.md" + } + }, + "mimeType": "text/html", + "styles": { + "file": "welcome.css" + }, + "subject": { + "en": "Your account has been created" + } +} diff --git a/test/e2e/exports/fr-config-manager/endpoints/linkedView/linkedView.js b/test/e2e/exports/fr-config-manager/endpoints/linkedView/linkedView.js new file mode 100644 index 000000000..1de3e8f40 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/endpoints/linkedView/linkedView.js @@ -0,0 +1 @@ +require('linkedView').fetch(request.resourcePath); diff --git a/test/e2e/exports/fr-config-manager/endpoints/linkedView/linkedView.json b/test/e2e/exports/fr-config-manager/endpoints/linkedView/linkedView.json new file mode 100644 index 000000000..d4a5f7fbf --- /dev/null +++ b/test/e2e/exports/fr-config-manager/endpoints/linkedView/linkedView.json @@ -0,0 +1,6 @@ +{ + "_id": "endpoint/linkedView", + "context": "endpoint/linkedView/*", + "file": "linkedView.js", + "type": "text/javascript" +} diff --git a/test/e2e/exports/fr-config-manager/endpoints/mappingDetails/mappingDetails.js b/test/e2e/exports/fr-config-manager/endpoints/mappingDetails/mappingDetails.js new file mode 100644 index 000000000..417b7b537 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/endpoints/mappingDetails/mappingDetails.js @@ -0,0 +1 @@ +undefined diff --git a/test/e2e/exports/fr-config-manager/endpoints/mappingDetails/mappingDetails.json b/test/e2e/exports/fr-config-manager/endpoints/mappingDetails/mappingDetails.json new file mode 100644 index 000000000..d1ef39274 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/endpoints/mappingDetails/mappingDetails.json @@ -0,0 +1,6 @@ +{ + "_id": "endpoint/mappingDetails", + "context": "endpoint/mappingDetails", + "file": "mappingDetails.js", + "type": "text/javascript" +} diff --git a/test/e2e/exports/fr-config-manager/endpoints/oauthproxy/oauthproxy.js b/test/e2e/exports/fr-config-manager/endpoints/oauthproxy/oauthproxy.js new file mode 100644 index 000000000..417b7b537 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/endpoints/oauthproxy/oauthproxy.js @@ -0,0 +1 @@ +undefined diff --git a/test/e2e/exports/fr-config-manager/endpoints/oauthproxy/oauthproxy.json b/test/e2e/exports/fr-config-manager/endpoints/oauthproxy/oauthproxy.json new file mode 100644 index 000000000..de3a43761 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/endpoints/oauthproxy/oauthproxy.json @@ -0,0 +1,6 @@ +{ + "_id": "endpoint/oauthproxy", + "context": "endpoint/oauthproxy", + "file": "oauthproxy.js", + "type": "text/javascript" +} diff --git a/test/e2e/exports/fr-config-manager/endpoints/validateQueryFilter/validateQueryFilter.js b/test/e2e/exports/fr-config-manager/endpoints/validateQueryFilter/validateQueryFilter.js new file mode 100644 index 000000000..ceaa293b5 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/endpoints/validateQueryFilter/validateQueryFilter.js @@ -0,0 +1 @@ +try { org.forgerock.openidm.query.StringQueryFilters.parse(request.content._queryFilter).accept(new org.forgerock.util.query.MapFilterVisitor(), null); } catch (e) { throw { 'code' : 400, 'message' : e.message } }; diff --git a/test/e2e/exports/fr-config-manager/endpoints/validateQueryFilter/validateQueryFilter.json b/test/e2e/exports/fr-config-manager/endpoints/validateQueryFilter/validateQueryFilter.json new file mode 100644 index 000000000..e16633066 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/endpoints/validateQueryFilter/validateQueryFilter.json @@ -0,0 +1,6 @@ +{ + "_id": "endpoint/validateQueryFilter", + "context": "util/validateQueryFilter", + "file": "validateQueryFilter.js", + "type": "text/javascript" +} diff --git a/test/e2e/exports/fr-config-manager/kba/selfservice.kba.json b/test/e2e/exports/fr-config-manager/kba/selfservice.kba.json new file mode 100644 index 000000000..b518ddfcd --- /dev/null +++ b/test/e2e/exports/fr-config-manager/kba/selfservice.kba.json @@ -0,0 +1,16 @@ +{ + "_id": "selfservice.kba", + "kbaPropertyName": "kbaInfo", + "minimumAnswersToDefine": 2, + "minimumAnswersToVerify": 1, + "questions": { + "1": { + "en": "What's your favorite color?", + "en_GB": "What is your favourite colour?", + "fr": "Quelle est votre couleur préférée?" + }, + "2": { + "en": "Who was your first employer?" + } + } +} diff --git a/test/e2e/exports/fr-config-manager/managed-objects/application/application.json b/test/e2e/exports/fr-config-manager/managed-objects/application/application.json new file mode 100644 index 000000000..9db86d5d0 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/managed-objects/application/application.json @@ -0,0 +1,331 @@ +{ + "name": "application", + "schema": { + "$schema": "http://forgerock.org/json-schema#", + "icon": "fa-folder", + "order": [ + "name", + "description", + "url", + "icon", + "mappingNames", + "owners", + "roles", + "members" + ], + "properties": { + "_id": { + "description": "Application ID", + "isPersonal": false, + "searchable": false, + "type": "string", + "userEditable": false, + "viewable": false + }, + "authoritative": { + "description": "Is this an authoritative application", + "searchable": false, + "title": "Authoritative", + "type": "boolean", + "viewable": false + }, + "connectorId": { + "description": "Id of the connector associated with the application", + "searchable": false, + "title": "Connector ID", + "type": "string", + "userEditable": false, + "viewable": false + }, + "description": { + "description": "Application Description", + "searchable": true, + "title": "Description", + "type": "string", + "viewable": true + }, + "icon": { + "searchable": true, + "title": "Icon", + "type": "string", + "userEditable": true, + "viewable": true + }, + "mappingNames": { + "description": "Names of the sync mappings used by an application with provisioning configured.", + "items": { + "title": "Mapping Name Items", + "type": "string" + }, + "searchable": true, + "title": "Sync Mapping Names", + "type": "array", + "viewable": true + }, + "members": { + "description": "Members directly granted an application", + "items": { + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:Application:members:items", + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_accountType": { + "description": "Account type", + "type": "string" + }, + "_grantType": { + "description": "Grant Type", + "label": "Grant Type", + "type": "string" + }, + "_id": { + "propName": "_id", + "required": false, + "type": "string" + }, + "_uniqueId": { + "description": "Unique identifier", + "type": "string" + } + }, + "title": "Application Members Items _refProperties", + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "User", + "notify": true, + "path": "managed/user", + "query": { + "fields": [ + "userName", + "givenName", + "sn" + ], + "queryFilter": "true" + } + } + ], + "reversePropertyName": "applications", + "reverseRelationship": true, + "title": "Application Members Items", + "type": "relationship", + "validate": true + }, + "policies": [], + "returnByDefault": false, + "searchable": false, + "title": "Members", + "type": "array", + "userEditable": false, + "viewable": true + }, + "name": { + "description": "Application name", + "notifyRelationships": [ + "roles", + "members" + ], + "policies": [ + { + "policyId": "unique" + } + ], + "returnByDefault": true, + "searchable": true, + "title": "Name", + "type": "string", + "userEditable": true, + "viewable": true + }, + "owners": { + "description": "Application Owners", + "items": { + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_id": { + "type": "string" + } + }, + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "User", + "path": "managed/user", + "query": { + "fields": [ + "userName", + "givenName", + "sn" + ], + "queryFilter": "true" + } + } + ], + "reversePropertyName": "ownerOfApp", + "reverseRelationship": true, + "type": "relationship", + "validate": true + }, + "returnByDefault": false, + "searchable": false, + "title": "Owners", + "type": "array", + "userEditable": false, + "viewable": true + }, + "roles": { + "description": "Roles granting users the application", + "items": { + "notifySelf": true, + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_accountType": { + "description": "Account type", + "type": "string" + }, + "_id": { + "propName": "_id", + "required": false, + "type": "string" + } + }, + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "Role", + "notify": true, + "path": "managed/role", + "query": { + "fields": [ + "name" + ], + "queryFilter": "true", + "sortKeys": [] + } + } + ], + "reversePropertyName": "applications", + "reverseRelationship": true, + "type": "relationship", + "validate": true + }, + "returnByDefault": false, + "searchable": false, + "title": "Roles", + "type": "array", + "userEditable": false, + "viewable": true + }, + "ssoEntities": { + "description": "SSO Entity Id", + "properties": { + "domain": { + "type": "string" + }, + "federatedDomain": { + "type": "string" + }, + "idpLocation": { + "type": "string" + }, + "idpLoginUrl": { + "type": "string" + }, + "idpPrivateId": { + "type": "string" + }, + "key": { + "type": "string" + }, + "oidcId": { + "type": "string" + }, + "pfApcId": { + "type": "string" + }, + "pfIdpAdapterId": { + "type": "string" + }, + "pfPolicyId": { + "type": "string" + }, + "pfSigningCertId": { + "type": "string" + }, + "pfSpConnectionId": { + "type": "string" + }, + "spLocation": { + "type": "string" + }, + "spPrivate": { + "type": "string" + }, + "spPrivateId": { + "type": "string" + } + }, + "searchable": false, + "title": "SSO Entity Id", + "type": "object", + "userEditable": false, + "viewable": false + }, + "templateName": { + "description": "Name of the template the application was created from", + "searchable": false, + "title": "Template Name", + "type": "string", + "userEditable": false, + "viewable": false + }, + "templateVersion": { + "description": "The template version", + "searchable": false, + "title": "Template Version", + "type": "string", + "userEditable": false, + "viewable": false + }, + "uiConfig": { + "description": "UI Config", + "isPersonal": false, + "properties": {}, + "searchable": false, + "title": "UI Config", + "type": "object", + "usageDescription": "", + "viewable": false + }, + "url": { + "searchable": true, + "title": "Url", + "type": "string", + "userEditable": true, + "viewable": true + } + }, + "required": [ + "name" + ], + "title": "Application", + "type": "object" + } +} diff --git a/test/e2e/exports/fr-config-manager/managed-objects/assignment/assignment.json b/test/e2e/exports/fr-config-manager/managed-objects/assignment/assignment.json new file mode 100644 index 000000000..23d70281c --- /dev/null +++ b/test/e2e/exports/fr-config-manager/managed-objects/assignment/assignment.json @@ -0,0 +1,254 @@ +{ + "attributeEncryption": {}, + "name": "assignment", + "schema": { + "$schema": "http://forgerock.org/json-schema#", + "description": "A role assignment", + "icon": "fa-key", + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:Assignment", + "mat-icon": "vpn_key", + "order": [ + "_id", + "name", + "description", + "type", + "mapping", + "attributes", + "linkQualifiers", + "roles", + "members", + "condition", + "weight" + ], + "properties": { + "_id": { + "description": "The assignment ID", + "searchable": false, + "title": "Name", + "type": "string", + "viewable": false + }, + "attributes": { + "description": "The attributes operated on by this assignment.", + "items": { + "order": [ + "assignmentOperation", + "unassignmentOperation", + "name", + "value" + ], + "properties": { + "assignmentOperation": { + "description": "Assignment operation", + "type": "string" + }, + "name": { + "description": "Name", + "type": "string" + }, + "unassignmentOperation": { + "description": "Unassignment operation", + "type": "string" + }, + "value": { + "description": "Value", + "type": "string" + } + }, + "required": [], + "title": "Assignment Attributes Items", + "type": "object" + }, + "notifyRelationships": [ + "roles", + "members" + ], + "title": "Assignment Attributes", + "type": "array", + "viewable": true + }, + "condition": { + "description": "A conditional filter for this assignment", + "isConditional": true, + "searchable": false, + "title": "Condition", + "type": "string", + "viewable": false + }, + "description": { + "description": "The assignment description, used for display purposes.", + "searchable": true, + "title": "Description", + "type": "string", + "viewable": true + }, + "linkQualifiers": { + "description": "Conditional link qualifiers to restrict this assignment to.", + "items": { + "title": "Link Qualifiers Items", + "type": "string" + }, + "title": "Link Qualifiers", + "type": "array", + "viewable": true + }, + "mapping": { + "description": "The name of the mapping this assignment applies to", + "policies": [ + { + "policyId": "mapping-exists" + } + ], + "searchable": true, + "title": "Mapping", + "type": "string", + "viewable": true + }, + "members": { + "description": "Assignment Members", + "items": { + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:Assignment:members:items", + "properties": { + "_ref": { + "description": "References a relationship from a managed object", + "type": "string" + }, + "_refProperties": { + "description": "Supports metadata within the relationship", + "properties": { + "_accountType": { + "description": "Account type", + "type": "string" + }, + "_grantType": { + "description": "Grant Type", + "label": "Grant Type", + "type": "string" + }, + "_id": { + "description": "_refProperties object ID", + "type": "string" + }, + "_uniqueId": { + "description": "Unique identifier", + "type": "string" + } + }, + "title": "Assignment Members Items _refProperties", + "type": "object" + } + }, + "resourceCollection": [ + { + "conditionalAssociation": true, + "label": "User", + "notify": true, + "path": "managed/user", + "query": { + "fields": [ + "userName", + "givenName", + "sn" + ], + "queryFilter": "true" + } + } + ], + "reversePropertyName": "assignments", + "reverseRelationship": true, + "title": "Assignment Members Items", + "type": "relationship", + "validate": true + }, + "returnByDefault": false, + "title": "Assignment Members", + "type": "array", + "viewable": true + }, + "name": { + "description": "The assignment name, used for display purposes.", + "searchable": true, + "title": "Name", + "type": "string", + "viewable": true + }, + "roles": { + "description": "Managed Roles", + "items": { + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:Assignment:roles:items", + "properties": { + "_ref": { + "description": "References a relationship from a managed object", + "type": "string" + }, + "_refProperties": { + "description": "Supports metadata within the relationship", + "properties": { + "_accountType": { + "description": "Account type", + "type": "string" + }, + "_id": { + "description": "_refProperties object ID", + "type": "string" + } + }, + "title": "Managed Roles Items _refProperties", + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "Role", + "notify": true, + "path": "managed/role", + "query": { + "fields": [ + "name" + ], + "queryFilter": "true" + } + } + ], + "reversePropertyName": "assignments", + "reverseRelationship": true, + "title": "Managed Roles Items", + "type": "relationship", + "validate": true + }, + "returnByDefault": false, + "title": "Managed Roles", + "type": "array", + "userEditable": false, + "viewable": true + }, + "type": { + "description": "The type of object this assignment represents", + "title": "Type", + "type": "string", + "viewable": true + }, + "weight": { + "description": "The weight of the assignment.", + "notifyRelationships": [ + "roles", + "members" + ], + "searchable": false, + "title": "Weight", + "type": [ + "number", + "null" + ], + "viewable": true + } + }, + "required": [ + "name", + "description", + "mapping" + ], + "title": "Assignment", + "type": "object" + } +} diff --git a/test/e2e/exports/fr-config-manager/managed-objects/group/group.json b/test/e2e/exports/fr-config-manager/managed-objects/group/group.json new file mode 100644 index 000000000..44cbef27d --- /dev/null +++ b/test/e2e/exports/fr-config-manager/managed-objects/group/group.json @@ -0,0 +1,111 @@ +{ + "name": "group", + "schema": { + "$schema": "http://json-schema.org/draft-03/schema", + "icon": "fa-group", + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:Group", + "mat-icon": "group", + "order": [ + "_id", + "name", + "description", + "condition", + "members" + ], + "properties": { + "_id": { + "description": "Group ID", + "isPersonal": false, + "searchable": false, + "type": "string", + "usageDescription": "", + "userEditable": false, + "viewable": false + }, + "condition": { + "description": "A filter for conditionally assigned members", + "isConditional": true, + "searchable": false, + "title": "Condition", + "type": "string", + "viewable": false + }, + "description": { + "description": "Group Description", + "searchable": true, + "title": "Description", + "type": "string", + "userEditable": false, + "viewable": true + }, + "members": { + "description": "Group Members", + "items": { + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:Group:members:items", + "properties": { + "_ref": { + "description": "References a relationship from a managed object", + "type": "string" + }, + "_refProperties": { + "description": "Supports metadata within the relationship", + "properties": { + "_grantType": { + "description": "Grant Type", + "label": "Grant Type", + "type": "string" + }, + "_id": { + "description": "_refProperties object ID", + "type": "string" + } + }, + "title": "Group Members Items _refProperties", + "type": "object" + } + }, + "resourceCollection": [ + { + "conditionalAssociation": true, + "label": "User", + "notify": true, + "path": "managed/user", + "query": { + "fields": [ + "userName", + "givenName", + "sn" + ], + "queryFilter": "true" + } + } + ], + "reversePropertyName": "groups", + "reverseRelationship": true, + "title": "Group Members Items", + "type": "relationship", + "validate": true + }, + "policies": [], + "returnByDefault": false, + "searchable": false, + "title": "Members", + "type": "array", + "userEditable": false, + "viewable": true + }, + "name": { + "description": "Group Name", + "searchable": true, + "title": "Name", + "type": "string", + "viewable": true + } + }, + "required": [ + "name" + ], + "title": "Group", + "viewable": true + } +} diff --git a/test/e2e/exports/fr-config-manager/managed-objects/organization/organization.json b/test/e2e/exports/fr-config-manager/managed-objects/organization/organization.json new file mode 100644 index 000000000..1c2dc6671 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/managed-objects/organization/organization.json @@ -0,0 +1,395 @@ +{ + "name": "organization", + "schema": { + "$schema": "http://forgerock.org/json-schema#", + "description": "An organization or tenant, whose resources are managed by organizational admins.", + "icon": "fa-building", + "mat-icon": "domain", + "order": [ + "name", + "description", + "owners", + "admins", + "members", + "parent", + "children", + "adminIDs", + "ownerIDs", + "parentAdminIDs", + "parentOwnerIDs", + "parentIDs" + ], + "properties": { + "adminIDs": { + "isVirtual": true, + "items": { + "title": "admin ids", + "type": "string" + }, + "queryConfig": { + "flattenProperties": true, + "referencedObjectFields": [ + "_id" + ], + "referencedRelationshipFields": [ + "admins" + ] + }, + "returnByDefault": true, + "searchable": false, + "title": "Admin user ids", + "type": "array", + "userEditable": false, + "viewable": false + }, + "admins": { + "items": { + "notifySelf": true, + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_id": { + "propName": "_id", + "required": false, + "type": "string" + } + }, + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "User", + "notify": false, + "path": "managed/user", + "query": { + "fields": [ + "userName", + "givenName", + "sn" + ], + "queryFilter": "true", + "sortKeys": [] + } + } + ], + "reversePropertyName": "adminOfOrg", + "reverseRelationship": true, + "type": "relationship", + "validate": true + }, + "notifyRelationships": [ + "children" + ], + "returnByDefault": false, + "searchable": false, + "title": "Administrators", + "type": "array", + "userEditable": false, + "viewable": true + }, + "children": { + "description": "Child Organizations", + "items": { + "notifySelf": true, + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_id": { + "propName": "_id", + "required": false, + "type": "string" + } + }, + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "Organization", + "notify": true, + "path": "managed/organization", + "query": { + "fields": [ + "name", + "description" + ], + "queryFilter": "true", + "sortKeys": [] + } + } + ], + "reversePropertyName": "parent", + "reverseRelationship": true, + "type": "relationship", + "validate": true + }, + "policies": [], + "returnByDefault": false, + "searchable": false, + "title": "Child Organizations", + "type": "array", + "userEditable": false, + "viewable": false + }, + "description": { + "searchable": true, + "title": "Description", + "type": "string", + "userEditable": true, + "viewable": true + }, + "members": { + "items": { + "notifySelf": false, + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_id": { + "propName": "_id", + "required": false, + "type": "string" + } + }, + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "User", + "notify": true, + "path": "managed/user", + "query": { + "fields": [ + "userName", + "givenName", + "sn" + ], + "queryFilter": "true", + "sortKeys": [] + } + } + ], + "reversePropertyName": "memberOfOrg", + "reverseRelationship": true, + "type": "relationship", + "validate": true + }, + "returnByDefault": false, + "searchable": false, + "title": "Members", + "type": "array", + "userEditable": false, + "viewable": true + }, + "name": { + "searchable": true, + "title": "Name", + "type": "string", + "userEditable": true, + "viewable": true + }, + "ownerIDs": { + "isVirtual": true, + "items": { + "title": "owner ids", + "type": "string" + }, + "queryConfig": { + "flattenProperties": true, + "referencedObjectFields": [ + "_id" + ], + "referencedRelationshipFields": [ + "owners" + ] + }, + "returnByDefault": true, + "searchable": false, + "title": "Owner user ids", + "type": "array", + "userEditable": false, + "viewable": false + }, + "owners": { + "items": { + "notifySelf": true, + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_id": { + "propName": "_id", + "required": false, + "type": "string" + } + }, + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "User", + "notify": false, + "path": "managed/user", + "query": { + "fields": [ + "userName", + "givenName", + "sn" + ], + "queryFilter": "true", + "sortKeys": [] + } + } + ], + "reversePropertyName": "ownerOfOrg", + "reverseRelationship": true, + "type": "relationship", + "validate": true + }, + "notifyRelationships": [ + "children" + ], + "returnByDefault": false, + "searchable": false, + "title": "Owner", + "type": "array", + "userEditable": false, + "viewable": true + }, + "parent": { + "description": "Parent Organization", + "notifyRelationships": [ + "children", + "members" + ], + "notifySelf": true, + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_id": { + "propName": "_id", + "required": false, + "type": "string" + } + }, + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "Organization", + "notify": true, + "path": "managed/organization", + "query": { + "fields": [ + "name", + "description" + ], + "queryFilter": "true", + "sortKeys": [] + } + } + ], + "returnByDefault": false, + "reversePropertyName": "children", + "reverseRelationship": true, + "searchable": false, + "title": "Parent Organization", + "type": "relationship", + "userEditable": false, + "validate": true, + "viewable": true + }, + "parentAdminIDs": { + "isVirtual": true, + "items": { + "title": "user ids of parent admins", + "type": "string" + }, + "queryConfig": { + "flattenProperties": true, + "referencedObjectFields": [ + "adminIDs", + "parentAdminIDs" + ], + "referencedRelationshipFields": [ + "parent" + ] + }, + "returnByDefault": true, + "searchable": false, + "title": "user ids of parent admins", + "type": "array", + "userEditable": false, + "viewable": false + }, + "parentIDs": { + "isVirtual": true, + "items": { + "title": "parent org ids", + "type": "string" + }, + "queryConfig": { + "flattenProperties": true, + "referencedObjectFields": [ + "_id", + "parentIDs" + ], + "referencedRelationshipFields": [ + "parent" + ] + }, + "returnByDefault": true, + "searchable": false, + "title": "parent org ids", + "type": "array", + "userEditable": false, + "viewable": false + }, + "parentOwnerIDs": { + "isVirtual": true, + "items": { + "title": "user ids of parent owners", + "type": "string" + }, + "queryConfig": { + "flattenProperties": true, + "referencedObjectFields": [ + "ownerIDs", + "parentOwnerIDs" + ], + "referencedRelationshipFields": [ + "parent" + ] + }, + "returnByDefault": true, + "searchable": false, + "title": "user ids of parent owners", + "type": "array", + "userEditable": false, + "viewable": false + } + }, + "required": [ + "name" + ], + "title": "Organization", + "type": "object" + } +} diff --git a/test/e2e/exports/fr-config-manager/managed-objects/role/role.json b/test/e2e/exports/fr-config-manager/managed-objects/role/role.json new file mode 100644 index 000000000..3fdc76bf8 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/managed-objects/role/role.json @@ -0,0 +1,244 @@ +{ + "name": "role", + "schema": { + "$schema": "http://forgerock.org/json-schema#", + "description": "", + "icon": "fa-check-square-o", + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:Role", + "mat-icon": "assignment_ind", + "order": [ + "_id", + "name", + "description", + "members", + "assignments", + "applications", + "condition", + "temporalConstraints" + ], + "properties": { + "_id": { + "description": "Role ID", + "searchable": false, + "title": "Name", + "type": "string", + "viewable": false + }, + "applications": { + "description": "Role Applications", + "items": { + "notifySelf": true, + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_accountType": { + "description": "Account type", + "type": "string" + }, + "_id": { + "propName": "_id", + "required": false, + "type": "string" + } + }, + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "Application", + "path": "managed/application", + "query": { + "fields": [ + "name" + ], + "queryFilter": "true" + } + } + ], + "reversePropertyName": "roles", + "reverseRelationship": true, + "title": "Role Application Items", + "type": "relationship", + "validate": true + }, + "notifyRelationships": [ + "members" + ], + "relationshipGrantTemporalConstraintsEnforced": true, + "returnByDefault": false, + "title": "Applications", + "type": "array", + "viewable": false + }, + "assignments": { + "description": "Managed Assignments", + "items": { + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:Role:assignments:items", + "notifySelf": true, + "properties": { + "_ref": { + "description": "References a relationship from a managed object", + "type": "string" + }, + "_refProperties": { + "description": "Supports metadata within the relationship", + "properties": { + "_accountType": { + "description": "Account type", + "type": "string" + }, + "_id": { + "description": "_refProperties object ID", + "type": "string" + } + }, + "title": "Managed Assignments Items _refProperties", + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "Assignment", + "path": "managed/assignment", + "query": { + "fields": [ + "name" + ], + "queryFilter": "true" + } + } + ], + "reversePropertyName": "roles", + "reverseRelationship": true, + "title": "Managed Assignments Items", + "type": "relationship", + "validate": true + }, + "notifyRelationships": [ + "members" + ], + "returnByDefault": false, + "title": "Managed Assignments", + "type": "array", + "viewable": true + }, + "condition": { + "description": "A conditional filter for this role", + "isConditional": true, + "searchable": false, + "title": "Condition", + "type": "string", + "viewable": false + }, + "description": { + "description": "The role description, used for display purposes.", + "searchable": true, + "title": "Description", + "type": "string", + "viewable": true + }, + "members": { + "description": "Role Members", + "items": { + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:Role:members:items", + "properties": { + "_ref": { + "description": "References a relationship from a managed object", + "type": "string" + }, + "_refProperties": { + "description": "Supports metadata within the relationship", + "properties": { + "_grantType": { + "description": "Grant Type", + "label": "Grant Type", + "type": "string" + }, + "_id": { + "description": "_refProperties object ID", + "type": "string" + } + }, + "title": "Role Members Items _refProperties", + "type": "object" + } + }, + "resourceCollection": [ + { + "conditionalAssociation": true, + "label": "User", + "notify": true, + "path": "managed/user", + "query": { + "fields": [ + "userName", + "givenName", + "sn" + ], + "queryFilter": "true" + } + } + ], + "reversePropertyName": "roles", + "reverseRelationship": true, + "title": "Role Members Items", + "type": "relationship", + "validate": true + }, + "relationshipGrantTemporalConstraintsEnforced": true, + "returnByDefault": false, + "title": "Role Members", + "type": "array", + "viewable": true + }, + "name": { + "description": "The role name, used for display purposes.", + "policies": [ + { + "policyId": "unique" + } + ], + "searchable": true, + "title": "Name", + "type": "string", + "viewable": true + }, + "temporalConstraints": { + "description": "An array of temporal constraints for a role", + "isTemporalConstraint": true, + "items": { + "order": [ + "duration" + ], + "properties": { + "duration": { + "description": "Duration", + "type": "string" + } + }, + "required": [ + "duration" + ], + "title": "Temporal Constraints Items", + "type": "object" + }, + "notifyRelationships": [ + "members" + ], + "returnByDefault": true, + "title": "Temporal Constraints", + "type": "array", + "viewable": false + } + }, + "required": [ + "name" + ], + "title": "Role", + "type": "object" + } +} diff --git a/test/e2e/exports/fr-config-manager/managed-objects/user/user.json b/test/e2e/exports/fr-config-manager/managed-objects/user/user.json new file mode 100644 index 000000000..1ddcaf58b --- /dev/null +++ b/test/e2e/exports/fr-config-manager/managed-objects/user/user.json @@ -0,0 +1,1281 @@ +{ + "lastSync": { + "effectiveAssignmentsProperty": "effectiveAssignments", + "lastSyncProperty": "lastSync" + }, + "meta": { + "property": "_meta", + "resourceCollection": "internal/usermeta", + "trackedProperties": [ + "createDate", + "lastChanged" + ] + }, + "name": "user", + "notifications": {}, + "schema": { + "$schema": "http://json-schema.org/draft-03/schema", + "icon": "fa-user", + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:User", + "mat-icon": "people", + "order": [ + "_id", + "userName", + "password", + "givenName", + "cn", + "sn", + "mail", + "profileImage", + "description", + "accountStatus", + "telephoneNumber", + "postalAddress", + "city", + "postalCode", + "country", + "stateProvince", + "assignedDashboard", + "roles", + "assignments", + "groups", + "applications", + "manager", + "authzRoles", + "reports", + "effectiveRoles", + "effectiveAssignments", + "effectiveGroups", + "effectiveApplications", + "lastSync", + "kbaInfo", + "preferences", + "consentedMappings", + "ownerOfOrg", + "adminOfOrg", + "memberOfOrg", + "memberOfOrgIDs", + "activeDate", + "inactiveDate", + "ownerOfApp", + "passwordLastChangedTime", + "passwordExpirationTime", + "devicePrintProfiles", + "deviceProfiles", + "oathDeviceProfiles", + "pushDeviceProfiles", + "webauthnDeviceProfiles" + ], + "properties": { + "_id": { + "description": "User ID", + "isPersonal": false, + "policies": [ + { + "params": { + "forbiddenChars": [ + "/" + ] + }, + "policyId": "cannot-contain-characters" + } + ], + "searchable": false, + "type": "string", + "usageDescription": "", + "userEditable": false, + "viewable": false + }, + "accountStatus": { + "default": "active", + "description": "Status", + "isPersonal": false, + "searchable": false, + "title": "Status", + "type": "string", + "usageDescription": "", + "userEditable": false, + "viewable": true + }, + "activeDate": { + "description": "Active Date", + "format": "datetime", + "isPersonal": false, + "policies": [ + { + "policyId": "valid-datetime" + } + ], + "searchable": false, + "title": "Active Date", + "type": "string", + "usageDescription": "", + "userEditable": false, + "viewable": true + }, + "adminOfOrg": { + "items": { + "notifySelf": false, + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_id": { + "propName": "_id", + "required": false, + "type": "string" + } + }, + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "Organization", + "notify": true, + "path": "managed/organization", + "query": { + "fields": [ + "name" + ], + "queryFilter": "true", + "sortKeys": [] + } + } + ], + "reversePropertyName": "admins", + "reverseRelationship": true, + "type": "relationship", + "validate": true + }, + "policies": [], + "returnByDefault": false, + "searchable": false, + "title": "Organizations I Administer", + "type": "array", + "userEditable": false, + "viewable": true + }, + "aliasList": { + "description": "List of identity aliases used primarily to record social IdP subjects for this user", + "isVirtual": false, + "items": { + "title": "User Alias Names Items", + "type": "string" + }, + "returnByDefault": false, + "searchable": false, + "title": "User Alias Names List", + "type": "array", + "userEditable": true, + "viewable": false + }, + "applications": { + "description": "Applications", + "isPersonal": false, + "items": { + "notifySelf": true, + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_accountType": { + "description": "Account type", + "type": "string" + }, + "_id": { + "propName": "_id", + "required": false, + "type": "string" + }, + "_uniqueId": { + "description": "Unique identifier", + "type": "string" + } + }, + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "Application", + "path": "managed/application", + "query": { + "fields": [ + "name" + ], + "queryFilter": "true", + "sortKeys": [ + "name" + ] + } + } + ], + "reversePropertyName": "members", + "reverseRelationship": true, + "title": "Application Items", + "type": "relationship", + "validate": true + }, + "returnByDefault": false, + "title": "Applications", + "type": "array", + "usageDescription": "", + "userEditable": false, + "viewable": false + }, + "assignedDashboard": { + "description": "List of items to click on for this user", + "isVirtual": true, + "items": { + "title": "Assigned Dashboard Items", + "type": "string" + }, + "queryConfig": { + "flattenProperties": true, + "referencedObjectFields": [ + "name" + ], + "referencedRelationshipFields": [ + [ + "roles", + "applications" + ], + [ + "applications" + ] + ] + }, + "searchable": false, + "title": "Assigned Dashboard", + "type": "array", + "userEditable": false, + "viewable": true + }, + "assignments": { + "description": "Assignments", + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:User:assignments", + "isPersonal": false, + "items": { + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:User:assignments:items", + "notifySelf": true, + "properties": { + "_ref": { + "description": "References a relationship from a managed object", + "type": "string" + }, + "_refProperties": { + "description": "Supports metadata within the relationship", + "properties": { + "_accountType": { + "description": "Account type", + "type": "string" + }, + "_grantType": { + "description": "Grant Type", + "label": "Grant Type", + "type": "string" + }, + "_id": { + "description": "_refProperties object ID", + "type": "string" + }, + "_uniqueId": { + "description": "Unique identifier", + "type": "string" + } + }, + "title": "Provisioning Roles Items _refProperties", + "type": "object" + } + }, + "resourceCollection": [ + { + "conditionalAssociationField": "condition", + "label": "Assignment", + "path": "managed/assignment", + "query": { + "fields": [ + "name" + ], + "queryFilter": "true" + } + } + ], + "reversePropertyName": "members", + "reverseRelationship": true, + "title": "Assignments Items", + "type": "relationship", + "validate": true + }, + "returnByDefault": false, + "title": "Assignments", + "type": "array", + "usageDescription": "", + "userEditable": false, + "viewable": true + }, + "authzRoles": { + "description": "Authorization Roles", + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:User:authzRoles", + "isPersonal": false, + "items": { + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:User:authzRoles:items", + "properties": { + "_ref": { + "description": "References a relationship from a managed object", + "type": "string" + }, + "_refProperties": { + "description": "Supports metadata within the relationship", + "properties": { + "_id": { + "description": "_refProperties object ID", + "type": "string" + } + }, + "title": "Authorization Roles Items _refProperties", + "type": "object" + } + }, + "resourceCollection": [ + { + "conditionalAssociationField": "condition", + "label": "Internal Role", + "path": "internal/role", + "query": { + "fields": [ + "name" + ], + "queryFilter": "true" + } + } + ], + "reversePropertyName": "authzMembers", + "reverseRelationship": true, + "title": "Authorization Roles Items", + "type": "relationship", + "validate": true + }, + "returnByDefault": false, + "title": "Authorization Roles", + "type": "array", + "usageDescription": "", + "userEditable": false, + "viewable": true + }, + "city": { + "description": "City", + "isPersonal": false, + "title": "City", + "type": "string", + "usageDescription": "", + "userEditable": true, + "viewable": true + }, + "cn": { + "default": "{{givenName}} {{sn}}", + "description": "Common Name", + "isPersonal": true, + "scope": "private", + "searchable": false, + "title": "Common Name", + "type": "string", + "userEditable": false, + "viewable": false + }, + "consentedMappings": { + "description": "Consented Mappings", + "isPersonal": false, + "isVirtual": false, + "items": { + "items": { + "order": [ + "mapping", + "consentDate" + ], + "properties": { + "consentDate": { + "description": "Consent Date", + "format": "datetime", + "policies": [ + { + "policyId": "valid-datetime" + } + ], + "searchable": false, + "title": "Consent Date", + "type": "string", + "userEditable": true, + "viewable": true + }, + "mapping": { + "description": "Mapping", + "searchable": false, + "title": "Mapping", + "type": "string", + "userEditable": true, + "viewable": true + } + }, + "required": [ + "mapping", + "consentDate" + ], + "title": "Consented Mappings Item", + "type": "object" + }, + "title": "Consented Mappings Items", + "type": "array" + }, + "returnByDefault": false, + "searchable": false, + "title": "Consented Mappings", + "type": "array", + "usageDescription": "", + "userEditable": true, + "viewable": false + }, + "country": { + "description": "Country", + "isPersonal": false, + "title": "Country", + "type": "string", + "usageDescription": "", + "userEditable": true, + "viewable": true + }, + "description": { + "description": "Description", + "isPersonal": false, + "searchable": false, + "title": "Description", + "type": "string", + "usageDescription": "", + "userEditable": true, + "viewable": true + }, + "devicePrintProfiles": { + "description": "Device Print Profiles Information", + "isPersonal": false, + "items": { + "title": "Profile", + "type": "string" + }, + "searchable": false, + "title": "Device Print Profiles", + "type": "array", + "userEditable": true, + "viewable": true + }, + "deviceProfiles": { + "description": "Device Profiles", + "isPersonal": false, + "items": { + "title": "Profile", + "type": "string" + }, + "searchable": false, + "title": "Device Profiles", + "type": "array", + "userEditable": true, + "viewable": true + }, + "effectiveApplications": { + "description": "Effective Applications", + "isPersonal": false, + "isVirtual": true, + "items": { + "title": "Effective Application Items", + "type": "object" + }, + "queryConfig": { + "referencedObjectFields": [ + "name" + ], + "referencedRelationshipFields": [ + [ + "roles", + "applications" + ], + [ + "applications" + ] + ] + }, + "returnByDefault": true, + "title": "Effective Applications", + "type": "array", + "viewable": false + }, + "effectiveAssignments": { + "description": "Effective Assignments", + "isPersonal": false, + "isVirtual": true, + "items": { + "title": "Effective Assignments Items", + "type": "object" + }, + "queryConfig": { + "referencedObjectFields": [ + "*" + ], + "referencedRelationshipFields": [ + [ + "roles", + "assignments" + ], + [ + "assignments" + ] + ] + }, + "returnByDefault": true, + "title": "Effective Assignments", + "type": "array", + "usageDescription": "", + "viewable": false + }, + "effectiveGroups": { + "description": "Effective Groups", + "isPersonal": false, + "isVirtual": true, + "items": { + "title": "Effective Groups Items", + "type": "object" + }, + "queryConfig": { + "referencedRelationshipFields": [ + "groups" + ] + }, + "returnByDefault": true, + "title": "Effective Groups", + "type": "array", + "usageDescription": "", + "viewable": false + }, + "effectiveRoles": { + "description": "Effective Roles", + "isPersonal": false, + "isVirtual": true, + "items": { + "title": "Effective Roles Items", + "type": "object" + }, + "queryConfig": { + "referencedRelationshipFields": [ + "roles" + ] + }, + "returnByDefault": true, + "title": "Effective Roles", + "type": "array", + "usageDescription": "", + "viewable": false + }, + "givenName": { + "description": "First Name", + "isPersonal": true, + "searchable": true, + "title": "First Name", + "type": "string", + "usageDescription": "", + "userEditable": true, + "viewable": true + }, + "groups": { + "description": "Groups", + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:User:groups", + "isPersonal": false, + "items": { + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:User:groups:items", + "notifySelf": true, + "properties": { + "_ref": { + "description": "References a relationship from a managed object", + "type": "string" + }, + "_refProperties": { + "description": "Supports metadata within the relationship", + "properties": { + "_grantType": { + "description": "Grant Type", + "label": "Grant Type", + "type": "string" + }, + "_id": { + "description": "_refProperties object ID", + "type": "string" + } + }, + "title": "Groups Items _refProperties", + "type": "object" + } + }, + "resourceCollection": [ + { + "conditionalAssociationField": "condition", + "label": "Group", + "path": "managed/group", + "query": { + "fields": [ + "name" + ], + "queryFilter": "true", + "sortKeys": [ + "name" + ] + } + } + ], + "reversePropertyName": "members", + "reverseRelationship": true, + "title": "Groups Items", + "type": "relationship", + "validate": true + }, + "relationshipGrantTemporalConstraintsEnforced": false, + "returnByDefault": false, + "title": "Group", + "type": "array", + "usageDescription": "", + "userEditable": false, + "viewable": true + }, + "inactiveDate": { + "description": "Inactive Date", + "format": "datetime", + "isPersonal": false, + "policies": [ + { + "policyId": "valid-datetime" + } + ], + "searchable": false, + "title": "Inactive Date", + "type": "string", + "usageDescription": "", + "userEditable": false, + "viewable": true + }, + "kbaInfo": { + "description": "KBA Info", + "isPersonal": true, + "items": { + "order": [ + "answer", + "customQuestion", + "questionId" + ], + "properties": { + "answer": { + "description": "Answer", + "type": "string" + }, + "customQuestion": { + "description": "Custom question", + "type": "string" + }, + "questionId": { + "description": "Question ID", + "type": "string" + } + }, + "required": [], + "title": "KBA Info Items", + "type": "object" + }, + "type": "array", + "usageDescription": "", + "userEditable": true, + "viewable": false + }, + "lastSync": { + "description": "Last Sync timestamp", + "isPersonal": false, + "order": [ + "effectiveAssignments", + "timestamp" + ], + "properties": { + "effectiveAssignments": { + "description": "Effective Assignments", + "items": { + "title": "Effective Assignments Items", + "type": "object" + }, + "title": "Effective Assignments", + "type": "array" + }, + "timestamp": { + "description": "Timestamp", + "format": "datetime", + "policies": [ + { + "policyId": "valid-datetime" + } + ], + "type": "string" + } + }, + "required": [], + "scope": "private", + "searchable": false, + "title": "Last Sync timestamp", + "type": "object", + "usageDescription": "", + "viewable": false + }, + "mail": { + "description": "Email Address", + "isPersonal": true, + "policies": [ + { + "policyId": "valid-email-address-format" + } + ], + "searchable": true, + "title": "Email Address", + "type": "string", + "usageDescription": "", + "userEditable": true, + "viewable": true + }, + "manager": { + "description": "Manager", + "isPersonal": false, + "properties": { + "_ref": { + "description": "References a relationship from a managed object", + "type": "string" + }, + "_refProperties": { + "description": "Supports metadata within the relationship", + "properties": { + "_id": { + "description": "_refProperties object ID", + "type": "string" + } + }, + "title": "Manager _refProperties", + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "User", + "path": "managed/user", + "query": { + "fields": [ + "userName", + "givenName", + "sn" + ], + "queryFilter": "true" + } + } + ], + "reversePropertyName": "reports", + "reverseRelationship": true, + "searchable": false, + "title": "Manager", + "type": "relationship", + "usageDescription": "", + "userEditable": false, + "validate": true, + "viewable": true + }, + "memberOfOrg": { + "items": { + "notifySelf": true, + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_id": { + "propName": "_id", + "required": false, + "type": "string" + } + }, + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "Organization", + "notify": false, + "path": "managed/organization", + "query": { + "fields": [ + "name" + ], + "queryFilter": "true", + "sortKeys": [] + } + } + ], + "reversePropertyName": "members", + "reverseRelationship": true, + "type": "relationship", + "validate": true + }, + "policies": [], + "returnByDefault": false, + "searchable": false, + "title": "Organizations to which I Belong", + "type": "array", + "userEditable": false, + "viewable": true + }, + "memberOfOrgIDs": { + "isVirtual": true, + "items": { + "title": "org identifiers", + "type": "string" + }, + "queryConfig": { + "flattenProperties": true, + "referencedObjectFields": [ + "_id", + "parentIDs" + ], + "referencedRelationshipFields": [ + "memberOfOrg" + ] + }, + "returnByDefault": true, + "searchable": false, + "title": "MemberOfOrgIDs", + "type": "array", + "userEditable": false, + "viewable": false + }, + "oathDeviceProfiles": { + "description": "Oath Device Profiles", + "isPersonal": false, + "items": { + "title": "Profile", + "type": "string" + }, + "searchable": false, + "title": "Oath Device Profiles", + "type": "array", + "userEditable": true, + "viewable": true + }, + "ownerOfApp": { + "items": { + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_id": { + "propName": "_id", + "required": false, + "type": "string" + } + }, + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "Application", + "path": "managed/application", + "query": { + "fields": [ + "name" + ], + "queryFilter": "true", + "sortKeys": [ + "name" + ] + } + } + ], + "reversePropertyName": "owners", + "reverseRelationship": true, + "type": "relationship", + "validate": true + }, + "returnByDefault": false, + "searchable": false, + "title": "Applications I Own", + "type": "array", + "userEditable": false, + "viewable": true + }, + "ownerOfOrg": { + "items": { + "notifySelf": false, + "properties": { + "_ref": { + "type": "string" + }, + "_refProperties": { + "properties": { + "_id": { + "propName": "_id", + "required": false, + "type": "string" + } + }, + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "Organization", + "notify": true, + "path": "managed/organization", + "query": { + "fields": [ + "name" + ], + "queryFilter": "true", + "sortKeys": [] + } + } + ], + "reversePropertyName": "owners", + "reverseRelationship": true, + "type": "relationship", + "validate": true + }, + "policies": [], + "returnByDefault": false, + "searchable": false, + "title": "Organizations I Own", + "type": "array", + "userEditable": false, + "viewable": true + }, + "password": { + "description": "Password", + "isPersonal": false, + "isProtected": true, + "policies": [ + { + "params": { + "minLength": 8 + }, + "policyId": "minimum-length" + }, + { + "params": { + "numCaps": 1 + }, + "policyId": "at-least-X-capitals" + }, + { + "params": { + "numNums": 1 + }, + "policyId": "at-least-X-numbers" + }, + { + "params": { + "disallowedFields": [ + "userName", + "givenName", + "sn" + ] + }, + "policyId": "cannot-contain-others" + } + ], + "scope": "private", + "searchable": false, + "title": "Password", + "type": "string", + "usageDescription": "", + "userEditable": false, + "viewable": false + }, + "passwordExpirationTime": { + "description": "Password Expiration Time", + "searchable": true, + "title": "Password Expiration Time", + "type": "string", + "userEditable": false, + "viewable": true + }, + "passwordLastChangedTime": { + "description": "Password Last Changed Time", + "searchable": true, + "title": "Password Last Changed Time", + "type": "string", + "userEditable": false, + "viewable": true + }, + "postalAddress": { + "description": "Address 1", + "isPersonal": true, + "title": "Address 1", + "type": "string", + "usageDescription": "", + "userEditable": true, + "viewable": true + }, + "postalCode": { + "description": "Postal Code", + "isPersonal": false, + "title": "Postal Code", + "type": "string", + "usageDescription": "", + "userEditable": true, + "viewable": true + }, + "preferences": { + "description": "Preferences", + "isPersonal": false, + "order": [ + "updates", + "marketing" + ], + "properties": { + "marketing": { + "description": "Send me special offers and services", + "type": "boolean" + }, + "updates": { + "description": "Send me news and updates", + "type": "boolean" + } + }, + "required": [], + "searchable": false, + "title": "Preferences", + "type": "object", + "usageDescription": "", + "userEditable": true, + "viewable": true + }, + "profileImage": { + "description": "Profile Image", + "isPersonal": true, + "searchable": false, + "title": "Profile Image", + "type": "string", + "usageDescription": "", + "userEditable": true, + "viewable": false + }, + "pushDeviceProfiles": { + "description": "Push Device Profiles", + "isPersonal": false, + "items": { + "title": "Profile", + "type": "string" + }, + "searchable": false, + "title": "Push Device Profiles", + "type": "array", + "userEditable": true, + "viewable": true + }, + "reports": { + "description": "Direct Reports", + "isPersonal": false, + "items": { + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:User:reports:items", + "properties": { + "_ref": { + "description": "References a relationship from a managed object", + "type": "string" + }, + "_refProperties": { + "description": "Supports metadata within the relationship", + "properties": { + "_id": { + "description": "_refProperties object ID", + "type": "string" + } + }, + "title": "Direct Reports Items _refProperties", + "type": "object" + } + }, + "resourceCollection": [ + { + "label": "User", + "path": "managed/user", + "query": { + "fields": [ + "userName", + "givenName", + "sn" + ], + "queryFilter": "true" + } + } + ], + "reversePropertyName": "manager", + "reverseRelationship": true, + "title": "Direct Reports Items", + "type": "relationship", + "validate": true + }, + "returnByDefault": false, + "title": "Direct Reports", + "type": "array", + "usageDescription": "", + "userEditable": false, + "viewable": true + }, + "roles": { + "description": "Provisioning Roles", + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:User:roles", + "isPersonal": false, + "items": { + "id": "urn:jsonschema:org:forgerock:openidm:managed:api:User:roles:items", + "notifySelf": true, + "properties": { + "_ref": { + "description": "References a relationship from a managed object", + "type": "string" + }, + "_refProperties": { + "description": "Supports metadata within the relationship", + "properties": { + "_grantType": { + "description": "Grant Type", + "label": "Grant Type", + "type": "string" + }, + "_id": { + "description": "_refProperties object ID", + "type": "string" + } + }, + "title": "Provisioning Roles Items _refProperties", + "type": "object" + } + }, + "resourceCollection": [ + { + "conditionalAssociationField": "condition", + "label": "Role", + "path": "managed/role", + "query": { + "fields": [ + "name" + ], + "queryFilter": "true" + } + } + ], + "reversePropertyName": "members", + "reverseRelationship": true, + "title": "Provisioning Roles Items", + "type": "relationship", + "validate": true + }, + "relationshipGrantTemporalConstraintsEnforced": true, + "returnByDefault": false, + "title": "Provisioning Roles", + "type": "array", + "usageDescription": "", + "userEditable": false, + "viewable": true + }, + "sn": { + "description": "Last Name", + "isPersonal": true, + "searchable": true, + "title": "Last Name", + "type": "string", + "usageDescription": "", + "userEditable": true, + "viewable": true + }, + "stateProvince": { + "description": "State/Province", + "isPersonal": false, + "title": "State/Province", + "type": "string", + "usageDescription": "", + "userEditable": true, + "viewable": true + }, + "telephoneNumber": { + "description": "Telephone Number", + "isPersonal": true, + "pattern": "^\\+?([0-9\\- \\(\\)])*$", + "searchable": true, + "title": "Telephone Number", + "type": "string", + "usageDescription": "", + "userEditable": true, + "viewable": true + }, + "userName": { + "description": "Username", + "isPersonal": true, + "policies": [ + { + "policyId": "valid-username" + }, + { + "params": { + "forbiddenChars": [ + "/" + ] + }, + "policyId": "cannot-contain-characters" + }, + { + "params": { + "minLength": 1 + }, + "policyId": "minimum-length" + }, + { + "params": { + "maxLength": 255 + }, + "policyId": "maximum-length" + } + ], + "searchable": true, + "title": "Username", + "type": "string", + "usageDescription": "", + "userEditable": true, + "viewable": true + }, + "webauthnDeviceProfiles": { + "description": "Web AuthN Device Profiles", + "isPersonal": false, + "items": { + "title": "Profile", + "type": "string" + }, + "searchable": false, + "title": "Web AuthN Device Profiles", + "type": "array", + "userEditable": true, + "viewable": true + } + }, + "required": [ + "userName", + "givenName", + "sn", + "mail" + ], + "title": "User", + "type": "object", + "viewable": true + } +} diff --git a/test/e2e/exports/fr-config-manager/org-privileges/privilegeAssignments.json b/test/e2e/exports/fr-config-manager/org-privileges/privilegeAssignments.json new file mode 100644 index 000000000..aa8a6c71d --- /dev/null +++ b/test/e2e/exports/fr-config-manager/org-privileges/privilegeAssignments.json @@ -0,0 +1,27 @@ +{ + "_id": "privilegeAssignments", + "privilegeAssignments": [ + { + "name": "ownerPrivileges", + "privileges": [ + "owner-view-update-delete-orgs", + "owner-create-orgs", + "owner-view-update-delete-admins-and-members", + "owner-create-admins", + "admin-view-update-delete-members", + "admin-create-members" + ], + "relationshipField": "ownerOfOrg" + }, + { + "name": "adminPrivileges", + "privileges": [ + "admin-view-update-delete-orgs", + "admin-create-orgs", + "admin-view-update-delete-members", + "admin-create-members" + ], + "relationshipField": "adminOfOrg" + } + ] +} diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Contrast/Contrast.json b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Contrast/Contrast.json new file mode 100644 index 000000000..62ff259e5 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Contrast/Contrast.json @@ -0,0 +1,90 @@ +{ + "_id": "abb4efed-ae70-4064-91a7-936be552d6fc", + "accountFooter": { + "file": "accountFooter.html" + }, + "accountFooterEnabled": false, + "accountPageSections": { + "accountControls": { + "enabled": false + }, + "accountSecurity": { + "enabled": true, + "subsections": { + "password": { + "enabled": true + }, + "securityQuestions": { + "enabled": false + }, + "twoStepVerification": { + "enabled": true + }, + "username": { + "enabled": true + } + } + }, + "consent": { + "enabled": false + }, + "oauthApplications": { + "enabled": false + }, + "personalInformation": { + "enabled": true + }, + "preferences": { + "enabled": false + }, + "social": { + "enabled": false + }, + "trustedDevices": { + "enabled": true + } + }, + "backgroundColor": "#FFFFFF", + "backgroundImage": "", + "bodyText": "#000000", + "buttonRounded": "0", + "dangerColor": "#f7685b", + "favicon": "", + "isDefault": false, + "journeyFooter": { + "file": "journeyFooter.html" + }, + "journeyFooterEnabled": false, + "journeyHeader": { + "file": "journeyHeader.html" + }, + "journeyHeaderEnabled": false, + "journeyJustifiedContent": "", + "journeyJustifiedContentEnabled": false, + "journeyLayout": "card", + "journeyTheaterMode": false, + "linkActiveColor": "#000000", + "linkColor": "#000000", + "linkedTrees": [], + "logo": "https://cdn.forgerock.com/platform/themes/contrast/logo-contrast.svg", + "logoAltText": "Contrast", + "logoEnabled": true, + "logoHeight": "72", + "logoProfile": "data:image/svg+xml,%0A%3Csvg width='46' height='46' viewBox='0 0 46 46' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M24.3477 13.5664H43.9438C43.5192 12.6317 43.0319 11.734 42.4905 10.8711H24.3477V13.5664Z' fill='black'/%3E%3Cpath d='M24.3477 8.17578H40.5261C39.6996 7.2052 38.7974 6.30182 37.8224 5.48047H24.3477V8.17578Z' fill='black'/%3E%3Cpath d='M24.3477 40.5195H37.8224C38.7975 39.6982 39.6996 38.7948 40.5261 37.8242H24.3477V40.5195Z' fill='black'/%3E%3Cpath d='M24.3477 2.78516H33.8482C31.0136 1.27039 27.7313 0.198195 24.3477 0V2.78516Z' fill='black'/%3E%3Cpath d='M24.3477 18.957H45.6208C45.4566 18.0405 45.2557 17.1372 44.9856 16.2617H24.3477V18.957Z' fill='black'/%3E%3Cpath d='M24.3477 21.6523V24.3477H45.9317C45.958 23.8992 46 23.4549 46 23C46 22.5451 45.958 22.1008 45.9317 21.6523H24.3477Z' fill='black'/%3E%3Cpath d='M0 23C0 35.1781 9.64778 45.2964 21.6523 46V0C9.64778 0.703566 0 10.8219 0 23Z' fill='black'/%3E%3Cpath d='M24.3477 46C27.7313 45.8018 31.0136 44.7296 33.8482 43.2148H24.3477V46Z' fill='black'/%3E%3Cpath d='M45.6208 27.043H24.3477V29.7383H44.9857C45.2557 28.8628 45.4566 27.9595 45.6208 27.043V27.043Z' fill='black'/%3E%3Cpath d='M24.3477 35.1289H42.4905C43.0319 34.266 43.5192 33.3683 43.9438 32.4336H24.3477V35.1289Z' fill='black'/%3E%3C/svg%3E%0A", + "logoProfileAltText": "Contrast", + "logoProfileCollapsed": "data:image/svg+xml,%0A%3Csvg width='46' height='46' viewBox='0 0 46 46' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M24.3477 13.5664H43.9438C43.5192 12.6317 43.0319 11.734 42.4905 10.8711H24.3477V13.5664Z' fill='black'/%3E%3Cpath d='M24.3477 8.17578H40.5261C39.6996 7.2052 38.7974 6.30182 37.8224 5.48047H24.3477V8.17578Z' fill='black'/%3E%3Cpath d='M24.3477 40.5195H37.8224C38.7975 39.6982 39.6996 38.7948 40.5261 37.8242H24.3477V40.5195Z' fill='black'/%3E%3Cpath d='M24.3477 2.78516H33.8482C31.0136 1.27039 27.7313 0.198195 24.3477 0V2.78516Z' fill='black'/%3E%3Cpath d='M24.3477 18.957H45.6208C45.4566 18.0405 45.2557 17.1372 44.9856 16.2617H24.3477V18.957Z' fill='black'/%3E%3Cpath d='M24.3477 21.6523V24.3477H45.9317C45.958 23.8992 46 23.4549 46 23C46 22.5451 45.958 22.1008 45.9317 21.6523H24.3477Z' fill='black'/%3E%3Cpath d='M0 23C0 35.1781 9.64778 45.2964 21.6523 46V0C9.64778 0.703566 0 10.8219 0 23Z' fill='black'/%3E%3Cpath d='M24.3477 46C27.7313 45.8018 31.0136 44.7296 33.8482 43.2148H24.3477V46Z' fill='black'/%3E%3Cpath d='M45.6208 27.043H24.3477V29.7383H44.9857C45.2557 28.8628 45.4566 27.9595 45.6208 27.043V27.043Z' fill='black'/%3E%3Cpath d='M24.3477 35.1289H42.4905C43.0319 34.266 43.5192 33.3683 43.9438 32.4336H24.3477V35.1289Z' fill='black'/%3E%3C/svg%3E%0A", + "logoProfileCollapsedAltText": "", + "logoProfileCollapsedHeight": "22", + "logoProfileHeight": "22", + "name": "Contrast", + "pageTitle": "#23282e", + "primaryColor": "#000000", + "primaryOffColor": "#000000", + "profileBackgroundColor": "#FFFFFF", + "profileMenuHighlightColor": "#FFFFFF", + "profileMenuHoverColor": "#FFFFFF", + "profileMenuHoverTextColor": "#000000", + "profileMenuTextHighlightColor": "#455469", + "secondaryColor": "#69788b", + "textColor": "#ffffff" +} diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Contrast/accountFooter.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Contrast/accountFooter.html new file mode 100644 index 000000000..325201c47 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Contrast/accountFooter.html @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Contrast/journeyFooter.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Contrast/journeyFooter.html new file mode 100644 index 000000000..325201c47 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Contrast/journeyFooter.html @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Contrast/journeyHeader.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Contrast/journeyHeader.html new file mode 100644 index 000000000..c7a5de7f1 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Contrast/journeyHeader.html @@ -0,0 +1 @@ +
Header Content
\ No newline at end of file diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Highlander/Highlander.json b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Highlander/Highlander.json new file mode 100644 index 000000000..d13464ffe --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Highlander/Highlander.json @@ -0,0 +1,90 @@ +{ + "_id": "00203891-dde0-4114-b27a-219ae0b43a61", + "accountFooter": { + "file": "accountFooter.html" + }, + "accountFooterEnabled": true, + "accountPageSections": { + "accountControls": { + "enabled": false + }, + "accountSecurity": { + "enabled": true, + "subsections": { + "password": { + "enabled": true + }, + "securityQuestions": { + "enabled": false + }, + "twoStepVerification": { + "enabled": true + }, + "username": { + "enabled": true + } + } + }, + "consent": { + "enabled": false + }, + "oauthApplications": { + "enabled": false + }, + "personalInformation": { + "enabled": true + }, + "preferences": { + "enabled": false + }, + "social": { + "enabled": false + }, + "trustedDevices": { + "enabled": true + } + }, + "backgroundColor": "#FFFFFF", + "backgroundImage": "", + "bodyText": "#5E6D82", + "buttonRounded": "50", + "dangerColor": "#f7685b", + "favicon": "", + "isDefault": false, + "journeyFooter": { + "file": "journeyFooter.html" + }, + "journeyFooterEnabled": true, + "journeyHeader": { + "file": "journeyHeader.html" + }, + "journeyHeaderEnabled": true, + "journeyJustifiedContent": "", + "journeyJustifiedContentEnabled": false, + "journeyLayout": "card", + "journeyTheaterMode": false, + "linkActiveColor": "#C60819", + "linkColor": "#EB0A1E", + "linkedTrees": [], + "logo": "", + "logoAltText": "", + "logoEnabled": true, + "logoHeight": "40", + "logoProfile": "https://cdn.forgerock.com/platform/themes/highlander/logo-highlander-full.svg", + "logoProfileAltText": "Highlander", + "logoProfileCollapsed": "https://cdn.forgerock.com/platform/themes/highlander/logo-highlander-icon.svg", + "logoProfileCollapsedAltText": "Highlander", + "logoProfileCollapsedHeight": "28", + "logoProfileHeight": "28", + "name": "Highlander", + "pageTitle": "#23282e", + "primaryColor": "#EB0A1E", + "primaryOffColor": "#C60819", + "profileBackgroundColor": "#FFFFFF", + "profileMenuHighlightColor": "#FFFFFF", + "profileMenuHoverColor": "#FFFFFF", + "profileMenuHoverTextColor": "#455469", + "profileMenuTextHighlightColor": "#EB0A1E", + "secondaryColor": "#69788b", + "textColor": "#ffffff" +} diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Highlander/accountFooter.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Highlander/accountFooter.html new file mode 100644 index 000000000..2e1fd1a9a --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Highlander/accountFooter.html @@ -0,0 +1,40 @@ + diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Highlander/journeyFooter.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Highlander/journeyFooter.html new file mode 100644 index 000000000..85315e964 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Highlander/journeyFooter.html @@ -0,0 +1,65 @@ + + diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Highlander/journeyHeader.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Highlander/journeyHeader.html new file mode 100644 index 000000000..08fae77b0 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Highlander/journeyHeader.html @@ -0,0 +1,37 @@ +
+ +
diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/Robroy.json b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/Robroy.json new file mode 100644 index 000000000..82da568bd --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/Robroy.json @@ -0,0 +1,92 @@ +{ + "_id": "8e756273-9dbb-42dd-babe-52912336ea3d", + "accountFooter": { + "file": "accountFooter.html" + }, + "accountFooterEnabled": true, + "accountPageSections": { + "accountControls": { + "enabled": false + }, + "accountSecurity": { + "enabled": true, + "subsections": { + "password": { + "enabled": true + }, + "securityQuestions": { + "enabled": false + }, + "twoStepVerification": { + "enabled": true + }, + "username": { + "enabled": true + } + } + }, + "consent": { + "enabled": false + }, + "oauthApplications": { + "enabled": false + }, + "personalInformation": { + "enabled": true + }, + "preferences": { + "enabled": false + }, + "social": { + "enabled": false + }, + "trustedDevices": { + "enabled": true + } + }, + "backgroundColor": "#FFFFFF", + "backgroundImage": "", + "bodyText": "#5E6D82", + "buttonRounded": "50", + "dangerColor": "#f7685b", + "favicon": "", + "isDefault": false, + "journeyFooter": { + "file": "journeyFooter.html" + }, + "journeyFooterEnabled": true, + "journeyHeader": { + "file": "journeyHeader.html" + }, + "journeyHeaderEnabled": true, + "journeyJustifiedContent": { + "file": "journeyJustifiedContent.html" + }, + "journeyJustifiedContentEnabled": true, + "journeyLayout": "justified-right", + "journeyTheaterMode": false, + "linkActiveColor": "#49871E", + "linkColor": "#5AA625", + "linkedTrees": [], + "logo": "https://cdn.forgerock.com/platform/themes/robroy/logo-robroy-icon.svg", + "logoAltText": "", + "logoEnabled": true, + "logoHeight": "40", + "logoProfile": "data:image/svg+xml,%0A%3Csvg width='156' height='34' viewBox='0 0 156 34' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg clip-path='url(%23clip0)'%3E%3Cpath d='M32.5539 32.5538C32.5539 32.5538 17.0796 35.6024 7.23861 25.7614C-2.60242 15.9204 0.446148 0.446137 0.446148 0.446137C0.446148 0.446137 15.9204 -2.60243 25.7614 7.23866C35.6024 17.0797 32.5539 32.5538 32.5539 32.5538Z' fill='%23C3EA21'/%3E%3Cpath d='M32.5537 32.554C32.5537 32.554 17.0795 35.6026 7.23845 25.7615C-2.60257 15.9205 0.445995 0.446289 0.445995 0.446289L32.5537 32.554Z' fill='%238ADB53'/%3E%3C/g%3E%3Cpath d='M51.053 25.38L53.186 25.11V8.964L51.161 8.586V6.939H55.076C55.418 6.939 55.796 6.93 56.21 6.912C56.624 6.894 56.939 6.876 57.155 6.858C58.091 6.786 58.865 6.75 59.477 6.75C61.331 6.75 62.816 6.939 63.932 7.317C65.048 7.695 65.858 8.271 66.362 9.045C66.866 9.819 67.118 10.836 67.118 12.096C67.118 13.338 66.785 14.49 66.119 15.552C65.453 16.614 64.49 17.343 63.23 17.739C63.95 18.045 64.589 18.603 65.147 19.413C65.705 20.223 66.299 21.276 66.929 22.572C67.379 23.454 67.721 24.093 67.955 24.489C68.207 24.867 68.45 25.083 68.684 25.137L69.575 25.407V27H64.985C64.697 27 64.391 26.712 64.067 26.136C63.761 25.542 63.356 24.615 62.852 23.355C62.258 21.879 61.745 20.727 61.313 19.899C60.881 19.071 60.422 18.558 59.936 18.36H57.155V25.11L59.639 25.38V27H51.053V25.38ZM59.639 16.713C60.665 16.713 61.466 16.344 62.042 15.606C62.618 14.868 62.906 13.761 62.906 12.285C62.906 10.971 62.618 9.999 62.042 9.369C61.484 8.739 60.512 8.424 59.126 8.424C58.622 8.424 58.19 8.451 57.83 8.505C57.488 8.541 57.263 8.559 57.155 8.559V16.659C57.371 16.695 57.893 16.713 58.721 16.713H59.639ZM70.674 19.521C70.674 17.829 71.007 16.389 71.673 15.201C72.357 14.013 73.266 13.122 74.4 12.528C75.534 11.916 76.767 11.61 78.099 11.61C80.367 11.61 82.113 12.312 83.337 13.716C84.579 15.102 85.2 16.992 85.2 19.386C85.2 21.096 84.858 22.554 84.174 23.76C83.508 24.948 82.608 25.839 81.474 26.433C80.358 27.009 79.125 27.297 77.775 27.297C75.525 27.297 73.779 26.604 72.537 25.218C71.295 23.814 70.674 21.915 70.674 19.521ZM77.991 25.542C80.025 25.542 81.042 23.58 81.042 19.656C81.042 17.604 80.799 16.047 80.313 14.985C79.827 13.905 79.035 13.365 77.937 13.365C75.849 13.365 74.805 15.327 74.805 19.251C74.805 21.303 75.057 22.869 75.561 23.949C76.083 25.011 76.893 25.542 77.991 25.542ZM86.4395 5.454L91.3805 4.86H91.4345L92.1905 5.373V13.338C92.6765 12.852 93.2705 12.447 93.9725 12.123C94.6925 11.781 95.4665 11.61 96.2945 11.61C98.0225 11.61 99.4265 12.222 100.506 13.446C101.604 14.652 102.153 16.506 102.153 19.008C102.153 20.556 101.829 21.96 101.181 23.22C100.533 24.48 99.5975 25.479 98.3735 26.217C97.1675 26.937 95.7635 27.297 94.1615 27.297C92.7395 27.297 91.5065 27.18 90.4625 26.946C89.4185 26.694 88.7525 26.469 88.4645 26.271V7.182L86.4395 6.858V5.454ZM94.8635 13.986C94.3235 13.986 93.8105 14.112 93.3245 14.364C92.8565 14.598 92.4785 14.868 92.1905 15.174V25.029C92.2985 25.227 92.5505 25.389 92.9465 25.515C93.3425 25.641 93.7925 25.704 94.2965 25.704C95.4485 25.704 96.3665 25.173 97.0505 24.111C97.7525 23.031 98.1035 21.438 98.1035 19.332C98.1035 17.514 97.8065 16.173 97.2125 15.309C96.6185 14.427 95.8355 13.986 94.8635 13.986Z' fill='black'/%3E%3Cpath d='M104.183 25.38L106.316 25.11V8.964L104.291 8.586V6.939H108.206C108.548 6.939 108.926 6.93 109.34 6.912C109.754 6.894 110.069 6.876 110.285 6.858C111.221 6.786 111.995 6.75 112.607 6.75C114.461 6.75 115.946 6.939 117.062 7.317C118.178 7.695 118.988 8.271 119.492 9.045C119.996 9.819 120.248 10.836 120.248 12.096C120.248 13.338 119.915 14.49 119.249 15.552C118.583 16.614 117.62 17.343 116.36 17.739C117.08 18.045 117.719 18.603 118.277 19.413C118.835 20.223 119.429 21.276 120.059 22.572C120.509 23.454 120.851 24.093 121.085 24.489C121.337 24.867 121.58 25.083 121.814 25.137L122.705 25.407V27H118.115C117.827 27 117.521 26.712 117.197 26.136C116.891 25.542 116.486 24.615 115.982 23.355C115.388 21.879 114.875 20.727 114.443 19.899C114.011 19.071 113.552 18.558 113.066 18.36H110.285V25.11L112.769 25.38V27H104.183V25.38ZM112.769 16.713C113.795 16.713 114.596 16.344 115.172 15.606C115.748 14.868 116.036 13.761 116.036 12.285C116.036 10.971 115.748 9.999 115.172 9.369C114.614 8.739 113.642 8.424 112.256 8.424C111.752 8.424 111.32 8.451 110.96 8.505C110.618 8.541 110.393 8.559 110.285 8.559V16.659C110.501 16.695 111.023 16.713 111.851 16.713H112.769ZM123.804 19.521C123.804 17.829 124.137 16.389 124.803 15.201C125.487 14.013 126.396 13.122 127.53 12.528C128.664 11.916 129.897 11.61 131.229 11.61C133.497 11.61 135.243 12.312 136.467 13.716C137.709 15.102 138.33 16.992 138.33 19.386C138.33 21.096 137.988 22.554 137.304 23.76C136.638 24.948 135.738 25.839 134.604 26.433C133.488 27.009 132.255 27.297 130.905 27.297C128.655 27.297 126.909 26.604 125.667 25.218C124.425 23.814 123.804 21.915 123.804 19.521ZM131.121 25.542C133.155 25.542 134.172 23.58 134.172 19.656C134.172 17.604 133.929 16.047 133.443 14.985C132.957 13.905 132.165 13.365 131.067 13.365C128.979 13.365 127.935 15.327 127.935 19.251C127.935 21.303 128.187 22.869 128.691 23.949C129.213 25.011 130.023 25.542 131.121 25.542ZM143.187 33.723C142.863 33.723 142.512 33.696 142.134 33.642C141.774 33.588 141.513 33.525 141.351 33.453V30.564C141.477 30.636 141.729 30.708 142.107 30.78C142.485 30.852 142.827 30.888 143.133 30.888C144.033 30.888 144.771 30.591 145.347 29.997C145.941 29.403 146.49 28.404 146.994 27H145.536L140.46 13.905L139.245 13.554V11.988H146.67V13.554L144.699 13.878L147.102 21.357L148.074 24.543L148.911 21.357L151.125 13.878L149.424 13.554V11.988H155.283V13.554L153.96 13.878C152.97 16.902 151.989 19.818 151.017 22.626C150.045 25.434 149.478 27.009 149.316 27.351C148.74 28.863 148.191 30.069 147.669 30.969C147.147 31.869 146.526 32.553 145.806 33.021C145.086 33.489 144.213 33.723 143.187 33.723Z' fill='%236CBE34'/%3E%3Cdefs%3E%3CclipPath id='clip0'%3E%3Crect width='33' height='33' fill='white' transform='matrix(-1 0 0 1 33 0)'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E%0A", + "logoProfileAltText": "RobRoy", + "logoProfileCollapsed": "data:image/svg+xml,%0A%3Csvg width='33' height='33' viewBox='0 0 33 33' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg clip-path='url(%23clip0)'%3E%3Cpath d='M32.5539 32.5538C32.5539 32.5538 17.0796 35.6024 7.23861 25.7614C-2.60242 15.9204 0.446148 0.446137 0.446148 0.446137C0.446148 0.446137 15.9204 -2.60243 25.7614 7.23866C35.6024 17.0797 32.5539 32.5538 32.5539 32.5538Z' fill='%23C3EA21'/%3E%3Cpath d='M32.5537 32.554C32.5537 32.554 17.0795 35.6026 7.23845 25.7615C-2.60257 15.9205 0.445996 0.446289 0.445996 0.446289L32.5537 32.554Z' fill='%238ADB53'/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id='clip0'%3E%3Crect width='33' height='33' fill='white' transform='matrix(-1 0 0 1 33 0)'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E%0A", + "logoProfileCollapsedAltText": "RobRoy", + "logoProfileCollapsedHeight": "28", + "logoProfileHeight": "28", + "name": "Robroy", + "pageTitle": "#23282e", + "primaryColor": "#5AA625", + "primaryOffColor": "#49871E", + "profileBackgroundColor": "#FFFFFF", + "profileMenuHighlightColor": "#FFFFFF", + "profileMenuHoverColor": "#FFFFFF", + "profileMenuHoverTextColor": "#455469", + "profileMenuTextHighlightColor": "#5AA625", + "secondaryColor": "#69788b", + "textColor": "#ffffff" +} diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/accountFooter.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/accountFooter.html new file mode 100644 index 000000000..b4ee3b09d --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/accountFooter.html @@ -0,0 +1,40 @@ + diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/journeyFooter.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/journeyFooter.html new file mode 100644 index 000000000..3a0d3a29f --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/journeyFooter.html @@ -0,0 +1,99 @@ + diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/journeyHeader.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/journeyHeader.html new file mode 100644 index 000000000..1f4ee6610 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/journeyHeader.html @@ -0,0 +1,37 @@ +
+ +
diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/journeyJustifiedContent.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/journeyJustifiedContent.html new file mode 100644 index 000000000..0e031e7bd --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Robroy/journeyJustifiedContent.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Starter Theme/Starter Theme.json b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Starter Theme/Starter Theme.json new file mode 100644 index 000000000..c1caa8df0 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Starter Theme/Starter Theme.json @@ -0,0 +1,89 @@ +{ + "_id": "33b89c09-2a29-4e9b-9e2b-12fd7e1c7466", + "accountFooter": { + "file": "accountFooter.html" + }, + "accountFooterEnabled": false, + "accountPageSections": { + "accountControls": { + "enabled": false + }, + "accountSecurity": { + "enabled": true, + "subsections": { + "password": { + "enabled": true + }, + "securityQuestions": { + "enabled": false + }, + "twoStepVerification": { + "enabled": true + }, + "username": { + "enabled": true + } + } + }, + "consent": { + "enabled": false + }, + "oauthApplications": { + "enabled": false + }, + "personalInformation": { + "enabled": true + }, + "preferences": { + "enabled": false + }, + "social": { + "enabled": false + }, + "trustedDevices": { + "enabled": true + } + }, + "backgroundColor": "#324054", + "backgroundImage": "", + "bodyText": "#23282e", + "buttonRounded": 5, + "dangerColor": "#f7685b", + "favicon": "", + "isDefault": true, + "journeyFooter": { + "file": "journeyFooter.html" + }, + "journeyFooterEnabled": false, + "journeyHeader": { + "file": "journeyHeader.html" + }, + "journeyHeaderEnabled": false, + "journeyJustifiedContent": "", + "journeyJustifiedContentEnabled": false, + "journeyLayout": "card", + "journeyTheaterMode": false, + "linkActiveColor": "#0c85cf", + "linkColor": "#109cf1", + "linkedTrees": [], + "logo": "", + "logoAltText": "", + "logoHeight": "40", + "logoProfile": "", + "logoProfileAltText": "", + "logoProfileCollapsed": "", + "logoProfileCollapsedAltText": "", + "logoProfileCollapsedHeight": "40", + "logoProfileHeight": "40", + "name": "Starter Theme", + "pageTitle": "#23282e", + "primaryColor": "#324054", + "primaryOffColor": "#242E3C", + "profileBackgroundColor": "#f6f8fa", + "profileMenuHighlightColor": "#f3f5f8", + "profileMenuHoverColor": "#324054", + "profileMenuHoverTextColor": "#ffffff", + "profileMenuTextHighlightColor": "#455469", + "secondaryColor": "#69788b", + "textColor": "#ffffff" +} diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Starter Theme/accountFooter.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Starter Theme/accountFooter.html new file mode 100644 index 000000000..325201c47 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Starter Theme/accountFooter.html @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Starter Theme/journeyFooter.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Starter Theme/journeyFooter.html new file mode 100644 index 000000000..325201c47 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Starter Theme/journeyFooter.html @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Starter Theme/journeyHeader.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Starter Theme/journeyHeader.html new file mode 100644 index 000000000..c7a5de7f1 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Starter Theme/journeyHeader.html @@ -0,0 +1 @@ +
Header Content
\ No newline at end of file diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/Zardoz.json b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/Zardoz.json new file mode 100644 index 000000000..23172b909 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/Zardoz.json @@ -0,0 +1,92 @@ +{ + "_id": "8ee2e08a-db04-4a16-b3d9-6f52c9aee5cb", + "accountFooter": { + "file": "accountFooter.html" + }, + "accountFooterEnabled": true, + "accountPageSections": { + "accountControls": { + "enabled": false + }, + "accountSecurity": { + "enabled": true, + "subsections": { + "password": { + "enabled": true + }, + "securityQuestions": { + "enabled": false + }, + "twoStepVerification": { + "enabled": true + }, + "username": { + "enabled": true + } + } + }, + "consent": { + "enabled": false + }, + "oauthApplications": { + "enabled": false + }, + "personalInformation": { + "enabled": true + }, + "preferences": { + "enabled": false + }, + "social": { + "enabled": false + }, + "trustedDevices": { + "enabled": true + } + }, + "backgroundColor": "#FFFFFF", + "backgroundImage": "", + "bodyText": "#5E6D82", + "buttonRounded": "50", + "dangerColor": "#f7685b", + "favicon": "", + "isDefault": false, + "journeyFooter": { + "file": "journeyFooter.html" + }, + "journeyFooterEnabled": true, + "journeyHeader": { + "file": "journeyHeader.html" + }, + "journeyHeaderEnabled": false, + "journeyJustifiedContent": { + "file": "journeyJustifiedContent.html" + }, + "journeyJustifiedContentEnabled": true, + "journeyLayout": "justified-right", + "journeyTheaterMode": true, + "linkActiveColor": "#007661", + "linkColor": "#009C80", + "linkedTrees": [], + "logo": "https://cdn.forgerock.com/platform/themes/zardoz/logo-zardoz.svg", + "logoAltText": "Zardoz Logo", + "logoEnabled": true, + "logoHeight": "47", + "logoProfile": "https://cdn.forgerock.com/platform/themes/zardoz/logo-zardoz.svg", + "logoProfileAltText": "Zardaz Logo", + "logoProfileCollapsed": "https://cdn.forgerock.com/platform/themes/zardoz/logo-zardoz.svg", + "logoProfileCollapsedAltText": "Zardaz Logo", + "logoProfileCollapsedHeight": "28", + "logoProfileHeight": "40", + "name": "Zardoz", + "pageTitle": "#23282e", + "primaryColor": "#009C80", + "primaryOffColor": "#007661", + "profileBackgroundColor": "#FFFFFF", + "profileMenuHighlightColor": "#FFFFFF", + "profileMenuHoverColor": "#FFFFFF", + "profileMenuHoverTextColor": "#455469", + "profileMenuTextHighlightColor": "#009C80", + "secondaryColor": "#69788b", + "textColor": "#ffffff" +} diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/accountFooter.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/accountFooter.html new file mode 100644 index 000000000..70dd95529 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/accountFooter.html @@ -0,0 +1,18 @@ + diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/journeyFooter.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/journeyFooter.html new file mode 100644 index 000000000..262ae63f6 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/journeyFooter.html @@ -0,0 +1,18 @@ + diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/journeyHeader.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/journeyHeader.html new file mode 100644 index 000000000..c7a5de7f1 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/journeyHeader.html @@ -0,0 +1 @@ +
Header Content
\ No newline at end of file diff --git a/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/journeyJustifiedContent.html b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/journeyJustifiedContent.html new file mode 100644 index 000000000..327d3a783 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/alpha/themes/Zardoz/journeyJustifiedContent.html @@ -0,0 +1,5 @@ +
+

Uptime & Performance Benchmarking Made Easy

+
+ diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Agent/Agent.json b/test/e2e/exports/fr-config-manager/realms/journeys/Agent/Agent.json new file mode 100644 index 000000000..116a2ba7a --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Agent/Agent.json @@ -0,0 +1,58 @@ +{ + "_id": "Agent", + "_rev": "174532371", + "description": "Authentication Tree for Agent", + "enabled": true, + "entryNodeId": "6c24a892-4bae-48ad-8d9c-8061257c9ed7", + "innerTreeOnly": false, + "mustRun": false, + "noSession": false, + "nodes": { + "35cb0861-c160-47ff-808c-3429ba18772c": { + "connections": { + "outcome": "7a910023-cad2-4f49-9ce0-1a0c711613d3" + }, + "displayName": "Page Node", + "nodeType": "PageNode", + "x": 350, + "y": 200 + }, + "6c24a892-4bae-48ad-8d9c-8061257c9ed7": { + "connections": { + "false": "35cb0861-c160-47ff-808c-3429ba18772c", + "true": "7a910023-cad2-4f49-9ce0-1a0c711613d3" + }, + "displayName": "Zero Page Login Collector", + "nodeType": "ZeroPageLoginNode", + "x": 150, + "y": 25 + }, + "7a910023-cad2-4f49-9ce0-1a0c711613d3": { + "connections": { + "false": "e301438c-0bd0-429c-ab0c-66126501069a", + "true": "70e691a5-1e33-4ac3-a356-e7b6d60d92e0" + }, + "displayName": "Agent Data Store Decision", + "nodeType": "AgentDataStoreDecisionNode", + "x": 700, + "y": 25 + } + }, + "staticNodes": { + "70e691a5-1e33-4ac3-a356-e7b6d60d92e0": { + "x": 1000, + "y": 25 + }, + "e301438c-0bd0-429c-ab0c-66126501069a": { + "x": 1000, + "y": 200 + }, + "startNode": { + "x": 50, + "y": 25 + } + }, + "uiConfig": { + "categories": "[\"Authentication\"]" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Agent Data Store Decision - 7a910023-cad2-4f49-9ce0-1a0c711613d3.json b/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Agent Data Store Decision - 7a910023-cad2-4f49-9ce0-1a0c711613d3.json new file mode 100644 index 000000000..99c193e11 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Agent Data Store Decision - 7a910023-cad2-4f49-9ce0-1a0c711613d3.json @@ -0,0 +1,19 @@ +{ + "_id": "7a910023-cad2-4f49-9ce0-1a0c711613d3", + "_outcomes": [ + { + "displayName": "True", + "id": "true" + }, + { + "displayName": "False", + "id": "false" + } + ], + "_rev": "1005305455", + "_type": { + "_id": "AgentDataStoreDecisionNode", + "collection": true, + "name": "Agent Data Store Decision" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Page Node - 35cb0861-c160-47ff-808c-3429ba18772c.json b/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Page Node - 35cb0861-c160-47ff-808c-3429ba18772c.json new file mode 100644 index 000000000..cb567f17c --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Page Node - 35cb0861-c160-47ff-808c-3429ba18772c.json @@ -0,0 +1,29 @@ +{ + "_id": "35cb0861-c160-47ff-808c-3429ba18772c", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-520517447", + "_type": { + "_id": "PageNode", + "collection": true, + "name": "Page Node" + }, + "nodes": [ + { + "_id": "d0990b1c-e23d-4f0c-a32d-af3c4a1cd16e", + "displayName": "Username Collector", + "nodeType": "UsernameCollectorNode" + }, + { + "_id": "b0faff37-78ad-492f-a614-9b96814e6915", + "displayName": "Password Collector", + "nodeType": "PasswordCollectorNode" + } + ], + "pageDescription": {}, + "pageHeader": {} +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Page Node - 35cb0861-c160-47ff-808c-3429ba18772c/Password Collector - b0faff37-78ad-492f-a614-9b96814e6915.json b/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Page Node - 35cb0861-c160-47ff-808c-3429ba18772c/Password Collector - b0faff37-78ad-492f-a614-9b96814e6915.json new file mode 100644 index 000000000..a27c29c11 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Page Node - 35cb0861-c160-47ff-808c-3429ba18772c/Password Collector - b0faff37-78ad-492f-a614-9b96814e6915.json @@ -0,0 +1,15 @@ +{ + "_id": "b0faff37-78ad-492f-a614-9b96814e6915", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "835969126", + "_type": { + "_id": "PasswordCollectorNode", + "collection": true, + "name": "Password Collector" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Page Node - 35cb0861-c160-47ff-808c-3429ba18772c/Username Collector - d0990b1c-e23d-4f0c-a32d-af3c4a1cd16e.json b/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Page Node - 35cb0861-c160-47ff-808c-3429ba18772c/Username Collector - d0990b1c-e23d-4f0c-a32d-af3c4a1cd16e.json new file mode 100644 index 000000000..0165e7013 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Page Node - 35cb0861-c160-47ff-808c-3429ba18772c/Username Collector - d0990b1c-e23d-4f0c-a32d-af3c4a1cd16e.json @@ -0,0 +1,15 @@ +{ + "_id": "d0990b1c-e23d-4f0c-a32d-af3c4a1cd16e", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-674343946", + "_type": { + "_id": "UsernameCollectorNode", + "collection": true, + "name": "Username Collector" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Zero Page Login Collector - 6c24a892-4bae-48ad-8d9c-8061257c9ed7.json b/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Zero Page Login Collector - 6c24a892-4bae-48ad-8d9c-8061257c9ed7.json new file mode 100644 index 000000000..1dbc7f341 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Agent/nodes/Zero Page Login Collector - 6c24a892-4bae-48ad-8d9c-8061257c9ed7.json @@ -0,0 +1,23 @@ +{ + "_id": "6c24a892-4bae-48ad-8d9c-8061257c9ed7", + "_outcomes": [ + { + "displayName": "Has Credentials", + "id": "true" + }, + { + "displayName": "No Credentials", + "id": "false" + } + ], + "_rev": "-605868868", + "_type": { + "_id": "ZeroPageLoginNode", + "collection": true, + "name": "Zero Page Login Collector" + }, + "allowWithoutReferer": true, + "passwordHeader": "X-OpenAM-Password", + "referrerWhiteList": [], + "usernameHeader": "X-OpenAM-Username" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/ForgottenUsername.json b/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/ForgottenUsername.json new file mode 100644 index 000000000..7ada533a6 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/ForgottenUsername.json @@ -0,0 +1,67 @@ +{ + "_id": "ForgottenUsername", + "_rev": "-1065471530", + "description": "Forgotten Username Tree", + "enabled": true, + "entryNodeId": "5e2a7c95-94af-4b23-8724-deb13853726a", + "innerTreeOnly": false, + "mustRun": false, + "noSession": false, + "nodes": { + "5e2a7c95-94af-4b23-8724-deb13853726a": { + "connections": { + "outcome": "bf9ea8d5-9802-4f26-9664-a21840faac23" + }, + "displayName": "Page Node", + "nodeType": "PageNode", + "x": 139, + "y": 146 + }, + "b93ce36e-1976-4610-b24f-8d6760b5463b": { + "connections": { + "false": "e301438c-0bd0-429c-ab0c-66126501069a", + "true": "70e691a5-1e33-4ac3-a356-e7b6d60d92e0" + }, + "displayName": "Inner Tree Evaluator", + "nodeType": "InnerTreeEvaluatorNode", + "x": 767, + "y": 188 + }, + "bf9ea8d5-9802-4f26-9664-a21840faac23": { + "connections": { + "false": "d9a79f01-2ce3-4be2-a28a-975f35c3c8ca", + "true": "d9a79f01-2ce3-4be2-a28a-975f35c3c8ca" + }, + "displayName": "Identify Existing User", + "nodeType": "IdentifyExistingUserNode", + "x": 324, + "y": 152 + }, + "d9a79f01-2ce3-4be2-a28a-975f35c3c8ca": { + "connections": { + "outcome": "b93ce36e-1976-4610-b24f-8d6760b5463b" + }, + "displayName": "Email Suspend Node", + "nodeType": "EmailSuspendNode", + "x": 563, + "y": 193 + } + }, + "staticNodes": { + "70e691a5-1e33-4ac3-a356-e7b6d60d92e0": { + "x": 970, + "y": 149 + }, + "e301438c-0bd0-429c-ab0c-66126501069a": { + "x": 982, + "y": 252 + }, + "startNode": { + "x": 50, + "y": 25 + } + }, + "uiConfig": { + "categories": "[\"Username Reset\"]" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Email Suspend Node - d9a79f01-2ce3-4be2-a28a-975f35c3c8ca.json b/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Email Suspend Node - d9a79f01-2ce3-4be2-a28a-975f35c3c8ca.json new file mode 100644 index 000000000..7e36377c6 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Email Suspend Node - d9a79f01-2ce3-4be2-a28a-975f35c3c8ca.json @@ -0,0 +1,22 @@ +{ + "_id": "d9a79f01-2ce3-4be2-a28a-975f35c3c8ca", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "2035832000", + "_type": { + "_id": "EmailSuspendNode", + "collection": true, + "name": "Email Suspend Node" + }, + "emailAttribute": "mail", + "emailSuspendMessage": { + "en": "An email has been sent to the address you entered. Click the link in that email to proceed." + }, + "emailTemplateName": "forgottenUsername", + "identityAttribute": "mail", + "objectLookup": true +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Identify Existing User - bf9ea8d5-9802-4f26-9664-a21840faac23.json b/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Identify Existing User - bf9ea8d5-9802-4f26-9664-a21840faac23.json new file mode 100644 index 000000000..6ddcfaaf7 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Identify Existing User - bf9ea8d5-9802-4f26-9664-a21840faac23.json @@ -0,0 +1,21 @@ +{ + "_id": "bf9ea8d5-9802-4f26-9664-a21840faac23", + "_outcomes": [ + { + "displayName": "True", + "id": "true" + }, + { + "displayName": "False", + "id": "false" + } + ], + "_rev": "-626658673", + "_type": { + "_id": "IdentifyExistingUserNode", + "collection": true, + "name": "Identify Existing User" + }, + "identifier": "userName", + "identityAttribute": "mail" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Inner Tree Evaluator - b93ce36e-1976-4610-b24f-8d6760b5463b.json b/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Inner Tree Evaluator - b93ce36e-1976-4610-b24f-8d6760b5463b.json new file mode 100644 index 000000000..164915216 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Inner Tree Evaluator - b93ce36e-1976-4610-b24f-8d6760b5463b.json @@ -0,0 +1,21 @@ +{ + "_id": "b93ce36e-1976-4610-b24f-8d6760b5463b", + "_outcomes": [ + { + "displayName": "True", + "id": "true" + }, + { + "displayName": "False", + "id": "false" + } + ], + "_rev": "1166482376", + "_type": { + "_id": "InnerTreeEvaluatorNode", + "collection": true, + "name": "Inner Tree Evaluator" + }, + "displayErrorOutcome": false, + "tree": "Login" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Page Node - 5e2a7c95-94af-4b23-8724-deb13853726a.json b/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Page Node - 5e2a7c95-94af-4b23-8724-deb13853726a.json new file mode 100644 index 000000000..7941e54aa --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Page Node - 5e2a7c95-94af-4b23-8724-deb13853726a.json @@ -0,0 +1,28 @@ +{ + "_id": "5e2a7c95-94af-4b23-8724-deb13853726a", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1421046051", + "_type": { + "_id": "PageNode", + "collection": true, + "name": "Page Node" + }, + "nodes": [ + { + "_id": "9f1e8d94-4922-481b-9e14-212b66548900", + "displayName": "Attribute Collector", + "nodeType": "AttributeCollectorNode" + } + ], + "pageDescription": { + "en": "Enter your email address or Sign in" + }, + "pageHeader": { + "en": "Forgotten Username" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Page Node - 5e2a7c95-94af-4b23-8724-deb13853726a/Attribute Collector - 9f1e8d94-4922-481b-9e14-212b66548900.json b/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Page Node - 5e2a7c95-94af-4b23-8724-deb13853726a/Attribute Collector - 9f1e8d94-4922-481b-9e14-212b66548900.json new file mode 100644 index 000000000..f6f346c3f --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ForgottenUsername/nodes/Page Node - 5e2a7c95-94af-4b23-8724-deb13853726a/Attribute Collector - 9f1e8d94-4922-481b-9e14-212b66548900.json @@ -0,0 +1,21 @@ +{ + "_id": "9f1e8d94-4922-481b-9e14-212b66548900", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1331445210", + "_type": { + "_id": "AttributeCollectorNode", + "collection": true, + "name": "Attribute Collector" + }, + "attributesToCollect": [ + "mail" + ], + "identityAttribute": "mail", + "required": true, + "validateInputs": false +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Login/Login.json b/test/e2e/exports/fr-config-manager/realms/journeys/Login/Login.json new file mode 100644 index 000000000..2d2f6c8ee --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Login/Login.json @@ -0,0 +1,67 @@ +{ + "_id": "Login", + "_rev": "870652898", + "description": "Platform Login Tree", + "enabled": true, + "entryNodeId": "a12bc72f-ad97-4f1e-a789-a1fa3dd566c8", + "innerTreeOnly": false, + "mustRun": false, + "noSession": false, + "nodes": { + "2998c1c9-f4c8-4a00-b2c6-3426783ee49d": { + "connections": { + "false": "e301438c-0bd0-429c-ab0c-66126501069a", + "true": "bba3e0d8-8525-4e82-bf48-ac17f7988917" + }, + "displayName": "Data Store Decision", + "nodeType": "DataStoreDecisionNode", + "x": 315, + "y": 140 + }, + "33b24514-3e50-4180-8f08-ab6f4e51b07e": { + "connections": { + "false": "e301438c-0bd0-429c-ab0c-66126501069a", + "true": "70e691a5-1e33-4ac3-a356-e7b6d60d92e0" + }, + "displayName": "Inner Tree Evaluator", + "nodeType": "InnerTreeEvaluatorNode", + "x": 815, + "y": 180 + }, + "a12bc72f-ad97-4f1e-a789-a1fa3dd566c8": { + "connections": { + "outcome": "2998c1c9-f4c8-4a00-b2c6-3426783ee49d" + }, + "displayName": "Page Node", + "nodeType": "PageNode", + "x": 136, + "y": 59 + }, + "bba3e0d8-8525-4e82-bf48-ac17f7988917": { + "connections": { + "outcome": "33b24514-3e50-4180-8f08-ab6f4e51b07e" + }, + "displayName": "Increment Login Count", + "nodeType": "IncrementLoginCountNode", + "x": 564, + "y": 132 + } + }, + "staticNodes": { + "70e691a5-1e33-4ac3-a356-e7b6d60d92e0": { + "x": 1008, + "y": 186 + }, + "e301438c-0bd0-429c-ab0c-66126501069a": { + "x": 624, + "y": 267 + }, + "startNode": { + "x": 50, + "y": 25 + } + }, + "uiConfig": { + "categories": "[\"Authentication\"]" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Data Store Decision - 2998c1c9-f4c8-4a00-b2c6-3426783ee49d.json b/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Data Store Decision - 2998c1c9-f4c8-4a00-b2c6-3426783ee49d.json new file mode 100644 index 000000000..9da2a0ca6 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Data Store Decision - 2998c1c9-f4c8-4a00-b2c6-3426783ee49d.json @@ -0,0 +1,19 @@ +{ + "_id": "2998c1c9-f4c8-4a00-b2c6-3426783ee49d", + "_outcomes": [ + { + "displayName": "True", + "id": "true" + }, + { + "displayName": "False", + "id": "false" + } + ], + "_rev": "-656534578", + "_type": { + "_id": "DataStoreDecisionNode", + "collection": true, + "name": "Data Store Decision" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Increment Login Count - bba3e0d8-8525-4e82-bf48-ac17f7988917.json b/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Increment Login Count - bba3e0d8-8525-4e82-bf48-ac17f7988917.json new file mode 100644 index 000000000..f145b6f0c --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Increment Login Count - bba3e0d8-8525-4e82-bf48-ac17f7988917.json @@ -0,0 +1,16 @@ +{ + "_id": "bba3e0d8-8525-4e82-bf48-ac17f7988917", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "2098371942", + "_type": { + "_id": "IncrementLoginCountNode", + "collection": true, + "name": "Increment Login Count" + }, + "identityAttribute": "userName" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Inner Tree Evaluator - 33b24514-3e50-4180-8f08-ab6f4e51b07e.json b/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Inner Tree Evaluator - 33b24514-3e50-4180-8f08-ab6f4e51b07e.json new file mode 100644 index 000000000..6eb2692fd --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Inner Tree Evaluator - 33b24514-3e50-4180-8f08-ab6f4e51b07e.json @@ -0,0 +1,21 @@ +{ + "_id": "33b24514-3e50-4180-8f08-ab6f4e51b07e", + "_outcomes": [ + { + "displayName": "True", + "id": "true" + }, + { + "displayName": "False", + "id": "false" + } + ], + "_rev": "-1628846194", + "_type": { + "_id": "InnerTreeEvaluatorNode", + "collection": true, + "name": "Inner Tree Evaluator" + }, + "displayErrorOutcome": false, + "tree": "ProgressiveProfile" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Page Node - a12bc72f-ad97-4f1e-a789-a1fa3dd566c8.json b/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Page Node - a12bc72f-ad97-4f1e-a789-a1fa3dd566c8.json new file mode 100644 index 000000000..5c3007d64 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Page Node - a12bc72f-ad97-4f1e-a789-a1fa3dd566c8.json @@ -0,0 +1,33 @@ +{ + "_id": "a12bc72f-ad97-4f1e-a789-a1fa3dd566c8", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1594114", + "_type": { + "_id": "PageNode", + "collection": true, + "name": "Page Node" + }, + "nodes": [ + { + "_id": "7354982f-57b6-4b04-9ddc-f1dd1e1e07d0", + "displayName": "Platform Username", + "nodeType": "ValidatedUsernameNode" + }, + { + "_id": "0c80c39b-4813-4e67-b4fb-5a0bba85f994", + "displayName": "Platform Password", + "nodeType": "ValidatedPasswordNode" + } + ], + "pageDescription": { + "en": "New here? Create an account
Forgot username? Forgot password?" + }, + "pageHeader": { + "en": "Sign In" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Page Node - a12bc72f-ad97-4f1e-a789-a1fa3dd566c8/Platform Password - 0c80c39b-4813-4e67-b4fb-5a0bba85f994.json b/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Page Node - a12bc72f-ad97-4f1e-a789-a1fa3dd566c8/Platform Password - 0c80c39b-4813-4e67-b4fb-5a0bba85f994.json new file mode 100644 index 000000000..daa7cb7de --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Page Node - a12bc72f-ad97-4f1e-a789-a1fa3dd566c8/Platform Password - 0c80c39b-4813-4e67-b4fb-5a0bba85f994.json @@ -0,0 +1,17 @@ +{ + "_id": "0c80c39b-4813-4e67-b4fb-5a0bba85f994", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1763423776", + "_type": { + "_id": "ValidatedPasswordNode", + "collection": true, + "name": "Platform Password" + }, + "passwordAttribute": "password", + "validateInput": false +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Page Node - a12bc72f-ad97-4f1e-a789-a1fa3dd566c8/Platform Username - 7354982f-57b6-4b04-9ddc-f1dd1e1e07d0.json b/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Page Node - a12bc72f-ad97-4f1e-a789-a1fa3dd566c8/Platform Username - 7354982f-57b6-4b04-9ddc-f1dd1e1e07d0.json new file mode 100644 index 000000000..a6785997f --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Login/nodes/Page Node - a12bc72f-ad97-4f1e-a789-a1fa3dd566c8/Platform Username - 7354982f-57b6-4b04-9ddc-f1dd1e1e07d0.json @@ -0,0 +1,17 @@ +{ + "_id": "7354982f-57b6-4b04-9ddc-f1dd1e1e07d0", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-2064640544", + "_type": { + "_id": "ValidatedUsernameNode", + "collection": true, + "name": "Platform Username" + }, + "usernameAttribute": "userName", + "validateInput": false +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/ProgressiveProfile.json b/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/ProgressiveProfile.json new file mode 100644 index 000000000..40cfc432c --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/ProgressiveProfile.json @@ -0,0 +1,68 @@ +{ + "_id": "ProgressiveProfile", + "_rev": "2039065517", + "description": "Prompt for missing preferences on 3rd login", + "enabled": true, + "entryNodeId": "8afdaec3-275e-4301-bb53-34f03e6a4b29", + "innerTreeOnly": false, + "mustRun": false, + "noSession": false, + "nodes": { + "423a959a-a1b9-498a-b0f7-596b6b6e775a": { + "connections": { + "FAILURE": "e301438c-0bd0-429c-ab0c-66126501069a", + "PATCHED": "70e691a5-1e33-4ac3-a356-e7b6d60d92e0" + }, + "displayName": "Patch Object", + "nodeType": "PatchObjectNode", + "x": 766, + "y": 36 + }, + "8afdaec3-275e-4301-bb53-34f03e6a4b29": { + "connections": { + "false": "70e691a5-1e33-4ac3-a356-e7b6d60d92e0", + "true": "a1f45b44-5bf7-4c57-aa3f-75c619c7db8e" + }, + "displayName": "Login Count Decision", + "nodeType": "LoginCountDecisionNode", + "x": 152, + "y": 36 + }, + "a1f45b44-5bf7-4c57-aa3f-75c619c7db8e": { + "connections": { + "false": "70e691a5-1e33-4ac3-a356-e7b6d60d92e0", + "true": "a5aecad8-854a-4ed5-b719-ff6c90e858c0" + }, + "displayName": "Query Filter Decision", + "nodeType": "QueryFilterDecisionNode", + "x": 357, + "y": 36 + }, + "a5aecad8-854a-4ed5-b719-ff6c90e858c0": { + "connections": { + "outcome": "423a959a-a1b9-498a-b0f7-596b6b6e775a" + }, + "displayName": "Page Node", + "nodeType": "PageNode", + "x": 555, + "y": 20 + } + }, + "staticNodes": { + "70e691a5-1e33-4ac3-a356-e7b6d60d92e0": { + "x": 802, + "y": 312 + }, + "e301438c-0bd0-429c-ab0c-66126501069a": { + "x": 919, + "y": 171 + }, + "startNode": { + "x": 50, + "y": 58.5 + } + }, + "uiConfig": { + "categories": "[\"Progressive Profile\"]" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Login Count Decision - 8afdaec3-275e-4301-bb53-34f03e6a4b29.json b/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Login Count Decision - 8afdaec3-275e-4301-bb53-34f03e6a4b29.json new file mode 100644 index 000000000..0cfe92454 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Login Count Decision - 8afdaec3-275e-4301-bb53-34f03e6a4b29.json @@ -0,0 +1,22 @@ +{ + "_id": "8afdaec3-275e-4301-bb53-34f03e6a4b29", + "_outcomes": [ + { + "displayName": "True", + "id": "true" + }, + { + "displayName": "False", + "id": "false" + } + ], + "_rev": "-1679047423", + "_type": { + "_id": "LoginCountDecisionNode", + "collection": true, + "name": "Login Count Decision" + }, + "amount": 3, + "identityAttribute": "userName", + "interval": "AT" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Page Node - a5aecad8-854a-4ed5-b719-ff6c90e858c0.json b/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Page Node - a5aecad8-854a-4ed5-b719-ff6c90e858c0.json new file mode 100644 index 000000000..41b1beebd --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Page Node - a5aecad8-854a-4ed5-b719-ff6c90e858c0.json @@ -0,0 +1,26 @@ +{ + "_id": "a5aecad8-854a-4ed5-b719-ff6c90e858c0", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "380010937", + "_type": { + "_id": "PageNode", + "collection": true, + "name": "Page Node" + }, + "nodes": [ + { + "_id": "0a042e10-b22e-4e02-86c4-65e26e775f7a", + "displayName": "Attribute Collector", + "nodeType": "AttributeCollectorNode" + } + ], + "pageDescription": {}, + "pageHeader": { + "en": "Please select your preferences" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Page Node - a5aecad8-854a-4ed5-b719-ff6c90e858c0/Attribute Collector - 0a042e10-b22e-4e02-86c4-65e26e775f7a.json b/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Page Node - a5aecad8-854a-4ed5-b719-ff6c90e858c0/Attribute Collector - 0a042e10-b22e-4e02-86c4-65e26e775f7a.json new file mode 100644 index 000000000..a970bf295 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Page Node - a5aecad8-854a-4ed5-b719-ff6c90e858c0/Attribute Collector - 0a042e10-b22e-4e02-86c4-65e26e775f7a.json @@ -0,0 +1,22 @@ +{ + "_id": "0a042e10-b22e-4e02-86c4-65e26e775f7a", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1210529544", + "_type": { + "_id": "AttributeCollectorNode", + "collection": true, + "name": "Attribute Collector" + }, + "attributesToCollect": [ + "preferences/updates", + "preferences/marketing" + ], + "identityAttribute": "userName", + "required": false, + "validateInputs": false +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Patch Object - 423a959a-a1b9-498a-b0f7-596b6b6e775a.json b/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Patch Object - 423a959a-a1b9-498a-b0f7-596b6b6e775a.json new file mode 100644 index 000000000..8ef307c45 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Patch Object - 423a959a-a1b9-498a-b0f7-596b6b6e775a.json @@ -0,0 +1,23 @@ +{ + "_id": "423a959a-a1b9-498a-b0f7-596b6b6e775a", + "_outcomes": [ + { + "displayName": "Patched", + "id": "PATCHED" + }, + { + "displayName": "Failed", + "id": "FAILURE" + } + ], + "_rev": "1653653564", + "_type": { + "_id": "PatchObjectNode", + "collection": true, + "name": "Patch Object" + }, + "identityAttribute": "userName", + "identityResource": "managed/user", + "ignoredFields": [], + "patchAsObject": false +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Query Filter Decision - a1f45b44-5bf7-4c57-aa3f-75c619c7db8e.json b/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Query Filter Decision - a1f45b44-5bf7-4c57-aa3f-75c619c7db8e.json new file mode 100644 index 000000000..f1b66bc24 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ProgressiveProfile/nodes/Query Filter Decision - a1f45b44-5bf7-4c57-aa3f-75c619c7db8e.json @@ -0,0 +1,21 @@ +{ + "_id": "a1f45b44-5bf7-4c57-aa3f-75c619c7db8e", + "_outcomes": [ + { + "displayName": "True", + "id": "true" + }, + { + "displayName": "False", + "id": "false" + } + ], + "_rev": "-1852493841", + "_type": { + "_id": "QueryFilterDecisionNode", + "collection": true, + "name": "Query Filter Decision" + }, + "identityAttribute": "userName", + "queryFilter": "!(/preferences pr) or /preferences/marketing eq false or /preferences/updates eq false" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Registration/Registration.json b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/Registration.json new file mode 100644 index 000000000..618e11652 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/Registration.json @@ -0,0 +1,57 @@ +{ + "_id": "Registration", + "_rev": "-1700711221", + "description": "Platform Registration Tree", + "enabled": true, + "entryNodeId": "0c091c49-f3af-48fb-ac6f-07fba0499dd6", + "innerTreeOnly": false, + "mustRun": false, + "noSession": false, + "nodes": { + "0c091c49-f3af-48fb-ac6f-07fba0499dd6": { + "connections": { + "outcome": "ad5dcbb3-7335-49b7-b3e7-7d850bb88237" + }, + "displayName": "Page Node", + "nodeType": "PageNode", + "x": 261, + "y": 168 + }, + "97a15eb2-a015-4b6d-81a0-be78c3aa1a3b": { + "connections": { + "outcome": "70e691a5-1e33-4ac3-a356-e7b6d60d92e0" + }, + "displayName": "Increment Login Count", + "nodeType": "IncrementLoginCountNode", + "x": 681, + "y": 144 + }, + "ad5dcbb3-7335-49b7-b3e7-7d850bb88237": { + "connections": { + "CREATED": "97a15eb2-a015-4b6d-81a0-be78c3aa1a3b", + "FAILURE": "e301438c-0bd0-429c-ab0c-66126501069a" + }, + "displayName": "Create Object", + "nodeType": "CreateObjectNode", + "x": 537, + "y": 206 + } + }, + "staticNodes": { + "70e691a5-1e33-4ac3-a356-e7b6d60d92e0": { + "x": 905, + "y": 171 + }, + "e301438c-0bd0-429c-ab0c-66126501069a": { + "x": 741, + "y": 293 + }, + "startNode": { + "x": 50, + "y": 25 + } + }, + "uiConfig": { + "categories": "[\"Registration\"]" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Create Object - ad5dcbb3-7335-49b7-b3e7-7d850bb88237.json b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Create Object - ad5dcbb3-7335-49b7-b3e7-7d850bb88237.json new file mode 100644 index 000000000..bb3660e26 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Create Object - ad5dcbb3-7335-49b7-b3e7-7d850bb88237.json @@ -0,0 +1,20 @@ +{ + "_id": "ad5dcbb3-7335-49b7-b3e7-7d850bb88237", + "_outcomes": [ + { + "displayName": "Created", + "id": "CREATED" + }, + { + "displayName": "Failed", + "id": "FAILURE" + } + ], + "_rev": "-246787506", + "_type": { + "_id": "CreateObjectNode", + "collection": true, + "name": "Create Object" + }, + "identityResource": "managed/user" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Increment Login Count - 97a15eb2-a015-4b6d-81a0-be78c3aa1a3b.json b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Increment Login Count - 97a15eb2-a015-4b6d-81a0-be78c3aa1a3b.json new file mode 100644 index 000000000..64739d007 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Increment Login Count - 97a15eb2-a015-4b6d-81a0-be78c3aa1a3b.json @@ -0,0 +1,16 @@ +{ + "_id": "97a15eb2-a015-4b6d-81a0-be78c3aa1a3b", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-841385771", + "_type": { + "_id": "IncrementLoginCountNode", + "collection": true, + "name": "Increment Login Count" + }, + "identityAttribute": "userName" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6.json b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6.json new file mode 100644 index 000000000..e75d754d6 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6.json @@ -0,0 +1,48 @@ +{ + "_id": "0c091c49-f3af-48fb-ac6f-07fba0499dd6", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "762531723", + "_type": { + "_id": "PageNode", + "collection": true, + "name": "Page Node" + }, + "nodes": [ + { + "_id": "7fcaf48e-a754-4959-858b-05b2933b825f", + "displayName": "Platform Username", + "nodeType": "ValidatedUsernameNode" + }, + { + "_id": "d3ce2036-1523-4ce8-b1a2-895a2a036667", + "displayName": "Attribute Collector", + "nodeType": "AttributeCollectorNode" + }, + { + "_id": "3d8709a1-f09f-4d1f-8094-2850e472c1db", + "displayName": "Platform Password", + "nodeType": "ValidatedPasswordNode" + }, + { + "_id": "120c69d3-90b4-4ad4-b7af-380e8b119340", + "displayName": "KBA Definition", + "nodeType": "KbaCreateNode" + }, + { + "_id": "b4a0e915-c15d-4b83-9c9d-18347d645976", + "displayName": "Accept Terms and Conditions", + "nodeType": "AcceptTermsAndConditionsNode" + } + ], + "pageDescription": { + "en": "Signing up is fast and easy.
Already have an account? Sign In" + }, + "pageHeader": { + "en": "Sign Up" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/Accept Terms and Conditions - b4a0e915-c15d-4b83-9c9d-18347d645976.json b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/Accept Terms and Conditions - b4a0e915-c15d-4b83-9c9d-18347d645976.json new file mode 100644 index 000000000..5c9eb3068 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/Accept Terms and Conditions - b4a0e915-c15d-4b83-9c9d-18347d645976.json @@ -0,0 +1,15 @@ +{ + "_id": "b4a0e915-c15d-4b83-9c9d-18347d645976", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "1508860909", + "_type": { + "_id": "AcceptTermsAndConditionsNode", + "collection": true, + "name": "Accept Terms and Conditions" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/Attribute Collector - d3ce2036-1523-4ce8-b1a2-895a2a036667.json b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/Attribute Collector - d3ce2036-1523-4ce8-b1a2-895a2a036667.json new file mode 100644 index 000000000..bce405e63 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/Attribute Collector - d3ce2036-1523-4ce8-b1a2-895a2a036667.json @@ -0,0 +1,25 @@ +{ + "_id": "d3ce2036-1523-4ce8-b1a2-895a2a036667", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1158802257", + "_type": { + "_id": "AttributeCollectorNode", + "collection": true, + "name": "Attribute Collector" + }, + "attributesToCollect": [ + "givenName", + "sn", + "mail", + "preferences/marketing", + "preferences/updates" + ], + "identityAttribute": "userName", + "required": true, + "validateInputs": true +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/KBA Definition - 120c69d3-90b4-4ad4-b7af-380e8b119340.json b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/KBA Definition - 120c69d3-90b4-4ad4-b7af-380e8b119340.json new file mode 100644 index 000000000..870022725 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/KBA Definition - 120c69d3-90b4-4ad4-b7af-380e8b119340.json @@ -0,0 +1,19 @@ +{ + "_id": "120c69d3-90b4-4ad4-b7af-380e8b119340", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-8134977", + "_type": { + "_id": "KbaCreateNode", + "collection": true, + "name": "KBA Definition" + }, + "allowUserDefinedQuestions": true, + "message": { + "en": "Select a security question" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/Platform Password - 3d8709a1-f09f-4d1f-8094-2850e472c1db.json b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/Platform Password - 3d8709a1-f09f-4d1f-8094-2850e472c1db.json new file mode 100644 index 000000000..3b3d79ec4 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/Platform Password - 3d8709a1-f09f-4d1f-8094-2850e472c1db.json @@ -0,0 +1,17 @@ +{ + "_id": "3d8709a1-f09f-4d1f-8094-2850e472c1db", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1470058997", + "_type": { + "_id": "ValidatedPasswordNode", + "collection": true, + "name": "Platform Password" + }, + "passwordAttribute": "password", + "validateInput": true +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/Platform Username - 7fcaf48e-a754-4959-858b-05b2933b825f.json b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/Platform Username - 7fcaf48e-a754-4959-858b-05b2933b825f.json new file mode 100644 index 000000000..8a57e11a2 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/Registration/nodes/Page Node - 0c091c49-f3af-48fb-ac6f-07fba0499dd6/Platform Username - 7fcaf48e-a754-4959-858b-05b2933b825f.json @@ -0,0 +1,17 @@ +{ + "_id": "7fcaf48e-a754-4959-858b-05b2933b825f", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "1966656034", + "_type": { + "_id": "ValidatedUsernameNode", + "collection": true, + "name": "Platform Username" + }, + "usernameAttribute": "userName", + "validateInput": true +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/ResetPassword.json b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/ResetPassword.json new file mode 100644 index 000000000..b825d0aba --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/ResetPassword.json @@ -0,0 +1,76 @@ +{ + "_id": "ResetPassword", + "_rev": "1024569230", + "description": "Reset Password Tree", + "enabled": true, + "entryNodeId": "cc3e1ed2-25f1-47bf-83c6-17084f8b2b2b", + "innerTreeOnly": false, + "mustRun": false, + "noSession": false, + "nodes": { + "06c97be5-7fdd-4739-aea1-ecc7fe082865": { + "connections": { + "outcome": "e4c752f9-c625-48c9-9644-a58802fa9e9c" + }, + "displayName": "Email Suspend Node", + "nodeType": "EmailSuspendNode", + "x": 453, + "y": 66 + }, + "21b8ddf3-0203-4ae1-ab05-51cf3a3a707a": { + "connections": { + "false": "06c97be5-7fdd-4739-aea1-ecc7fe082865", + "true": "06c97be5-7fdd-4739-aea1-ecc7fe082865" + }, + "displayName": "Identify Existing User", + "nodeType": "IdentifyExistingUserNode", + "x": 271, + "y": 21 + }, + "989f0bf8-a328-4217-b82b-5275d79ca8bd": { + "connections": { + "FAILURE": "e301438c-0bd0-429c-ab0c-66126501069a", + "PATCHED": "70e691a5-1e33-4ac3-a356-e7b6d60d92e0" + }, + "displayName": "Patch Object", + "nodeType": "PatchObjectNode", + "x": 819, + "y": 61 + }, + "cc3e1ed2-25f1-47bf-83c6-17084f8b2b2b": { + "connections": { + "outcome": "21b8ddf3-0203-4ae1-ab05-51cf3a3a707a" + }, + "displayName": "Page Node", + "nodeType": "PageNode", + "x": 103, + "y": 50 + }, + "e4c752f9-c625-48c9-9644-a58802fa9e9c": { + "connections": { + "outcome": "989f0bf8-a328-4217-b82b-5275d79ca8bd" + }, + "displayName": "Page Node", + "nodeType": "PageNode", + "x": 643, + "y": 50 + } + }, + "staticNodes": { + "70e691a5-1e33-4ac3-a356-e7b6d60d92e0": { + "x": 970, + "y": 79 + }, + "e301438c-0bd0-429c-ab0c-66126501069a": { + "x": 981, + "y": 147 + }, + "startNode": { + "x": 25, + "y": 25 + } + }, + "uiConfig": { + "categories": "[\"Password Reset\"]" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Email Suspend Node - 06c97be5-7fdd-4739-aea1-ecc7fe082865.json b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Email Suspend Node - 06c97be5-7fdd-4739-aea1-ecc7fe082865.json new file mode 100644 index 000000000..d77f60afe --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Email Suspend Node - 06c97be5-7fdd-4739-aea1-ecc7fe082865.json @@ -0,0 +1,22 @@ +{ + "_id": "06c97be5-7fdd-4739-aea1-ecc7fe082865", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1138066714", + "_type": { + "_id": "EmailSuspendNode", + "collection": true, + "name": "Email Suspend Node" + }, + "emailAttribute": "mail", + "emailSuspendMessage": { + "en": "An email has been sent to the address you entered. Click the link in that email to proceed." + }, + "emailTemplateName": "resetPassword", + "identityAttribute": "mail", + "objectLookup": true +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Identify Existing User - 21b8ddf3-0203-4ae1-ab05-51cf3a3a707a.json b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Identify Existing User - 21b8ddf3-0203-4ae1-ab05-51cf3a3a707a.json new file mode 100644 index 000000000..234a361ae --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Identify Existing User - 21b8ddf3-0203-4ae1-ab05-51cf3a3a707a.json @@ -0,0 +1,21 @@ +{ + "_id": "21b8ddf3-0203-4ae1-ab05-51cf3a3a707a", + "_outcomes": [ + { + "displayName": "True", + "id": "true" + }, + { + "displayName": "False", + "id": "false" + } + ], + "_rev": "402776485", + "_type": { + "_id": "IdentifyExistingUserNode", + "collection": true, + "name": "Identify Existing User" + }, + "identifier": "userName", + "identityAttribute": "mail" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Page Node - cc3e1ed2-25f1-47bf-83c6-17084f8b2b2b.json b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Page Node - cc3e1ed2-25f1-47bf-83c6-17084f8b2b2b.json new file mode 100644 index 000000000..5ff01be45 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Page Node - cc3e1ed2-25f1-47bf-83c6-17084f8b2b2b.json @@ -0,0 +1,28 @@ +{ + "_id": "cc3e1ed2-25f1-47bf-83c6-17084f8b2b2b", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "86486605", + "_type": { + "_id": "PageNode", + "collection": true, + "name": "Page Node" + }, + "nodes": [ + { + "_id": "276afa7c-a680-4cf4-a5f6-d6c78191f5c9", + "displayName": "Attribute Collector", + "nodeType": "AttributeCollectorNode" + } + ], + "pageDescription": { + "en": "Enter your email address or Sign in" + }, + "pageHeader": { + "en": "Reset Password" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Page Node - cc3e1ed2-25f1-47bf-83c6-17084f8b2b2b/Attribute Collector - 276afa7c-a680-4cf4-a5f6-d6c78191f5c9.json b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Page Node - cc3e1ed2-25f1-47bf-83c6-17084f8b2b2b/Attribute Collector - 276afa7c-a680-4cf4-a5f6-d6c78191f5c9.json new file mode 100644 index 000000000..1cfd0defd --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Page Node - cc3e1ed2-25f1-47bf-83c6-17084f8b2b2b/Attribute Collector - 276afa7c-a680-4cf4-a5f6-d6c78191f5c9.json @@ -0,0 +1,21 @@ +{ + "_id": "276afa7c-a680-4cf4-a5f6-d6c78191f5c9", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1256358519", + "_type": { + "_id": "AttributeCollectorNode", + "collection": true, + "name": "Attribute Collector" + }, + "attributesToCollect": [ + "mail" + ], + "identityAttribute": "mail", + "required": true, + "validateInputs": false +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Page Node - e4c752f9-c625-48c9-9644-a58802fa9e9c.json b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Page Node - e4c752f9-c625-48c9-9644-a58802fa9e9c.json new file mode 100644 index 000000000..58b1f4bd6 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Page Node - e4c752f9-c625-48c9-9644-a58802fa9e9c.json @@ -0,0 +1,28 @@ +{ + "_id": "e4c752f9-c625-48c9-9644-a58802fa9e9c", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "1593283676", + "_type": { + "_id": "PageNode", + "collection": true, + "name": "Page Node" + }, + "nodes": [ + { + "_id": "009c19c8-9572-47bb-adb2-1f092c559a43", + "displayName": "Platform Password", + "nodeType": "ValidatedPasswordNode" + } + ], + "pageDescription": { + "en": "Change password" + }, + "pageHeader": { + "en": "Reset Password" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Page Node - e4c752f9-c625-48c9-9644-a58802fa9e9c/Platform Password - 009c19c8-9572-47bb-adb2-1f092c559a43.json b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Page Node - e4c752f9-c625-48c9-9644-a58802fa9e9c/Platform Password - 009c19c8-9572-47bb-adb2-1f092c559a43.json new file mode 100644 index 000000000..7661932f0 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Page Node - e4c752f9-c625-48c9-9644-a58802fa9e9c/Platform Password - 009c19c8-9572-47bb-adb2-1f092c559a43.json @@ -0,0 +1,17 @@ +{ + "_id": "009c19c8-9572-47bb-adb2-1f092c559a43", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "519412822", + "_type": { + "_id": "ValidatedPasswordNode", + "collection": true, + "name": "Platform Password" + }, + "passwordAttribute": "password", + "validateInput": true +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Patch Object - 989f0bf8-a328-4217-b82b-5275d79ca8bd.json b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Patch Object - 989f0bf8-a328-4217-b82b-5275d79ca8bd.json new file mode 100644 index 000000000..45f52bcc8 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ResetPassword/nodes/Patch Object - 989f0bf8-a328-4217-b82b-5275d79ca8bd.json @@ -0,0 +1,23 @@ +{ + "_id": "989f0bf8-a328-4217-b82b-5275d79ca8bd", + "_outcomes": [ + { + "displayName": "Patched", + "id": "PATCHED" + }, + { + "displayName": "Failed", + "id": "FAILURE" + } + ], + "_rev": "920985509", + "_type": { + "_id": "PatchObjectNode", + "collection": true, + "name": "Patch Object" + }, + "identityAttribute": "mail", + "identityResource": "managed/user", + "ignoredFields": [], + "patchAsObject": false +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/UpdatePassword.json b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/UpdatePassword.json new file mode 100644 index 000000000..a653d3fef --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/UpdatePassword.json @@ -0,0 +1,95 @@ +{ + "_id": "UpdatePassword", + "_rev": "459173545", + "description": "Update password using active session", + "enabled": true, + "entryNodeId": "d1b79744-493a-44fe-bc26-7d324a8caa4e", + "innerTreeOnly": false, + "mustRun": false, + "noSession": false, + "nodes": { + "0f0904e6-1da3-4cdb-9abf-0d2545016fab": { + "connections": { + "false": "a3d97b53-e38a-4b24-aed0-a021050eb744", + "true": "20237b34-26cb-4a0b-958f-abb422290d42" + }, + "displayName": "Attribute Present Decision", + "nodeType": "AttributePresentDecisionNode", + "x": 288, + "y": 133 + }, + "20237b34-26cb-4a0b-958f-abb422290d42": { + "connections": { + "outcome": "7d1deabe-cd98-49c8-943f-ca12305775f3" + }, + "displayName": "Page Node", + "nodeType": "PageNode", + "x": 526, + "y": 46 + }, + "3990ce1f-cce6-435b-ae1c-f138e89411c1": { + "connections": { + "FAILURE": "e301438c-0bd0-429c-ab0c-66126501069a", + "PATCHED": "70e691a5-1e33-4ac3-a356-e7b6d60d92e0" + }, + "displayName": "Patch Object", + "nodeType": "PatchObjectNode", + "x": 1062, + "y": 189 + }, + "7d1deabe-cd98-49c8-943f-ca12305775f3": { + "connections": { + "false": "e301438c-0bd0-429c-ab0c-66126501069a", + "true": "d018fcd1-4e22-4160-8c41-63bee51c9cb3" + }, + "displayName": "Data Store Decision", + "nodeType": "DataStoreDecisionNode", + "x": 722, + "y": 45 + }, + "a3d97b53-e38a-4b24-aed0-a021050eb744": { + "connections": { + "outcome": "d018fcd1-4e22-4160-8c41-63bee51c9cb3" + }, + "displayName": "Email Suspend Node", + "nodeType": "EmailSuspendNode", + "x": 659, + "y": 223 + }, + "d018fcd1-4e22-4160-8c41-63bee51c9cb3": { + "connections": { + "outcome": "3990ce1f-cce6-435b-ae1c-f138e89411c1" + }, + "displayName": "Page Node", + "nodeType": "PageNode", + "x": 943, + "y": 30 + }, + "d1b79744-493a-44fe-bc26-7d324a8caa4e": { + "connections": { + "outcome": "0f0904e6-1da3-4cdb-9abf-0d2545016fab" + }, + "displayName": "Get Session Data", + "nodeType": "SessionDataNode", + "x": 122, + "y": 129 + } + }, + "staticNodes": { + "70e691a5-1e33-4ac3-a356-e7b6d60d92e0": { + "x": 1212, + "y": 128 + }, + "e301438c-0bd0-429c-ab0c-66126501069a": { + "x": 939, + "y": 290 + }, + "startNode": { + "x": 50, + "y": 25 + } + }, + "uiConfig": { + "categories": "[\"Password Reset\"]" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Attribute Present Decision - 0f0904e6-1da3-4cdb-9abf-0d2545016fab.json b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Attribute Present Decision - 0f0904e6-1da3-4cdb-9abf-0d2545016fab.json new file mode 100644 index 000000000..824ba674e --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Attribute Present Decision - 0f0904e6-1da3-4cdb-9abf-0d2545016fab.json @@ -0,0 +1,21 @@ +{ + "_id": "0f0904e6-1da3-4cdb-9abf-0d2545016fab", + "_outcomes": [ + { + "displayName": "True", + "id": "true" + }, + { + "displayName": "False", + "id": "false" + } + ], + "_rev": "-1218497043", + "_type": { + "_id": "AttributePresentDecisionNode", + "collection": true, + "name": "Attribute Present Decision" + }, + "identityAttribute": "userName", + "presentAttribute": "password" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Data Store Decision - 7d1deabe-cd98-49c8-943f-ca12305775f3.json b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Data Store Decision - 7d1deabe-cd98-49c8-943f-ca12305775f3.json new file mode 100644 index 000000000..1d265346f --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Data Store Decision - 7d1deabe-cd98-49c8-943f-ca12305775f3.json @@ -0,0 +1,19 @@ +{ + "_id": "7d1deabe-cd98-49c8-943f-ca12305775f3", + "_outcomes": [ + { + "displayName": "True", + "id": "true" + }, + { + "displayName": "False", + "id": "false" + } + ], + "_rev": "869693667", + "_type": { + "_id": "DataStoreDecisionNode", + "collection": true, + "name": "Data Store Decision" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Email Suspend Node - a3d97b53-e38a-4b24-aed0-a021050eb744.json b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Email Suspend Node - a3d97b53-e38a-4b24-aed0-a021050eb744.json new file mode 100644 index 000000000..62cbe90b1 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Email Suspend Node - a3d97b53-e38a-4b24-aed0-a021050eb744.json @@ -0,0 +1,22 @@ +{ + "_id": "a3d97b53-e38a-4b24-aed0-a021050eb744", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1059437256", + "_type": { + "_id": "EmailSuspendNode", + "collection": true, + "name": "Email Suspend Node" + }, + "emailAttribute": "mail", + "emailSuspendMessage": { + "en": "An email has been sent to your address, please verify your email address to update your password. Click the link in that email to proceed." + }, + "emailTemplateName": "updatePassword", + "identityAttribute": "userName", + "objectLookup": true +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Get Session Data - d1b79744-493a-44fe-bc26-7d324a8caa4e.json b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Get Session Data - d1b79744-493a-44fe-bc26-7d324a8caa4e.json new file mode 100644 index 000000000..99f6569d0 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Get Session Data - d1b79744-493a-44fe-bc26-7d324a8caa4e.json @@ -0,0 +1,17 @@ +{ + "_id": "d1b79744-493a-44fe-bc26-7d324a8caa4e", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-716667889", + "_type": { + "_id": "SessionDataNode", + "collection": true, + "name": "Get Session Data" + }, + "sessionDataKey": "UserToken", + "sharedStateKey": "userName" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Page Node - 20237b34-26cb-4a0b-958f-abb422290d42.json b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Page Node - 20237b34-26cb-4a0b-958f-abb422290d42.json new file mode 100644 index 000000000..9f1e4654b --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Page Node - 20237b34-26cb-4a0b-958f-abb422290d42.json @@ -0,0 +1,28 @@ +{ + "_id": "20237b34-26cb-4a0b-958f-abb422290d42", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "1965792723", + "_type": { + "_id": "PageNode", + "collection": true, + "name": "Page Node" + }, + "nodes": [ + { + "_id": "fe2962fc-4db3-4066-8624-553649afc438", + "displayName": "Platform Password", + "nodeType": "ValidatedPasswordNode" + } + ], + "pageDescription": { + "en": "Enter current password" + }, + "pageHeader": { + "en": "Verify Existing Password" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Page Node - 20237b34-26cb-4a0b-958f-abb422290d42/Platform Password - fe2962fc-4db3-4066-8624-553649afc438.json b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Page Node - 20237b34-26cb-4a0b-958f-abb422290d42/Platform Password - fe2962fc-4db3-4066-8624-553649afc438.json new file mode 100644 index 000000000..4dcf63d1f --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Page Node - 20237b34-26cb-4a0b-958f-abb422290d42/Platform Password - fe2962fc-4db3-4066-8624-553649afc438.json @@ -0,0 +1,17 @@ +{ + "_id": "fe2962fc-4db3-4066-8624-553649afc438", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "875005143", + "_type": { + "_id": "ValidatedPasswordNode", + "collection": true, + "name": "Platform Password" + }, + "passwordAttribute": "password", + "validateInput": false +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Page Node - d018fcd1-4e22-4160-8c41-63bee51c9cb3.json b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Page Node - d018fcd1-4e22-4160-8c41-63bee51c9cb3.json new file mode 100644 index 000000000..eef271876 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Page Node - d018fcd1-4e22-4160-8c41-63bee51c9cb3.json @@ -0,0 +1,28 @@ +{ + "_id": "d018fcd1-4e22-4160-8c41-63bee51c9cb3", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1359533036", + "_type": { + "_id": "PageNode", + "collection": true, + "name": "Page Node" + }, + "nodes": [ + { + "_id": "21a99653-a7a7-47ee-b650-f493a84bba09", + "displayName": "Platform Password", + "nodeType": "ValidatedPasswordNode" + } + ], + "pageDescription": { + "en": "Enter new password" + }, + "pageHeader": { + "en": "Update Password" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Page Node - d018fcd1-4e22-4160-8c41-63bee51c9cb3/Platform Password - 21a99653-a7a7-47ee-b650-f493a84bba09.json b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Page Node - d018fcd1-4e22-4160-8c41-63bee51c9cb3/Platform Password - 21a99653-a7a7-47ee-b650-f493a84bba09.json new file mode 100644 index 000000000..4429f9401 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Page Node - d018fcd1-4e22-4160-8c41-63bee51c9cb3/Platform Password - 21a99653-a7a7-47ee-b650-f493a84bba09.json @@ -0,0 +1,17 @@ +{ + "_id": "21a99653-a7a7-47ee-b650-f493a84bba09", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "688403743", + "_type": { + "_id": "ValidatedPasswordNode", + "collection": true, + "name": "Platform Password" + }, + "passwordAttribute": "password", + "validateInput": true +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Patch Object - 3990ce1f-cce6-435b-ae1c-f138e89411c1.json b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Patch Object - 3990ce1f-cce6-435b-ae1c-f138e89411c1.json new file mode 100644 index 000000000..8426cdea7 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/UpdatePassword/nodes/Patch Object - 3990ce1f-cce6-435b-ae1c-f138e89411c1.json @@ -0,0 +1,25 @@ +{ + "_id": "3990ce1f-cce6-435b-ae1c-f138e89411c1", + "_outcomes": [ + { + "displayName": "Patched", + "id": "PATCHED" + }, + { + "displayName": "Failed", + "id": "FAILURE" + } + ], + "_rev": "152951098", + "_type": { + "_id": "PatchObjectNode", + "collection": true, + "name": "Patch Object" + }, + "identityAttribute": "userName", + "identityResource": "managed/user", + "ignoredFields": [ + "userName" + ], + "patchAsObject": false +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/amsterService/amsterService.json b/test/e2e/exports/fr-config-manager/realms/journeys/amsterService/amsterService.json new file mode 100644 index 000000000..0c2c9bcdb --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/amsterService/amsterService.json @@ -0,0 +1,40 @@ +{ + "_id": "amsterService", + "_rev": "-809809713", + "description": "Authentication Tree for Amster utility", + "enabled": true, + "entryNodeId": "cfcd2084-95d5-35ef-a6e7-d7f9f98764db", + "identityResource": "null", + "innerTreeOnly": false, + "mustRun": false, + "noSession": false, + "nodes": { + "cfcd2084-95d5-35ef-a6e7-d7f9f98764db": { + "connections": { + "false": "e301438c-0bd0-429c-ab0c-66126501069a", + "true": "70e691a5-1e33-4ac3-a356-e7b6d60d92e0" + }, + "displayName": "Amster Jwt Decision Node", + "nodeType": "AmsterJwtDecisionNode", + "x": 200, + "y": 30 + } + }, + "staticNodes": { + "70e691a5-1e33-4ac3-a356-e7b6d60d92e0": { + "x": 500, + "y": 30 + }, + "e301438c-0bd0-429c-ab0c-66126501069a": { + "x": 500, + "y": 130 + }, + "startNode": { + "x": 50, + "y": 30 + } + }, + "uiConfig": { + "categories": "[\"Authentication\"]" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/amsterService/nodes/Amster Jwt Decision Node - cfcd2084-95d5-35ef-a6e7-d7f9f98764db.json b/test/e2e/exports/fr-config-manager/realms/journeys/amsterService/nodes/Amster Jwt Decision Node - cfcd2084-95d5-35ef-a6e7-d7f9f98764db.json new file mode 100644 index 000000000..3c68a2ffd --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/amsterService/nodes/Amster Jwt Decision Node - cfcd2084-95d5-35ef-a6e7-d7f9f98764db.json @@ -0,0 +1,20 @@ +{ + "_id": "cfcd2084-95d5-35ef-a6e7-d7f9f98764db", + "_outcomes": [ + { + "displayName": "True", + "id": "true" + }, + { + "displayName": "False", + "id": "false" + } + ], + "_rev": "-1115967105", + "_type": { + "_id": "AmsterJwtDecisionNode", + "collection": true, + "name": "Amster Jwt Decision Node" + }, + "authorizedKeys": "/var/run/secrets/amster/authorized_keys" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/ldapService.json b/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/ldapService.json new file mode 100644 index 000000000..60a839c5c --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/ldapService.json @@ -0,0 +1,59 @@ +{ + "_id": "ldapService", + "_rev": "-972265986", + "description": "Authentication tree replacing old default chain for backward compatibility", + "enabled": true, + "entryNodeId": "eccbc87e-4b5c-32fe-a830-8fd9f2a7baf5", + "identityResource": "null", + "innerTreeOnly": false, + "mustRun": false, + "noSession": false, + "nodes": { + "6c8349cc-7260-3e62-a3b1-396831a8398a": { + "connections": { + "outcome": "c81e728d-9d4c-3f63-af06-7f89cc14862d" + }, + "displayName": "Page Node", + "nodeType": "PageNode", + "x": 500, + "y": 25 + }, + "c81e728d-9d4c-3f63-af06-7f89cc14862d": { + "connections": { + "false": "e301438c-0bd0-429c-ab0c-66126501069a", + "true": "70e691a5-1e33-4ac3-a356-e7b6d60d92e0" + }, + "displayName": "Data Store Decision", + "nodeType": "DataStoreDecisionNode", + "x": 800, + "y": 25 + }, + "eccbc87e-4b5c-32fe-a830-8fd9f2a7baf5": { + "connections": { + "false": "6c8349cc-7260-3e62-a3b1-396831a8398a", + "true": "c81e728d-9d4c-3f63-af06-7f89cc14862d" + }, + "displayName": "Zero Page Login Collector", + "nodeType": "ZeroPageLoginNode", + "x": 150, + "y": 25 + } + }, + "staticNodes": { + "70e691a5-1e33-4ac3-a356-e7b6d60d92e0": { + "x": 1000, + "y": 25 + }, + "e301438c-0bd0-429c-ab0c-66126501069a": { + "x": 1000, + "y": 200 + }, + "startNode": { + "x": 50, + "y": 25 + } + }, + "uiConfig": { + "categories": "[\"Authentication\"]" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Data Store Decision - c81e728d-9d4c-3f63-af06-7f89cc14862d.json b/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Data Store Decision - c81e728d-9d4c-3f63-af06-7f89cc14862d.json new file mode 100644 index 000000000..7ab8c1e04 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Data Store Decision - c81e728d-9d4c-3f63-af06-7f89cc14862d.json @@ -0,0 +1,19 @@ +{ + "_id": "c81e728d-9d4c-3f63-af06-7f89cc14862d", + "_outcomes": [ + { + "displayName": "True", + "id": "true" + }, + { + "displayName": "False", + "id": "false" + } + ], + "_rev": "1201833785", + "_type": { + "_id": "DataStoreDecisionNode", + "collection": true, + "name": "Data Store Decision" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Page Node - 6c8349cc-7260-3e62-a3b1-396831a8398a.json b/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Page Node - 6c8349cc-7260-3e62-a3b1-396831a8398a.json new file mode 100644 index 000000000..4e6a98540 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Page Node - 6c8349cc-7260-3e62-a3b1-396831a8398a.json @@ -0,0 +1,34 @@ +{ + "_id": "6c8349cc-7260-3e62-a3b1-396831a8398a", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1862464893", + "_type": { + "_id": "PageNode", + "collection": true, + "name": "Page Node" + }, + "nodes": [ + { + "_id": "cfcd2084-95d5-35ef-a6e7-dff9f98764db", + "displayName": "User Name Collector", + "nodeType": "UsernameCollectorNode" + }, + { + "_id": "c4ca4238-a0b9-3382-8dcc-509a6f75849c", + "displayName": "Password Collector", + "nodeType": "PasswordCollectorNode" + } + ], + "pageDescription": { + "en": "" + }, + "pageHeader": { + "en": "Sign In" + }, + "stage": "null" +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Page Node - 6c8349cc-7260-3e62-a3b1-396831a8398a/Password Collector - c4ca4238-a0b9-3382-8dcc-509a6f75849c.json b/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Page Node - 6c8349cc-7260-3e62-a3b1-396831a8398a/Password Collector - c4ca4238-a0b9-3382-8dcc-509a6f75849c.json new file mode 100644 index 000000000..e0d7bddf7 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Page Node - 6c8349cc-7260-3e62-a3b1-396831a8398a/Password Collector - c4ca4238-a0b9-3382-8dcc-509a6f75849c.json @@ -0,0 +1,15 @@ +{ + "_id": "c4ca4238-a0b9-3382-8dcc-509a6f75849c", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1271206474", + "_type": { + "_id": "PasswordCollectorNode", + "collection": true, + "name": "Password Collector" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Page Node - 6c8349cc-7260-3e62-a3b1-396831a8398a/User Name Collector - cfcd2084-95d5-35ef-a6e7-dff9f98764db.json b/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Page Node - 6c8349cc-7260-3e62-a3b1-396831a8398a/User Name Collector - cfcd2084-95d5-35ef-a6e7-dff9f98764db.json new file mode 100644 index 000000000..3d60f86b6 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Page Node - 6c8349cc-7260-3e62-a3b1-396831a8398a/User Name Collector - cfcd2084-95d5-35ef-a6e7-dff9f98764db.json @@ -0,0 +1,15 @@ +{ + "_id": "cfcd2084-95d5-35ef-a6e7-dff9f98764db", + "_outcomes": [ + { + "displayName": "Outcome", + "id": "outcome" + } + ], + "_rev": "-1588216697", + "_type": { + "_id": "UsernameCollectorNode", + "collection": true, + "name": "Username Collector" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Zero Page Login Collector - eccbc87e-4b5c-32fe-a830-8fd9f2a7baf5.json b/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Zero Page Login Collector - eccbc87e-4b5c-32fe-a830-8fd9f2a7baf5.json new file mode 100644 index 000000000..9d5f16818 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/journeys/ldapService/nodes/Zero Page Login Collector - eccbc87e-4b5c-32fe-a830-8fd9f2a7baf5.json @@ -0,0 +1,23 @@ +{ + "_id": "eccbc87e-4b5c-32fe-a830-8fd9f2a7baf5", + "_outcomes": [ + { + "displayName": "Has Credentials", + "id": "true" + }, + { + "displayName": "No Credentials", + "id": "false" + } + ], + "_rev": "1517053586", + "_type": { + "_id": "ZeroPageLoginNode", + "collection": true, + "name": "Zero Page Login Collector" + }, + "allowWithoutReferer": true, + "passwordHeader": "X-OpenAM-Password", + "referrerWhiteList": [], + "usernameHeader": "X-OpenAM-Username" +} diff --git a/test/e2e/exports/fr-config-manager/realms/realm-config/authentication.json b/test/e2e/exports/fr-config-manager/realms/realm-config/authentication.json new file mode 100644 index 000000000..414532457 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/realm-config/authentication.json @@ -0,0 +1,66 @@ +{ + "_id": "", + "_rev": "1552144906", + "_type": { + "_id": "EMPTY", + "collection": false, + "name": "Core" + }, + "accountlockout": { + "lockoutDuration": 0, + "lockoutDurationMultiplier": 1, + "lockoutWarnUserCount": 0, + "loginFailureCount": 5, + "loginFailureDuration": 300, + "loginFailureLockoutMode": false, + "storeInvalidAttemptsInDataStore": true + }, + "core": { + "adminAuthModule": "ldapService", + "orgConfig": "ldapService" + }, + "general": { + "defaultAuthLevel": 0, + "identityType": [ + "agent", + "user" + ], + "locale": "en_US", + "statelessSessionsEnabled": false, + "twoFactorRequired": false, + "userStatusCallbackPlugins": [] + }, + "postauthprocess": { + "loginFailureUrl": [], + "loginPostProcessClass": [], + "loginSuccessUrl": [ + "/am/console" + ], + "userAttributeSessionMapping": [], + "usernameGeneratorClass": "com.sun.identity.authentication.spi.DefaultUserIDGenerator", + "usernameGeneratorEnabled": true + }, + "security": { + "addClearSiteDataHeader": true, + "keyAlias": "test", + "moduleBasedAuthEnabled": true, + "sharedSecret": null, + "zeroPageLoginAllowedWithoutReferrer": true, + "zeroPageLoginEnabled": false, + "zeroPageLoginReferrerWhiteList": [] + }, + "trees": { + "authenticationSessionsMaxDuration": 5, + "authenticationSessionsStateManagement": "JWT", + "authenticationSessionsWhitelist": false, + "authenticationTreeCookieHttpOnly": true, + "suspendedAuthenticationTimeout": 5 + }, + "userprofile": { + "aliasAttributeName": [ + "uid" + ], + "defaultRole": [], + "dynamicProfileCreation": "false" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/01e1a3c0-038b-4c16-956a-6c9d89328cff.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/01e1a3c0-038b-4c16-956a-6c9d89328cff.json new file mode 100644 index 000000000..c3e37634b --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/01e1a3c0-038b-4c16-956a-6c9d89328cff.json @@ -0,0 +1,16 @@ +{ + "_id": "01e1a3c0-038b-4c16-956a-6c9d89328cff", + "context": "AUTHENTICATION_TREE_DECISION_NODE", + "createdBy": "null", + "creationDate": 0, + "default": true, + "description": "Default global script for a scripted decision node", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "null", + "lastModifiedDate": 0, + "name": "Authentication Tree Decision Node Script", + "script": { + "file": "scripts-content/AUTHENTICATION_TREE_DECISION_NODE/Authentication Tree Decision Node Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/11e1a3c0-038b-4c16-956a-6c9d89328cff.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/11e1a3c0-038b-4c16-956a-6c9d89328cff.json new file mode 100644 index 000000000..8bb02eeff --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/11e1a3c0-038b-4c16-956a-6c9d89328cff.json @@ -0,0 +1,16 @@ +{ + "_id": "11e1a3c0-038b-4c16-956a-6c9d89328cff", + "context": "SCRIPTED_DECISION_NODE", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1433147666269, + "default": true, + "description": "Default global script for a scripted decision node", + "evaluatorVersion": "2.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1433147666269, + "name": "Next Generation Scripted Decision Node Script", + "script": { + "file": "scripts-content/SCRIPTED_DECISION_NODE/Next Generation Scripted Decision Node Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/11e1a3c0-038b-4c16-956a-6c9d89328d00.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/11e1a3c0-038b-4c16-956a-6c9d89328d00.json new file mode 100644 index 000000000..51ed2bfd9 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/11e1a3c0-038b-4c16-956a-6c9d89328d00.json @@ -0,0 +1,16 @@ +{ + "_id": "11e1a3c0-038b-4c16-956a-6c9d89328d00", + "context": "DEVICE_MATCH_NODE", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1433147666269, + "default": true, + "description": "Default global script for a device match node", + "evaluatorVersion": "2.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1433147666269, + "name": "Next Generation Device Match Node Script", + "script": { + "file": "scripts-content/DEVICE_MATCH_NODE/Next Generation Device Match Node Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/13e3f263-9cd3-4844-8d1c-040fd0dd02eb.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/13e3f263-9cd3-4844-8d1c-040fd0dd02eb.json new file mode 100644 index 000000000..1895c6c73 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/13e3f263-9cd3-4844-8d1c-040fd0dd02eb.json @@ -0,0 +1,16 @@ +{ + "_id": "13e3f263-9cd3-4844-8d1c-040fd0dd02eb", + "context": "AUTHENTICATION_TREE_DECISION_NODE", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1433147666269, + "default": true, + "description": "Default global script template for Device Profile Match decision node script for Authentication Tree", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1433147666269, + "name": "Device Profile Match Template - Decision Node Script", + "script": { + "file": "scripts-content/AUTHENTICATION_TREE_DECISION_NODE/Device Profile Match Template - Decision Node Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/157298c0-7d31-4059-a95b-eeb08473b7e5.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/157298c0-7d31-4059-a95b-eeb08473b7e5.json new file mode 100644 index 000000000..0b7e6e205 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/157298c0-7d31-4059-a95b-eeb08473b7e5.json @@ -0,0 +1,16 @@ +{ + "_id": "157298c0-7d31-4059-a95b-eeb08473b7e5", + "context": "AUTHENTICATION_CLIENT_SIDE", + "createdBy": "null", + "creationDate": 0, + "default": true, + "description": "Default global script for client side Device Id (Match) Authentication Module", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "null", + "lastModifiedDate": 0, + "name": "Device Id (Match) - Client Side", + "script": { + "file": "scripts-content/AUTHENTICATION_CLIENT_SIDE/Device Id (Match) - Client Side.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/248b8a56-df81-4b1b-b4ba-45d994f6504c.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/248b8a56-df81-4b1b-b4ba-45d994f6504c.json new file mode 100644 index 000000000..98595e843 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/248b8a56-df81-4b1b-b4ba-45d994f6504c.json @@ -0,0 +1,16 @@ +{ + "_id": "248b8a56-df81-4b1b-b4ba-45d994f6504c", + "context": "SAML2_IDP_ADAPTER", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1433147666269, + "default": true, + "description": "Default global script for SAML2 IDP Adapter", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1433147666269, + "name": "SAML2 IDP Adapter Script", + "script": { + "file": "scripts-content/SAML2_IDP_ADAPTER/SAML2 IDP Adapter Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/25e6c06d-cf70-473b-bd28-26931edc476b.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/25e6c06d-cf70-473b-bd28-26931edc476b.json new file mode 100644 index 000000000..f6871fb0a --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/25e6c06d-cf70-473b-bd28-26931edc476b.json @@ -0,0 +1,16 @@ +{ + "_id": "25e6c06d-cf70-473b-bd28-26931edc476b", + "context": "OAUTH2_VALIDATE_SCOPE", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1433147666269, + "default": true, + "description": "Default global script for OAuth2 Scope Validation", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1433147666269, + "name": "OAuth2 Validate Scope Script", + "script": { + "file": "scripts-content/OAUTH2_VALIDATE_SCOPE/OAuth2 Validate Scope Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/36863ffb-40ec-48b9-94b1-9a99f71cc3b5.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/36863ffb-40ec-48b9-94b1-9a99f71cc3b5.json new file mode 100644 index 000000000..037b89876 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/36863ffb-40ec-48b9-94b1-9a99f71cc3b5.json @@ -0,0 +1,16 @@ +{ + "_id": "36863ffb-40ec-48b9-94b1-9a99f71cc3b5", + "context": "OIDC_CLAIMS", + "createdBy": "null", + "creationDate": 0, + "default": true, + "description": "Default global script for OIDC claims", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "null", + "lastModifiedDate": 0, + "name": "OIDC Claims Script", + "script": { + "file": "scripts-content/OIDC_CLAIMS/OIDC Claims Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/3f93ef6e-e54a-4393-aba1-f322656db28a.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/3f93ef6e-e54a-4393-aba1-f322656db28a.json new file mode 100644 index 000000000..fc947aec6 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/3f93ef6e-e54a-4393-aba1-f322656db28a.json @@ -0,0 +1,16 @@ +{ + "_id": "3f93ef6e-e54a-4393-aba1-f322656db28a", + "context": "OAUTH2_AUTHORIZE_ENDPOINT_DATA_PROVIDER", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1433147666269, + "default": true, + "description": "Default global script for OAuth2 Authorize Endpoint Data Provider", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1433147666269, + "name": "OAuth2 Authorize Endpoint Data Provider Script", + "script": { + "file": "scripts-content/OAUTH2_AUTHORIZE_ENDPOINT_DATA_PROVIDER/OAuth2 Authorize Endpoint Data Provider Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/400e48ba-3f13-4144-ac7b-f824ea8e98c5.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/400e48ba-3f13-4144-ac7b-f824ea8e98c5.json new file mode 100644 index 000000000..edfe7f372 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/400e48ba-3f13-4144-ac7b-f824ea8e98c5.json @@ -0,0 +1,16 @@ +{ + "_id": "400e48ba-3f13-4144-ac7b-f824ea8e98c5", + "context": "OAUTH2_SCRIPTED_JWT_ISSUER", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1433147666269, + "default": true, + "description": "Default global script for scripted JWT Issuers", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1433147666269, + "name": "OAuth2 JWT Issuer Script", + "script": { + "file": "scripts-content/OAUTH2_SCRIPTED_JWT_ISSUER/OAuth2 JWT Issuer Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/4a171d3a-056b-4ab7-a19f-d7e93ddf7ae5.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/4a171d3a-056b-4ab7-a19f-d7e93ddf7ae5.json new file mode 100644 index 000000000..1cf697d53 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/4a171d3a-056b-4ab7-a19f-d7e93ddf7ae5.json @@ -0,0 +1,16 @@ +{ + "_id": "4a171d3a-056b-4ab7-a19f-d7e93ddf7ae5", + "context": "SAML2_NAMEID_MAPPER", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1433147666269, + "default": true, + "description": "Default global script for SAML2 NameID Mapper", + "evaluatorVersion": "2.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1433147666269, + "name": "SAML2 NameID Mapper Script", + "script": { + "file": "scripts-content/SAML2_NAMEID_MAPPER/SAML2 NameID Mapper Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/4b6b7e8e-cf03-46c8-949f-c5742dbd6bc5.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/4b6b7e8e-cf03-46c8-949f-c5742dbd6bc5.json new file mode 100644 index 000000000..232ef0c9d --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/4b6b7e8e-cf03-46c8-949f-c5742dbd6bc5.json @@ -0,0 +1,16 @@ +{ + "_id": "4b6b7e8e-cf03-46c8-949f-c5742dbd6bc5", + "context": "OAUTH2_DYNAMIC_CLIENT_REGISTRATION", + "createdBy": "null", + "creationDate": 0, + "default": true, + "description": "Default global script for Dynamic Client Registration", + "evaluatorVersion": "2.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "null", + "lastModifiedDate": 0, + "name": "OAuth2 Dynamic Client Registration Script", + "script": { + "file": "scripts-content/OAUTH2_DYNAMIC_CLIENT_REGISTRATION/OAuth2 Dynamic Client Registration Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/5e854779-6ec1-4c39-aeba-0477e0986646.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/5e854779-6ec1-4c39-aeba-0477e0986646.json new file mode 100644 index 000000000..b1ffc39c0 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/5e854779-6ec1-4c39-aeba-0477e0986646.json @@ -0,0 +1,16 @@ +{ + "_id": "5e854779-6ec1-4c39-aeba-0477e0986646", + "context": "CONFIG_PROVIDER_NODE", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1433147666269, + "default": true, + "description": "Default global script for Config Provider", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1433147666269, + "name": "Config Provider", + "script": { + "file": "scripts-content/CONFIG_PROVIDER_NODE/Config Provider.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/69f06e63-128c-4e2f-af52-079a8a6f448b.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/69f06e63-128c-4e2f-af52-079a8a6f448b.json new file mode 100644 index 000000000..900caf3dd --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/69f06e63-128c-4e2f-af52-079a8a6f448b.json @@ -0,0 +1,16 @@ +{ + "_id": "69f06e63-128c-4e2f-af52-079a8a6f448b", + "context": "SAML2_SP_ADAPTER", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1663685699666, + "default": true, + "description": "Default global script for SAML2 SP Adapter", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1663685699666, + "name": "SAML2 SP Adapter Script", + "script": { + "file": "scripts-content/SAML2_SP_ADAPTER/SAML2 SP Adapter Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/6c49bebe-3a62-11ed-a261-0242ac120002.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/6c49bebe-3a62-11ed-a261-0242ac120002.json new file mode 100644 index 000000000..d9db5f503 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/6c49bebe-3a62-11ed-a261-0242ac120002.json @@ -0,0 +1,16 @@ +{ + "_id": "6c49bebe-3a62-11ed-a261-0242ac120002", + "context": "LIBRARY", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1433147666269, + "default": true, + "description": "Default global library script to be referenced from other scripts", + "evaluatorVersion": "2.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1433147666269, + "name": "Library Script", + "script": { + "file": "scripts-content/LIBRARY/Library Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/703dab1a-1921-4981-98dd-b8e5349d8548.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/703dab1a-1921-4981-98dd-b8e5349d8548.json new file mode 100644 index 000000000..94cecb435 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/703dab1a-1921-4981-98dd-b8e5349d8548.json @@ -0,0 +1,16 @@ +{ + "_id": "703dab1a-1921-4981-98dd-b8e5349d8548", + "context": "AUTHENTICATION_SERVER_SIDE", + "createdBy": "null", + "creationDate": 0, + "default": true, + "description": "Default global script for server side Device Id (Match) Authentication Module", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "null", + "lastModifiedDate": 0, + "name": "Device Id (Match) - Server Side", + "script": { + "file": "scripts-content/AUTHENTICATION_SERVER_SIDE/Device Id (Match) - Server Side.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/7e3d7067-d50f-4674-8c76-a3e13a810c33.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/7e3d7067-d50f-4674-8c76-a3e13a810c33.json new file mode 100644 index 000000000..f7a4e8105 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/7e3d7067-d50f-4674-8c76-a3e13a810c33.json @@ -0,0 +1,16 @@ +{ + "_id": "7e3d7067-d50f-4674-8c76-a3e13a810c33", + "context": "AUTHENTICATION_SERVER_SIDE", + "createdBy": "null", + "creationDate": 0, + "default": true, + "description": "Default global script for server side Scripted Authentication Module", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "null", + "lastModifiedDate": 0, + "name": "Scripted Module - Server Side", + "script": { + "file": "scripts-content/AUTHENTICATION_SERVER_SIDE/Scripted Module - Server Side.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/9de3eb62-f131-4fac-a294-7bd170fd4acb.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/9de3eb62-f131-4fac-a294-7bd170fd4acb.json new file mode 100644 index 000000000..c026e3d84 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/9de3eb62-f131-4fac-a294-7bd170fd4acb.json @@ -0,0 +1,16 @@ +{ + "_id": "9de3eb62-f131-4fac-a294-7bd170fd4acb", + "context": "POLICY_CONDITION", + "createdBy": "null", + "creationDate": 0, + "default": true, + "description": "Default global script for Scripted Policy Conditions", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "null", + "lastModifiedDate": 0, + "name": "Scripted Policy Condition", + "script": { + "file": "scripts-content/POLICY_CONDITION/Scripted Policy Condition.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/c4f22465-2368-4e27-8013-e6399974fd48.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/c4f22465-2368-4e27-8013-e6399974fd48.json new file mode 100644 index 000000000..53b494059 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/c4f22465-2368-4e27-8013-e6399974fd48.json @@ -0,0 +1,16 @@ +{ + "_id": "c4f22465-2368-4e27-8013-e6399974fd48", + "context": "SAML2_IDP_ATTRIBUTE_MAPPER", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1433147666269, + "default": true, + "description": "Default global script for SAML2 IDP Attribute Mapper Script", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1433147666269, + "name": "SAML2 IDP Attribute Mapper Script", + "script": { + "file": "scripts-content/SAML2_IDP_ATTRIBUTE_MAPPER/SAML2 IDP Attribute Mapper Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/c735de08-f8f2-4e69-aa4a-2d8d3d438323.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/c735de08-f8f2-4e69-aa4a-2d8d3d438323.json new file mode 100644 index 000000000..d4da91bee --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/c735de08-f8f2-4e69-aa4a-2d8d3d438323.json @@ -0,0 +1,16 @@ +{ + "_id": "c735de08-f8f2-4e69-aa4a-2d8d3d438323", + "context": "OAUTH2_MAY_ACT", + "createdBy": "null", + "creationDate": 0, + "default": true, + "description": "Default global script for OAuth2 May Act", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "null", + "lastModifiedDate": 0, + "name": "OAuth2 May Act Script", + "script": { + "file": "scripts-content/OAUTH2_MAY_ACT/OAuth2 May Act Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/c827d2b4-3608-4693-868e-bbcf86bd87c7.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/c827d2b4-3608-4693-868e-bbcf86bd87c7.json new file mode 100644 index 000000000..f3f5115e9 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/c827d2b4-3608-4693-868e-bbcf86bd87c7.json @@ -0,0 +1,16 @@ +{ + "_id": "c827d2b4-3608-4693-868e-bbcf86bd87c7", + "context": "AUTHENTICATION_CLIENT_SIDE", + "createdBy": "null", + "creationDate": 0, + "default": true, + "description": "Default global script for client side Scripted Authentication Module", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "null", + "lastModifiedDate": 0, + "name": "Scripted Module - Client Side", + "script": { + "file": "scripts-content/AUTHENTICATION_CLIENT_SIDE/Scripted Module - Client Side.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/d22f9a0c-426a-4466-b95e-d0f125b0d5fa.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/d22f9a0c-426a-4466-b95e-d0f125b0d5fa.json new file mode 100644 index 000000000..33b7e0e58 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/d22f9a0c-426a-4466-b95e-d0f125b0d5fa.json @@ -0,0 +1,16 @@ +{ + "_id": "d22f9a0c-426a-4466-b95e-d0f125b0d5fa", + "context": "OAUTH2_ACCESS_TOKEN_MODIFICATION", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1433147666269, + "default": true, + "description": "Default global script for OAuth2 Access Token Modification", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1433147666269, + "name": "OAuth2 Access Token Modification Script", + "script": { + "file": "scripts-content/OAUTH2_ACCESS_TOKEN_MODIFICATION/OAuth2 Access Token Modification Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/da56fe60-8b38-4c46-a405-d6b306d4b336.json b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/da56fe60-8b38-4c46-a405-d6b306d4b336.json new file mode 100644 index 000000000..344125cc1 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-config/da56fe60-8b38-4c46-a405-d6b306d4b336.json @@ -0,0 +1,16 @@ +{ + "_id": "da56fe60-8b38-4c46-a405-d6b306d4b336", + "context": "OAUTH2_EVALUATE_SCOPE", + "createdBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "creationDate": 1433147666269, + "default": true, + "description": "Default global script for OAuth2 Scope Evaluation", + "evaluatorVersion": "1.0", + "language": "JAVASCRIPT", + "lastModifiedBy": "id=dsameuser,ou=user,dc=openam,dc=forgerock,dc=org", + "lastModifiedDate": 1433147666269, + "name": "OAuth2 Evaluate Scope Script", + "script": { + "file": "scripts-content/OAUTH2_EVALUATE_SCOPE/OAuth2 Evaluate Scope Script.js" + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_CLIENT_SIDE/Device Id (Match) - Client Side.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_CLIENT_SIDE/Device Id (Match) - Client Side.js new file mode 100644 index 000000000..34de64bd6 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_CLIENT_SIDE/Device Id (Match) - Client Side.js @@ -0,0 +1,245 @@ +var fontDetector = (function () { + /** + * JavaScript code to detect available availability of a + * particular font in a browser using JavaScript and CSS. + * + * Author : Lalit Patel + * Website: http://www.lalit.org/lab/javascript-css-font-detect/ + * License: Apache Software License 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * Version: 0.15 (21 Sep 2009) + * Changed comparision font to default from sans-default-default, + * as in FF3.0 font of child element didn't fallback + * to parent element if the font is missing. + * Version: 0.2 (04 Mar 2012) + * Comparing font against all the 3 generic font families ie, + * 'monospace', 'sans-serif' and 'sans'. If it doesn't match all 3 + * then that font is 100% not available in the system + * Version: 0.3 (24 Mar 2012) + * Replaced sans with serif in the list of baseFonts + */ + /* + * Portions Copyrighted 2013-2025 Ping Identity Corporation + */ + var detector = {}, baseFonts, testString, testSize, h, s, defaultWidth = {}, defaultHeight = {}, index; + + // a font will be compared against all the three default fonts. + // and if it doesn't match all 3 then that font is not available. + baseFonts = ['monospace', 'sans-serif', 'serif']; + + //we use m or w because these two characters take up the maximum width. + // And we use a LLi so that the same matching fonts can get separated + testString = "mmmmmmmmmmlli"; + + //we test using 72px font size, we may use any size. I guess larger the better. + testSize = '72px'; + + h = document.getElementsByTagName("body")[0]; + + // create a SPAN in the document to get the width of the text we use to test + s = document.createElement("span"); + s.style.fontSize = testSize; + s.innerHTML = testString; + for (index in baseFonts) { + //get the default width for the three base fonts + s.style.fontFamily = baseFonts[index]; + h.appendChild(s); + defaultWidth[baseFonts[index]] = s.offsetWidth; //width for the default font + defaultHeight[baseFonts[index]] = s.offsetHeight; //height for the defualt font + h.removeChild(s); + } + + detector.detect = function(font) { + var detected = false, index, matched; + for (index in baseFonts) { + s.style.fontFamily = font + ',' + baseFonts[index]; // name of the font along with the base font for fallback. + h.appendChild(s); + matched = (s.offsetWidth !== defaultWidth[baseFonts[index]] || s.offsetHeight !== defaultHeight[baseFonts[index]]); + h.removeChild(s); + detected = detected || matched; + } + return detected; + }; + + return detector; +}()); +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2009 Sun Microsystems Inc. All Rights Reserved + * + * The contents of this file are subject to the terms + * of the Common Development and Distribution License + * (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at + * https://opensso.dev.java.net/public/CDDLv1.0.html or + * opensso/legal/CDDLv1.0.txt + * See the License for the specific language governing + * permission and limitations under the License. + * + * When distributing Covered Code, include this CDDL + * Header Notice in each file and include the License file + * at opensso/legal/CDDLv1.0.txt. + * If applicable, add the following below the CDDL Header, + * with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + */ +/* + * Portions Copyrighted 2013 Syntegrity. + * Portions Copyrighted 2013-2025 Ping Identity Corporation + */ + +var collectScreenInfo = function () { + var screenInfo = {}; + if (screen) { + if (screen.width) { + screenInfo.screenWidth = screen.width; + } + + if (screen.height) { + screenInfo.screenHeight = screen.height; + } + + if (screen.pixelDepth) { + screenInfo.screenColourDepth = screen.pixelDepth; + } + } else { + console.warn("Cannot collect screen information. screen is not defined."); + } + return screenInfo; + }, + collectTimezoneInfo = function () { + var timezoneInfo = {}, offset = new Date().getTimezoneOffset(); + + if (offset) { + timezoneInfo.timezone = offset; + } else { + console.warn("Cannot collect timezone information. timezone is not defined."); + } + + return timezoneInfo; + }, + collectBrowserPluginsInfo = function () { + + if (navigator && navigator.plugins) { + var pluginsInfo = {}, i, plugins = navigator.plugins; + pluginsInfo.installedPlugins = ""; + + for (i = 0; i < plugins.length; i++) { + pluginsInfo.installedPlugins = pluginsInfo.installedPlugins + plugins[i].filename + ";"; + } + + return pluginsInfo; + } else { + console.warn("Cannot collect browser plugin information. navigator.plugins is not defined."); + return {}; + } + + }, +// Getting geolocation takes some time and is done asynchronously, hence need a callback which is called once geolocation is retrieved. + collectGeolocationInfo = function (callback) { + var geolocationInfo = {}, + successCallback = function(position) { + geolocationInfo.longitude = position.coords.longitude; + geolocationInfo.latitude = position.coords.latitude; + callback(geolocationInfo); + }, errorCallback = function(error) { + console.warn("Cannot collect geolocation information. " + error.code + ": " + error.message); + callback(geolocationInfo); + }; + if (navigator && navigator.geolocation) { + // NB: If user chooses 'Not now' on Firefox neither callback gets called + // https://bugzilla.mozilla.org/show_bug.cgi?id=675533 + navigator.geolocation.getCurrentPosition(successCallback, errorCallback); + } else { + console.warn("Cannot collect geolocation information. navigator.geolocation is not defined."); + callback(geolocationInfo); + } + }, + collectBrowserFontsInfo = function () { + var fontsInfo = {}, i, fontsList = ["cursive","monospace","serif","sans-serif","fantasy","default","Arial","Arial Black", + "Arial Narrow","Arial Rounded MT Bold","Bookman Old Style","Bradley Hand ITC","Century","Century Gothic", + "Comic Sans MS","Courier","Courier New","Georgia","Gentium","Impact","King","Lucida Console","Lalit", + "Modena","Monotype Corsiva","Papyrus","Tahoma","TeX","Times","Times New Roman","Trebuchet MS","Verdana", + "Verona"]; + fontsInfo.installedFonts = ""; + + for (i = 0; i < fontsList.length; i++) { + if (fontDetector.detect(fontsList[i])) { + fontsInfo.installedFonts = fontsInfo.installedFonts + fontsList[i] + ";"; + } + } + return fontsInfo; + }, + devicePrint = {}; + +devicePrint.screen = collectScreenInfo(); +devicePrint.timezone = collectTimezoneInfo(); +devicePrint.plugins = collectBrowserPluginsInfo(); +devicePrint.fonts = collectBrowserFontsInfo(); + +if (navigator.userAgent) { + devicePrint.userAgent = navigator.userAgent; +} +if (navigator.appName) { + devicePrint.appName = navigator.appName; +} +if (navigator.appCodeName) { + devicePrint.appCodeName = navigator.appCodeName; +} +if (navigator.appVersion) { + devicePrint.appVersion = navigator.appVersion; +} +if (navigator.appMinorVersion) { + devicePrint.appMinorVersion = navigator.appMinorVersion; +} +if (navigator.buildID) { + devicePrint.buildID = navigator.buildID; +} +if (navigator.platform) { + devicePrint.platform = navigator.platform; +} +if (navigator.cpuClass) { + devicePrint.cpuClass = navigator.cpuClass; +} +if (navigator.oscpu) { + devicePrint.oscpu = navigator.oscpu; +} +if (navigator.product) { + devicePrint.product = navigator.product; +} +if (navigator.productSub) { + devicePrint.productSub = navigator.productSub; +} +if (navigator.vendor) { + devicePrint.vendor = navigator.vendor; +} +if (navigator.vendorSub) { + devicePrint.vendorSub = navigator.vendorSub; +} +if (navigator.language) { + devicePrint.language = navigator.language; +} +if (navigator.userLanguage) { + devicePrint.userLanguage = navigator.userLanguage; +} +if (navigator.browserLanguage) { + devicePrint.browserLanguage = navigator.browserLanguage; +} +if (navigator.systemLanguage) { + devicePrint.systemLanguage = navigator.systemLanguage; +} + +// Attempt to collect geo-location information and return this with the data collected so far. +// Otherwise, if geo-location fails or takes longer than 30 seconds, auto-submit the data collected so far. +autoSubmitDelay = 30000; +output.value = JSON.stringify(devicePrint); +collectGeolocationInfo(function(geolocationInfo) { + devicePrint.geolocation = geolocationInfo; + output.value = JSON.stringify(devicePrint); + submit(); +}); diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_CLIENT_SIDE/Scripted Module - Client Side.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_CLIENT_SIDE/Scripted Module - Client Side.js new file mode 100644 index 000000000..3bdd1a0d7 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_CLIENT_SIDE/Scripted Module - Client Side.js @@ -0,0 +1,9 @@ +/* + * Copyright 2016-2025 Ping Identity Corporation. All Rights Reserved + * + * This code is to be used exclusively in connection with Ping Identity + * Corporation software or services. Ping Identity Corporation only offers + * such software or services to legal entities who have entered into a + * binding license agreement with Ping Identity Corporation. + */ +/* Default Authentication client side script to use as a template for new scripts */ diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_SERVER_SIDE/Device Id (Match) - Server Side.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_SERVER_SIDE/Device Id (Match) - Server Side.js new file mode 100644 index 000000000..96b6f890a --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_SERVER_SIDE/Device Id (Match) - Server Side.js @@ -0,0 +1,831 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2009 Sun Microsystems Inc. All Rights Reserved + * + * The contents of this file are subject to the terms + * of the Common Development and Distribution License + * (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at + * https://opensso.dev.java.net/public/CDDLv1.0.html or + * opensso/legal/CDDLv1.0.txt + * See the License for the specific language governing + * permission and limitations under the License. + * + * When distributing Covered Code, include this CDDL + * Header Notice in each file and include the License file + * at opensso/legal/CDDLv1.0.txt. + * If applicable, add the following below the CDDL Header, + * with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + */ +/* + * Portions Copyrighted 2013 Syntegrity. + * Portions Copyrighted 2013-2025 Ping Identity Corporation + */ + +var ScalarComparator = {}, ScreenComparator = {}, MultiValueComparator = {}, UserAgentComparator = {}, GeolocationComparator = {}; + +var config = { + profileExpiration: 30, //in days + maxProfilesAllowed: 5, + maxPenaltyPoints: 0, + attributes: { + screen: { + required: true, + comparator: ScreenComparator, + args: { + penaltyPoints: 50 + } + }, + plugins: { + installedPlugins: { + required: false, + comparator: MultiValueComparator, + args: { + maxPercentageDifference: 10, + maxDifferences: 5, + penaltyPoints: 100 + } + } + }, + fonts: { + installedFonts: { + required: false, + comparator: MultiValueComparator, + args: { + maxPercentageDifference: 10, + maxDifferences: 5, + penaltyPoints: 100 + } + } + }, + timezone: { + timezone: { + required: false, + comparator: ScalarComparator, + args: { + penaltyPoints: 100 + } + } + }, + userAgent: { + required: true, + comparator: UserAgentComparator, + args: { + ignoreVersion: true, + penaltyPoints: 100 + } + }, + geolocation: { + required: false, + comparator: GeolocationComparator, + args: { + allowedRange: 100, //in miles + penaltyPoints: 100 + } + } + } +}; + +//---------------------------------------------------------------------------// +// Comparator functions // +//---------------------------------------------------------------------------// + +var all, any, calculateDistance, calculateIntersection, calculatePercentage, nullOrUndefined, splitAndTrim, + undefinedLocation; + +// ComparisonResult + +/** + * Constructs an instance of a ComparisonResult with the given penalty points. + * + * @param penaltyPoints (Number) The penalty points for the comparison (defaults to 0). + * @param additionalInfoInCurrentValue (boolean) Whether the current value contains more information + * than the stored value (defaults to false). + */ +function ComparisonResult() { + + var penaltyPoints = 0, + additionalInfoInCurrentValue = false; + + if (arguments[0] !== undefined && arguments[1] !== undefined) { + penaltyPoints = arguments[0]; + additionalInfoInCurrentValue = arguments[1]; + } + + if (arguments[0] !== undefined && arguments[1] === undefined) { + if (typeof(arguments[0]) === "boolean") { + additionalInfoInCurrentValue = arguments[0]; + } else { + penaltyPoints = arguments[0]; + } + } + + this.penaltyPoints = penaltyPoints; + this.additionalInfoInCurrentValue = additionalInfoInCurrentValue; + +} + +ComparisonResult.ZERO_PENALTY_POINTS = new ComparisonResult(0); + +/** + * Static method for functional programming. + * + * @return boolean true if comparisonResult.isSuccessful(). + */ +ComparisonResult.isSuccessful = function(comparisonResult) { + return comparisonResult.isSuccessful(); +}; + + +/** + * Static method for functional programming. + * + * @return boolean true if comparisonResult.additionalInfoInCurrentValue. + */ +ComparisonResult.additionalInfoInCurrentValue = function(comparisonResult) { + return comparisonResult.additionalInfoInCurrentValue; +}; + +/** + * Comparison function that can be provided as an argument to array.sort + */ +ComparisonResult.compare = function(first, second) { + if (nullOrUndefined(first) && nullOrUndefined(second)) { + return 0; + } else if (nullOrUndefined(first)) { + return -1; + } else if (nullOrUndefined(second)) { + return 1; + } else { + if (first.penaltyPoints !== second.penaltyPoints) { + return first.penaltyPoints - second.penaltyPoints; + } else { + return (first.additionalInfoInCurrentValue ? 1 : 0) - (second.additionalInfoInCurrentValue ? 1 : 0); + } + } +}; + +/** + * Amalgamates the given ComparisonResult into this ComparisonResult. + * + * @param comparisonResult The ComparisonResult to include. + */ +ComparisonResult.prototype.addComparisonResult = function(comparisonResult) { + this.penaltyPoints += comparisonResult.penaltyPoints; + if (comparisonResult.additionalInfoInCurrentValue) { + this.additionalInfoInCurrentValue = comparisonResult.additionalInfoInCurrentValue; + } +}; + +/** + * Returns true if no penalty points have been assigned for the comparison. + * + * @return boolean true if the comparison was successful. + */ +ComparisonResult.prototype.isSuccessful = function() { + return nullOrUndefined(this.penaltyPoints) || this.penaltyPoints === 0; +}; + +/** + * Compares two simple objects (String|Number) and if they are equal then returns a ComparisonResult with zero + * penalty points assigned, otherwise returns a ComparisonResult with the given number of penalty points assigned. + * + * @param currentValue (String|Number) The current value. + * @param storedValue (String|Number) The stored value. + * @param config: { + * "penaltyPoints": (Number) The number of penalty points. + * } + * @return ComparisonResult. + */ +ScalarComparator.compare = function (currentValue, storedValue, config) { + if (logger.messageEnabled()) { + logger.message("StringComparator.compare:currentValue: " + JSON.stringify(currentValue)); + logger.message("StringComparator.compare:storedValue: " + JSON.stringify(storedValue)); + logger.message("StringComparator.compare:config: " + JSON.stringify(config)); + } + if (config.penaltyPoints === 0) { + return ComparisonResult.ZERO_PENALTY_POINTS; + } + + if (!nullOrUndefined(storedValue)) { + if (nullOrUndefined(currentValue) || currentValue !== storedValue) { + return new ComparisonResult(config.penaltyPoints); + } + } else if (!nullOrUndefined(currentValue)) { + return new ComparisonResult(true); + } + + return ComparisonResult.ZERO_PENALTY_POINTS; +}; + +/** + * Compares two screens and if they are equal then returns a ComparisonResult with zero penalty points assigned, + * otherwise returns a ComparisonResult with the given number of penalty points assigned. + * + * @param currentValue: { + * "screenWidth": (Number) The current client screen width. + * "screenHeight": (Number) The current client screen height. + * "screenColourDepth": (Number) The current client screen colour depth. + * } + * @param storedValue: { + * "screenWidth": (Number) The stored client screen width. + * "screenHeight": (Number) The stored client screen height. + * "screenColourDepth": (Number) The stored client screen colour depth. + * } + * @param config: { + * "penaltyPoints": (Number) The number of penalty points. + * } + * @return ComparisonResult + */ +ScreenComparator.compare = function (currentValue, storedValue, config) { + if (logger.messageEnabled()) { + logger.message("ScreenComparator.compare:currentValue: " + JSON.stringify(currentValue)); + logger.message("ScreenComparator.compare:storedValue: " + JSON.stringify(storedValue)); + logger.message("ScreenComparator.compare:config: " + JSON.stringify(config)); + } + + if (nullOrUndefined(currentValue)) { + currentValue = {screenWidth: null, screenHeight: null, screenColourDepth: null}; + } + if (nullOrUndefined(storedValue)) { + storedValue = {screenWidth: null, screenHeight: null, screenColourDepth: null}; + } + + var comparisonResults = [ + ScalarComparator.compare(currentValue.screenWidth, storedValue.screenWidth, config), + ScalarComparator.compare(currentValue.screenHeight, storedValue.screenHeight, config), + ScalarComparator.compare(currentValue.screenColourDepth, storedValue.screenColourDepth, config)]; + + if (all(comparisonResults, ComparisonResult.isSuccessful)) { + return new ComparisonResult(any(comparisonResults, ComparisonResult.additionalInfoInCurrentValue)); + } else { + return new ComparisonResult(config.penaltyPoints); + } +}; + +/** + * Splits both values using delimiter, trims every value and compares collections of values. + * Returns zero-result for same multi-value attributes. + * + * If collections are not same checks if number of differences is less or equal maxDifferences or + * percentage of difference is less or equal maxPercentageDifference. + * + * If yes then returns zero-result with additional info, else returns penaltyPoints-result. + * + * @param currentValue: (String) The current value. + * @param storedValue: (String) The stored value. + * @param config: { + * "maxPercentageDifference": (Number) The max difference percentage in the values, + * before the penalty is assigned. + * "maxDifferences": (Number) The max number of differences in the values, + * before the penalty points are assigned. + * "penaltyPoints": (Number) The number of penalty points. + * } + * @return ComparisonResult + */ +MultiValueComparator.compare = function (currentValue, storedValue, config) { + if (logger.messageEnabled()) { + logger.message("MultiValueComparator.compare:currentValue: " + JSON.stringify(currentValue)); + logger.message("MultiValueComparator.compare:storedValue: " + JSON.stringify(storedValue)); + logger.message("MultiValueComparator.compare:config: " + JSON.stringify(config)); + } + + var delimiter = ";", + currentValues = splitAndTrim(currentValue, delimiter), + storedValues = splitAndTrim(storedValue, delimiter), + maxNumberOfElements = Math.max(currentValues.length, storedValues.length), + numberOfTheSameElements = calculateIntersection(currentValues, storedValues).length, + numberOfDifferences = maxNumberOfElements - numberOfTheSameElements, + percentageOfDifferences = calculatePercentage(numberOfDifferences, maxNumberOfElements); + + if (nullOrUndefined(storedValue) && !nullOrUndefined(currentValue)) { + return new ComparisonResult(true); + } + + if (logger.messageEnabled()) { + logger.message(numberOfTheSameElements + " of " + maxNumberOfElements + " are same"); + } + + if (maxNumberOfElements === 0) { + logger.message("Ignored because no attributes found in both profiles"); + return ComparisonResult.ZERO_PENALTY_POINTS; + } + + if (numberOfTheSameElements === maxNumberOfElements) { + logger.message("Ignored because all attributes are same"); + return ComparisonResult.ZERO_PENALTY_POINTS; + } + + if (numberOfDifferences > config.maxDifferences) { + if (logger.messageEnabled()) { + logger.message("Would be ignored if not more than " + config.maxDifferences + " differences"); + } + return new ComparisonResult(config.penaltyPoints); + } + + if (percentageOfDifferences > config.maxPercentageDifference) { + if (logger.messageEnabled()) { + logger.message(percentageOfDifferences + " percents are different"); + logger.message("Would be ignored if not more than " + config.maxPercentageDifference + " percent"); + } + return new ComparisonResult(config.penaltyPoints); + } + + if (logger.messageEnabled()) { + logger.message("Ignored because number of differences(" + numberOfDifferences + ") not more than " + + config.maxDifferences); + logger.message(percentageOfDifferences + " percents are different"); + logger.message("Ignored because not more than " + config.maxPercentageDifference + " percent"); + } + return new ComparisonResult(true); +}; + +/** + * Compares two User Agent Strings and if they are equal then returns a ComparisonResult with zero penalty + * points assigned, otherwise returns a ComparisonResult with the given number of penalty points assigned. + * + * @param currentValue (String) The current value. + * @param storedValue (String) The stored value. + * @param config: { + * "ignoreVersion": (boolean) If the version numbers in the User Agent Strings should be ignore + * in the comparison. + * "penaltyPoints": (Number) The number of penalty points. + * } + * @return A ComparisonResult. + */ +UserAgentComparator.compare = function (currentValue, storedValue, config) { + if (logger.messageEnabled()) { + logger.message("UserAgentComparator.compare:currentValue: " + JSON.stringify(currentValue)); + logger.message("UserAgentComparator.compare:storedValue: " + JSON.stringify(storedValue)); + logger.message("UserAgentComparator.compare:config: " + JSON.stringify(config)); + } + + if (config.ignoreVersion) { + // remove version number + currentValue = nullOrUndefined(currentValue) ? null : currentValue.replace(/[\d\.]+/g, "").trim(); + storedValue = nullOrUndefined(storedValue) ? null : storedValue.replace(/[\d\.]+/g, "").trim(); + } + + return ScalarComparator.compare(currentValue, storedValue, config); +}; + +/** + * Compares two locations, taking into account a degree of difference. + * + * @param currentValue: { + * "latitude": (Number) The current latitude. + * "longitude": (Number) The current longitude. + * } + * @param storedValue: { + * "latitude": (Number) The stored latitude. + * "longitude": (Number) The stored longitude. + * } + * @param config: { + * "allowedRange": (Number) The max difference allowed in the two locations, before the penalty is assigned. + * "penaltyPoints": (Number) The number of penalty points. +* } + * @return ComparisonResult + */ +GeolocationComparator.compare = function (currentValue, storedValue, config) { + if (logger.messageEnabled()) { + logger.message("GeolocationComparator.compare:currentValue: " + JSON.stringify(currentValue)); + logger.message("GeolocationComparator.compare:storedValue: " + JSON.stringify(storedValue)); + logger.message("GeolocationComparator.compare:config: " + JSON.stringify(config)); + } + + // Check for undefined stored or current locations + + if (undefinedLocation(currentValue) && undefinedLocation(storedValue)) { + return ComparisonResult.ZERO_PENALTY_POINTS; + } + if (undefinedLocation(currentValue) && !undefinedLocation(storedValue)) { + return new ComparisonResult(config.penaltyPoints); + } + if (!undefinedLocation(currentValue) && undefinedLocation(storedValue)) { + return new ComparisonResult(true); + } + + // Both locations defined, therefore perform comparison + + var distance = calculateDistance(currentValue, storedValue); + + if (logger.messageEnabled()) { + logger.message("Distance between (" + currentValue.latitude + "," + currentValue.longitude + ") and (" + + storedValue.latitude + "," + storedValue.longitude + ") is " + distance + " miles"); + } + + if (parseFloat(distance.toPrecision(5)) === 0) { + logger.message("Location is the same"); + return ComparisonResult.ZERO_PENALTY_POINTS; + } + + if (distance <= config.allowedRange) { + if (logger.messageEnabled()) { + logger.message("Tolerated because distance not more then " + config.allowedRange); + } + return new ComparisonResult(true); + } else { + if (logger.messageEnabled()) { + logger.message("Would be ignored if distance not more then " + config.allowedRange); + } + return new ComparisonResult(config.penaltyPoints); + } +}; + + +//---------------------------------------------------------------------------// +// Device Print Logic - DO NOT MODIFY // +//---------------------------------------------------------------------------// + +// Utility functions + +/** + * Returns true if evaluating function f on each element of the Array a returns true. + * + * @param a: (Array) The array of elements to evaluate + * @param f: (Function) A single argument function for mapping elements of the array to boolean. + * @return boolean. + */ +all = function(a, f) { + var i; + for (i = 0; i < a.length; i++) { + if (f(a[i]) === false) { + return false; + } + } + return true; +}; + +/** + * Returns true if evaluating function f on any element of the Array a returns true. + * + * @param a: (Array) The array of elements to evaluate + * @param f: (Function) A single argument function for mapping elements of the array to boolean. + * @return boolean. + */ +any = function(a, f) { + var i; + for (i = 0; i < a.length; i++) { + if (f(a[i]) === true) { + return true; + } + } + return false; +}; + +/** + * Returns true if the provided location is null or has undefined longitude or latitude values. + * + * @param location: { + * "latitude": (Number) The latitude. + * "longitude": (Number) The longitude. + * } + * @return boolean + */ +undefinedLocation = function(location) { + return nullOrUndefined(location) || nullOrUndefined(location.latitude) || nullOrUndefined(location.longitude); +}; + +/** + * Returns true if the provided value is null or undefined. + * + * @param value: a value of any type + * @return boolean + */ +nullOrUndefined = function(value) { + return value === null || value === undefined; +}; + +/** + * Calculates the distances between the two locations. + * + * @param first: { + * "latitude": (Number) The first latitude. + * "longitude": (Number) The first longitude. + * } + * @param second: { + * "latitude": (Number) The second latitude. + * "longitude": (Number) The second longitude. + * } + * @return Number The distance between the two locations. + */ +calculateDistance = function(first, second) { + var factor = (Math.PI / 180), + theta, + dist; + function degreesToRadians(degrees) { + return degrees * factor; + } + function radiansToDegrees(radians) { + return radians / factor; + } + theta = first.longitude - second.longitude; + dist = Math.sin(degreesToRadians(first.latitude)) * Math.sin(degreesToRadians(second.latitude)) + + Math.cos(degreesToRadians(first.latitude)) * Math.cos(degreesToRadians(second.latitude)) + * Math.cos(degreesToRadians(theta)); + dist = Math.acos(dist); + dist = radiansToDegrees(dist); + dist = dist * 60 * 1.1515; + return dist; +}; + +/** + * Converts a String holding a delimited sequence of values into an array. + * + * @param text (String) The String representation of a delimited sequence of values. + * @param delimiter (String) The character delimiting values within the text String. + * @return (Array) The comma separated values. + */ +splitAndTrim = function(text, delimiter) { + + var results = [], + i, + values, + value; + if (text === null) { + return results; + } + + values = text.split(delimiter); + for (i = 0; i < values.length; i++) { + value = values[i].trim(); + if (value !== "") { + results.push(value); + } + } + + return results; +}; + +/** + * Converts value to a percentage of range. + * + * @param value (Number) The actual number to be converted to a percentage. + * @param range (Number) The total number of values (i.e. represents 100%). + * @return (Number) The percentage. + */ +calculatePercentage = function(value, range) { + if (range === 0) { + return 0; + } + return parseFloat((value / range).toPrecision(2)) * 100; +}; + +/** + * Creates a new array containing only those elements found in both arrays received as arguments. + * + * @param first (Array) The first array. + * @param second (Array) The second array. + * @return (Array) The elements that found in first and second. + */ +calculateIntersection = function(first, second) { + return first.filter(function(element) { + return second.indexOf(element) !== -1; + }); +}; + +function getValue(obj, attributePath) { + var value = obj, + i; + for (i = 0; i < attributePath.length; i++) { + if (value === undefined) { + return null; + } + value = value[attributePath[i]]; + } + return value; +} + + +function isLeafNode(attributeConfig) { + return attributeConfig.comparator !== undefined; +} + +function getAttributePaths(attributeConfig, attributePath) { + + var attributePaths = [], + attributeName, + attrPaths, + attrPath, + i; + + for (attributeName in attributeConfig) { + if (attributeConfig.hasOwnProperty(attributeName)) { + + if (isLeafNode(attributeConfig[attributeName])) { + attrPath = attributePath.slice(); + attrPath.push(attributeName); + attributePaths.push(attrPath); + } else { + attrPath = attributePath.slice(); + attrPath.push(attributeName); + attrPaths = getAttributePaths(attributeConfig[attributeName], attrPath); + for (i = 0; i < attrPaths.length; i++) { + attributePaths.push(attrPaths[i]); + } + } + } + } + + return attributePaths; +} + +function getDevicePrintAttributePaths(attributeConfig) { + return getAttributePaths(attributeConfig, []); +} + +function hasRequiredAttributes(devicePrint, attributeConfig) { + + var attributePaths = getDevicePrintAttributePaths(attributeConfig), + i, + attrValue, + attrConfig; + + for (i = 0; i < attributePaths.length; i++) { + + attrValue = getValue(devicePrint, attributePaths[i]); + attrConfig = getValue(attributeConfig, attributePaths[i]); + + if (attrConfig.required && attrValue === undefined) { + logger.warning("Device Print profile missing required attribute, " + attributePaths[i]); + return false; + } + } + + logger.message("device print has required attributes"); + return true; +} + +function compareDevicePrintProfiles(attributeConfig, devicePrint, devicePrintProfiles, maxPenaltyPoints) { + + var attributePaths = getDevicePrintAttributePaths(attributeConfig), + dao = sharedState.get('_DeviceIdDao'), + results, + j, + aggregatedComparisonResult, + i, + currentValue, + storedValue, + attrConfig, + comparisonResult, + selectedComparisonResult, + selectedProfile, + curDevicePrintProfile, + vals; + + results = []; + for (j = 0; j < devicePrintProfiles.length; j++) { + curDevicePrintProfile = JSON.parse(org.forgerock.json.JsonValue.json(devicePrintProfiles[j])); + aggregatedComparisonResult = new ComparisonResult(); + for (i = 0; i < attributePaths.length; i++) { + + currentValue = getValue(devicePrint, attributePaths[i]); + storedValue = getValue(curDevicePrintProfile.devicePrint, attributePaths[i]); + attrConfig = getValue(attributeConfig, attributePaths[i]); + + if (storedValue === null) { + comparisonResult = new ComparisonResult(attrConfig.penaltyPoints); + } else { + comparisonResult = attrConfig.comparator.compare(currentValue, storedValue, attrConfig.args); + } + + if (logger.messageEnabled()) { + logger.message("Comparing attribute path: " + attributePaths[i] + + ", Comparison result: successful=" + comparisonResult.isSuccessful() + ", penaltyPoints=" + + comparisonResult.penaltyPoints + ", additionalInfoInCurrentValue=" + + comparisonResult.additionalInfoInCurrentValue); + } + aggregatedComparisonResult.addComparisonResult(comparisonResult); + } + if (logger.messageEnabled()) { + logger.message("Aggregated comparison result: successful=" + + aggregatedComparisonResult.isSuccessful() + ", penaltyPoints=" + + aggregatedComparisonResult.penaltyPoints + ", additionalInfoInCurrentValue=" + + aggregatedComparisonResult.additionalInfoInCurrentValue); + } + + results.push({ + key: aggregatedComparisonResult, + value: devicePrintProfiles[j] + }); + } + + if (results.length === 0) { + return null; + } + + results.sort(function(a, b) { + return ComparisonResult.compare(a.key, b.key); + }); + selectedComparisonResult = results[0].key; + if (logger.messageEnabled()) { + logger.message("Selected comparison result: successful=" + selectedComparisonResult.isSuccessful() + + ", penaltyPoints=" + selectedComparisonResult.penaltyPoints + ", additionalInfoInCurrentValue=" + + selectedComparisonResult.additionalInfoInCurrentValue); + } + + selectedProfile = null; + if (selectedComparisonResult.penaltyPoints <= maxPenaltyPoints) { + selectedProfile = results[0].value; + if (logger.messageEnabled()) { + logger.message("Selected profile: " + selectedProfile + + " with " + selectedComparisonResult.penaltyPoints + " penalty points"); + } + } + + if (selectedProfile === null) { + return false; + } + + /* update profile */ + selectedProfile.put("selectionCounter", + java.lang.Integer.valueOf(parseInt(selectedProfile.get("selectionCounter"), 10) + 1)); + selectedProfile.put("lastSelectedDate", java.lang.Long.valueOf(new Date().getTime())); + selectedProfile.put("devicePrint", devicePrint); + + vals = []; + for (i = 0; i < devicePrintProfiles.length; i++) { + vals.push(org.forgerock.json.JsonValue.json(devicePrintProfiles[i])); + } + + dao.saveDeviceProfiles(username, realm, vals); + + return true; +} + +function matchDevicePrint() { + + if (!username) { + logger.error("Username not set. Cannot compare user's device print profiles."); + authState = FAILED; + } else { + + if (logger.messageEnabled()) { + logger.message("client devicePrint: " + clientScriptOutputData); + } + + var getProfiles = function () { + + function isExpiredProfile(devicePrintProfile) { + var expirationDate = new Date(), + lastSelectedDate; + expirationDate.setDate(expirationDate.getDate() - config.profileExpiration); + + lastSelectedDate = new Date(devicePrintProfile.lastSelectedDate); + + return lastSelectedDate < expirationDate; + } + + function getNotExpiredProfiles() { + var profile, + dao = sharedState.get('_DeviceIdDao'), + results = [], + profiles, + iter; + + profiles = dao.getDeviceProfiles(username, realm); + + if (profiles) { + iter = profiles.iterator(); + + while (iter.hasNext()) { + profile = iter.next().getObject(); + if (!isExpiredProfile(profile)) { + results.push(profile); + } + } + } + if (logger.messageEnabled()) { + logger.message("stored non-expired profiles: " + results); + } + return results; + } + + return getNotExpiredProfiles(); + }, + devicePrint = JSON.parse(clientScriptOutputData), + devicePrintProfiles = getProfiles(); + + if (!hasRequiredAttributes(devicePrint, config.attributes)) { + logger.message("devicePrint.hasRequiredAttributes: false"); + // Will fail this module but fall-through to next module. Which should be OTP. + authState = FAILED; + } else if (compareDevicePrintProfiles(config.attributes, devicePrint, devicePrintProfiles, config.maxPenaltyPoints)) { + logger.message("devicePrint.hasValidProfile: true"); + authState = SUCCESS; + } else { + logger.message("devicePrint.hasValidProfile: false"); + sharedState.put('devicePrintProfile', JSON.stringify(devicePrint)); + // Will fail this module but fall-through to next module. Which should be OTP. + authState = FAILED; + } + } +} + +matchDevicePrint(); diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_SERVER_SIDE/Scripted Module - Server Side.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_SERVER_SIDE/Scripted Module - Server Side.js new file mode 100644 index 000000000..1e84da418 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_SERVER_SIDE/Scripted Module - Server Side.js @@ -0,0 +1,86 @@ +/* + * Copyright 2015-2025 Ping Identity Corporation. All Rights Reserved + * + * This code is to be used exclusively in connection with Ping Identity + * Corporation software or services. Ping Identity Corporation only offers + * such software or services to legal entities who have entered into a + * binding license agreement with Ping Identity Corporation. + */ + +var START_TIME = 9; // 9am +var END_TIME = 17; // 5pm +var longitude, latitude; +var localTime; + +logger.message("Starting scripted authentication"); +logger.message("User: " + username); + +var userPostalAddress = getUserPostalAddress(); +logger.message("User address: " + userPostalAddress); + +getLongitudeLatitudeFromUserPostalAddress(); +getLocalTime(); + +logger.message("Current time at the users location: " + localTime.getHours()); +if (localTime.getHours() < START_TIME || localTime.getHours() > END_TIME) { + logger.error("Login forbidden outside work hours!"); + authState = FAILED; +} else { + logger.message("Authentication allowed!"); + authState = SUCCESS; +} + +function getLongitudeLatitudeFromUserPostalAddress() { + + var request = new org.forgerock.http.protocol.Request(); + request.setUri("http://maps.googleapis.com/maps/api/geocode/json?address=" + encodeURIComponent(userPostalAddress)); + request.setMethod("GET"); + //the above URI has to be extended with an API_KEY if used in a frequent manner + //see documentation: https://developers.google.com/maps/documentation/geocoding/intro + + var response = httpClient.send(request).get(); + logResponse(response); + + var geocode = JSON.parse(response.getEntity()); + var i; + for (i = 0; i < geocode.results.length; i++) { + var result = geocode.results[i]; + latitude = result.geometry.location.lat; + longitude = result.geometry.location.lng; + + logger.message("latitude:" + latitude + " longitude:" + longitude); + } +} + +function getLocalTime() { + + var now = new Date().getTime() / 1000; + var location = "location=" + latitude + "," + longitude; + var timestamp = "timestamp=" + now; + + var request = new org.forgerock.http.protocol.Request(); + request.setUri("https://maps.googleapis.com/maps/api/timezone/json?" + location + "&" + timestamp); + request.setMethod("GET"); + //the above URI has to be extended with an API_KEY if used in a frequent manner + //see documentation: https://developers.google.com/maps/documentation/timezone/intro + + var response = httpClient.send(request).get(); + logResponse(response); + + var timezone = JSON.parse(response.getEntity()); + var localTimestamp = parseInt(now) + parseInt(timezone.dstOffset) + parseInt(timezone.rawOffset); + localTime = new Date(localTimestamp*1000); +} + +function getUserPostalAddress() { + var userAddressSet = idRepository.getAttribute(username, "postalAddress"); + if (userAddressSet == null || userAddressSet.isEmpty()) { + logger.warning("No address specified for user: " + username); + return false; + } + return userAddressSet.iterator().next() +} + +function logResponse(response) { + logger.message("User REST Call. Status: " + response.getStatus() + ", Body: " + response.getEntity()); +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_TREE_DECISION_NODE/Authentication Tree Decision Node Script.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_TREE_DECISION_NODE/Authentication Tree Decision Node Script.js new file mode 100644 index 000000000..d78155005 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_TREE_DECISION_NODE/Authentication Tree Decision Node Script.js @@ -0,0 +1,6 @@ +/* + - Data made available by nodes that have already executed are available in the sharedState variable. + - The script should set outcome to either "true" or "false". + */ + +outcome = "true"; diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_TREE_DECISION_NODE/Device Profile Match Template - Decision Node Script.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_TREE_DECISION_NODE/Device Profile Match Template - Decision Node Script.js new file mode 100644 index 000000000..45eb79b6e --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/AUTHENTICATION_TREE_DECISION_NODE/Device Profile Match Template - Decision Node Script.js @@ -0,0 +1,82 @@ +/* + * Copyright 2020-2025 Ping Identity Corporation. All Rights Reserved + * + * This code is to be used exclusively in connection with Ping Identity + * Corporation software or services. Ping Identity Corporation only offers + * such software or services to legal entities who have entered into a + * binding license agreement with Ping Identity Corporation. + */ + +/** ****************************************************************** + * + * The following script is a simplified template for understanding + * the basics of device matching. _This is not functionally complete._ + * For a functionally complete script as well as a development toolkit, + * visit https://github.com/ForgeRock/forgerock-device-match-script. + * + * Global node variables accessible within this scope: + * 1. `sharedState` provides access to incoming request + * 2. `deviceProfilesDao` provides access to stored profiles + * 3. `outcome` variable maps to auth tree node outcomes; values are + * 'true', 'false', or 'unknownDevice' (notice _all_ are strings). + * ******************************************************************/ + +/** + * Get the incoming request's device profile. + * Returns serialized JSON (type string); parsing this will result a + * native JS object. + */ +var incomingJson = sharedState.get('forgeRock.device.profile').toString(); +var incoming = JSON.parse(incomingJson); + +/** + * Get the incoming user's username and realm. + * Notice the use of `.asString()`. + */ +var username = sharedState.get("username").asString(); +var realm = sharedState.get("realm").asString(); + +/** + * Get the user's stored profiles for appropriate realm. + * Returns a _special_ object with methods for profile data + */ +var storedProfiles = deviceProfilesDao.getDeviceProfiles(username, realm); + +// Default to `outcome` of 'unknownDevice' +outcome = 'unknownDevice'; + +if (storedProfiles) { + var i = 0; + // NOTE: `.size()` method returns the number of stored profiles + var len = storedProfiles.size(); + + for (i; i < len; i++) { + /** + * Get the stored profile. + * Returns serialized JSON (type string); parsing this will result + * a native JS object. + */ + var storedJson = storedProfiles.get(i); + var stored = JSON.parse(storedJson); + + /** + * Find a stored profile with the same identifier. + */ + if (incoming.identifier === stored.identifier) { + + /** + * Now that you've found the appropriate profile, you will perform + * the logic here to match the values of the `incoming` profile + * with that of the `stored` profile. + * + * The result of the matching logic is assigned to `outcome`. Since + * we have profiles of the same identifier, the value (type string) + * should now be either 'true' or 'false' (properties matched or not). + * + * For more information about this topic, visit this Github repo: + * https://github.com/ForgeRock/forgerock-device-match-script + */ + outcome = 'false'; + } + } +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/CONFIG_PROVIDER_NODE/Config Provider.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/CONFIG_PROVIDER_NODE/Config Provider.js new file mode 100644 index 000000000..5440dae17 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/CONFIG_PROVIDER_NODE/Config Provider.js @@ -0,0 +1,65 @@ +/* + * Copyright 2021 ForgeRock AS. All Rights Reserved + * Use of this code requires a commercial software license with ForgeRock AS. + * or with one of its affiliates. All use shall be exclusively subject + * to such license between the licensee and ForgeRock AS. + */ + +/** + * The following script is a simplified template for understanding how to build + * up a config Map object with custom values. The Config Provider Node will then + * provide this config Map to the desired node type. It is important that the Map + * you build here is named 'config'. + * + * Defined variables: + * + * nodeState - Node State (1) + * Always present, this represents the current values stored in the node state. + * + * idRepository - Profile Data (2) + * Always present, a repository to retrieve user information. + * + * secrets - Credentials and Secrets (3) + * Always present, an interface to access the Secrets API from a scripting context. + * + * requestHeaders (4) - Map (5) + * Always present, an object that provides methods for accessing headers in the login request. + * + * logger - Debug Logging (6) + * Always present, the debug logger instance. + * + * httpClient - HTTP Client (7) + * Always present, the HTTP client that can be used to make external HTTP requests. + * + * realm - String (primitive). + * Always present, the name of the realm the user is authenticating to. + * + * existingSession - Map (5) + * Present if the request contains the session cookie, the user's session object. The returned map from + * SSOToken.getProperties() (8) + * + * requestParameters - Map (5) + * Always present, the object that contains the authentication request parameters. + * + * + * Outputs: + * + * config - Map (5) + * Define and fill a Map object named 'config' with custom values, this will define the configuration for the + * associated node selected in the ConfigProviderNode. + * + * Reference: + * (1) Node State - https://backstage.forgerock.com/docs/idcloud-am/latest/authentication-guide/scripting-api-node.html#scripting-api-node-nodeState + * (2) Profile Data - https://backstage.forgerock.com/docs/am/7.1/authentication-guide/scripting-api-node.html#scripting-api-node-id-repo + * (3) Credentials and Secrets - https://backstage.forgerock.com/docs/am/7.1/authentication-guide/scripting-api-node.html#scripting-api-authn-secrets + * (4) Request Headers - https://backstage.forgerock.com/docs/am/7/authentication-guide/scripting-api-node.html#scripting-api-node-requestHeaders. + * (5) Map - https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Map.html + * (6) Debug Logging - https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-logger.html#scripting-api-global-logger. + * (7) HTTP Client - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/http/Client.html. + * (8) SSOToken - https://backstage.forgerock.com/docs/am/7/apidocs/com/iplanet/sso/SSOToken.html. + */ + +config = { + "key0": {"subKey": "value0"}, + "key1": "value1" +}; diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/DEVICE_MATCH_NODE/Next Generation Device Match Node Script.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/DEVICE_MATCH_NODE/Next Generation Device Match Node Script.js new file mode 100644 index 000000000..bc57aca00 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/DEVICE_MATCH_NODE/Next Generation Device Match Node Script.js @@ -0,0 +1,14 @@ +/* + * Copyright 2024-2025 Ping Identity Corporation. All Rights Reserved + * + * This code is to be used exclusively in connection with Ping Identity + * Corporation software or services. Ping Identity Corporation only offers + * such software or services to legal entities who have entered into a + * binding license agreement with Ping Identity Corporation. + */ +/* + - Data made available by nodes that have already executed is available in the nodeState variable. + - Use the action object to set the outcome of the node. + */ + +action.goTo("true"); diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/LIBRARY/Library Script.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/LIBRARY/Library Script.js new file mode 100644 index 000000000..a02033efe --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/LIBRARY/Library Script.js @@ -0,0 +1,33 @@ +/* + * Copyright 2022-2023 ForgeRock AS. All Rights Reserved + * + * Use of this code requires a commercial software license with ForgeRock AS. + * or with one of its affiliates. All use shall be exclusively subject + * to such license between the licensee and ForgeRock AS. + */ + +/* + * This is an example library script with methods that can be used in other scripts. + * To reference it, use the following: + * + * var library = require("Library Script"); + * + * library.logError(logger, "Error message"); + * library.logDebug(logger, "Debug message"); + */ + +function logError(log, errorMessage) { + log.error(errorMessage); +} + +function logWarning(log, warningMessage) { + log.warn(warningMessage); +} + +exports.logError = logError; +exports.logWarning = logWarning; + +// Alternatively, exports can be declared using an inline arrow function + +exports.logInfo = (log, infoMessage) => log.info(infoMessage); +exports.logDebug = (log, debugMessage) => log.debug(debugMessage); diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_ACCESS_TOKEN_MODIFICATION/OAuth2 Access Token Modification Script.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_ACCESS_TOKEN_MODIFICATION/OAuth2 Access Token Modification Script.js new file mode 100644 index 000000000..a89688384 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_ACCESS_TOKEN_MODIFICATION/OAuth2 Access Token Modification Script.js @@ -0,0 +1,136 @@ +/* + * Copyright 2019-2025 Ping Identity Corporation. All Rights Reserved. + * + * This code is to be used exclusively in connection with Ping Identity + * Corporation software or services. Ping Identity Corporation only offers + * such software or services to legal entities who have entered into a + * binding license agreement with Ping Identity Corporation. + */ + +/* + * This script lets you modify information associated with an OAuth2 access token + * with methods provided by the AccessToken (1) interface. + * The changes made to OAuth2 access tokens will directly impact the size of the CTS tokens, + * and, similarly, the size of the JWTs if client-based OAuth2 tokens are utilized. + * When adding/updating fields make sure that the token size remains within client/user-agent limits. + * + * Defined variables: + * accessToken - AccessToken (1). + * The access token to be updated. + * Mutable object, all changes to the access token will be reflected. + * scopes - Set (6). + * Always present, the requested scopes. + * requestProperties - Unmodifiable Map (5). + * Always present, contains a map of request properties: + * requestUri - The request URI. + * realm - The realm that the request relates to. + * requestParams - A map of the request params and/or posted data. + * Each value is a list of one or more properties. + * Please note that these should be handled in accordance with OWASP best practices: + * https://owasp.org/www-community/vulnerabilities/Unsafe_use_of_Reflection. + * clientProperties - Unmodifiable Map (5). + * Present if the client specified in the request was identified, contains a map of client properties: + * clientId - The client's URI for the request locale. + * allowedGrantTypes - List of the allowed grant types (org.forgerock.oauth2.core.GrantType) for the client. + * allowedResponseTypes - List of the allowed response types for the client. + * allowedScopes - List of the allowed scopes for the client. + * customProperties - A map of the custom properties of the client. + * Lists or maps will be included as sub-maps; for example: + * customMap[Key1]=Value1 will be returned as customMap -> Key1 -> Value1. + * To add custom properties to a client, update the Custom Properties field + * in AM Console > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Advanced. + * identity - AMIdentity (3). + * Always present, the identity of the resource owner. + * session - SSOToken (4). + * Present if the request contains the session cookie, the user's session object. + * scriptName - String (primitive). + * Always present, the display name of the script. + * logger - Always present, the "OAuth2Provider" debug logger instance: + * https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-logger.html#scripting-api-global-logger. + * Corresponding log files will be prefixed with: scripts.OAUTH2_ACCESS_TOKEN_MODIFICATION. + * httpClient - HTTP Client (8). + * Always present, the HTTP Client instance: + * https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-http-client.html#scripting-api-global-http-client. + * + * Return - no value is expected, changes shall be made to the accessToken parameter directly. + * + * Class reference: + * (1) AccessToken - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/oauth2/core/AccessToken.html. + * (3) AMIdentity - https://backstage.forgerock.com/docs/am/7/apidocs/com/sun/identity/idm/AMIdentity.html. + * (4) SSOToken - https://backstage.forgerock.com/docs/am/7/apidocs/com/iplanet/sso/SSOToken.html. + * (5) Map - https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashMap.html, + * or https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/LinkedHashMap.html. + * (6) Set - https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashSet.html. + * (8) Client - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/http/Client.html. + */ + +/* EXAMPLE +(function () { + var frJava = JavaImporter( + org.forgerock.http.protocol.Request, + org.forgerock.http.protocol.Response + ); + + // Always includes this field in the token. + accessToken.setField('key1', 'value1'); + + // Receives and adds to the access token additional values by performing a REST call to an external service. + // WARNING: Below, you will find a reference to a third-party site, which is provided only as an example. + var uri = 'https://jsonplaceholder.typicode.com/posts'; + + try { + var request = new frJava.Request(); + + // You can chain methods that return the request object. + request.setUri(uri) + .setMethod('POST') + .setEntity(JSON.stringify({ + updatedFields: { + key2: 'value2', + key3: 'value3' + } + })); + + // You can call a method when chaining is not possible. + request.getHeaders().add('Content-Type', 'application/json; charset=UTF-8'); + + // Sends the request and receives the response. + var response = httpClient.send(request).getOrThrow(); + + // Checks if the response status is as expected. + if (response.getStatus() === org.forgerock.http.protocol.Status.CREATED) { + var result = JSON.parse(response.getEntity().getString()); + + // Set multiple token fields at once. + accessToken.setFields(result.updatedFields); + } else { + logger.error('Unable to obtain access token modifications. Status: ' + response.getStatus() + '. Content: ' + response.getEntity().getString()); + } + } catch (e) { + logger.error('The request processing was interrupted. ' + e); + + // The access token request fails with the HTTP 500 error in this case. + throw ('Unable to obtain response from: ' + uri); + } + + // Adds new fields containing identity attribute values to the access token. + accessToken.setField('mail', identity.getAttribute('mail')); + accessToken.setField('phone', identity.getAttribute('telephoneNumber').toArray()[0]); + + // Adds new fields containing the session property values. + // NOTE: session may not be available for non-interactive authorization grants. + if (session) { + try { + accessToken.setField('ipAddress', session.getProperty('Host')); + } catch (e) { + logger.error('Unable to retrieve session property value. ' + e); + } + } + + // Removes a native field from the token entry, that was set by AM. + // WARNING: removing native fields from the token may result in loss of functionality. + // accessToken.removeTokenName() + + // No return value is expected. Let it be undefined. +}()); +*/ diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_AUTHORIZE_ENDPOINT_DATA_PROVIDER/OAuth2 Authorize Endpoint Data Provider Script.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_AUTHORIZE_ENDPOINT_DATA_PROVIDER/OAuth2 Authorize Endpoint Data Provider Script.js new file mode 100644 index 000000000..470be8c36 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_AUTHORIZE_ENDPOINT_DATA_PROVIDER/OAuth2 Authorize Endpoint Data Provider Script.js @@ -0,0 +1,90 @@ +/* + * Copyright 2021 ForgeRock AS. All Rights Reserved + * Use of this code requires a commercial software license with ForgeRock AS. + * or with one of its affiliates. All use shall be exclusively subject + * to such license between the licensee and ForgeRock AS. + */ + +/* + * This script lets you return additional data when authorize request is called. + * + * Defined variables: + * + * session - SSOToken (1) + * Present if the request contains the session cookie, the user's session object. + * + * httpClient - HTTP Client (2). + * Always present, the HTTP client that can be used to make external HTTP requests + * + * logger - Debug (3) + * Always present, the "ScriptedAuthorizeEndpointDataProvider" debug logger instance: + * https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-logger.html#scripting-api-global-logger. + * Corresponding log files will be prefixed with: scripts.OAUTH2_AUTHORIZE_ENDPOINT_DATA_PROVIDER. + * + * scriptName - String (primitive). + * Always present, the display name of the script + * + * Return - a Map of additional data (4). + * + * Class reference: + * (1) SSOToken - https://backstage.forgerock.com/docs/am/7/apidocs/com/iplanet/sso/SSOToken.html. + * (2) Client - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/http/Client.html. + * (3) Debug - https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-logger.html#scripting-api-global-logger. + * (4) Map - https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashMap.html. + */ + +/** + * Default authorize endpoint data provider script to use as a template for new scripts. + */ + +/* EXAMPLE +var map = new java.util.HashMap(); + +function addAdditionalData() { + + //If constant data needs to be returned + map.put("hello", "world"); + + //If some data needs to be returned from third party service + addAdditionalDataFromExternalService(); + + //If there is a need to return some user session data + addAdditionalDataFromSessionProperties() + + return map; +}; + +function addAdditionalDataFromExternalService() { + var frJava = JavaImporter( + org.forgerock.oauth2.core.exceptions.ServerException + ); + try { + //Obtain additional data by performing a REST call to an external service + var request = new org.forgerock.http.protocol.Request(); + request.setUri("https://third.party.app/hello.jsp"); + request.setMethod("POST"); + //request.setEntity("foo=bar&hello=world"); + request.setEntity(json(object( + field("foo", "bar")))); + var response = httpClient.send(request).getOrThrow(); + logResponse(response); + var result = JSON.parse(response.getEntity()); + map.put("someKey",result.get("someKey")); + } catch (err) { + throw new frJava.ServerException(err); + } +}; + +function addAdditionalDataFromSessionProperties() { + //Add additional data from session property values + if (session != null) { // session is not available for resource owner password credentials grant + map.put("ipAddress", session.getProperty("Host")) + } +}; + +function logResponse(response) { + logger.message("User REST Call. Status: " + response.getStatus() + ", Body: " + response.getEntity()); +}; + +addAdditionalData(); +*/ diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_DYNAMIC_CLIENT_REGISTRATION/OAuth2 Dynamic Client Registration Script.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_DYNAMIC_CLIENT_REGISTRATION/OAuth2 Dynamic Client Registration Script.js new file mode 100644 index 000000000..de215145f --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_DYNAMIC_CLIENT_REGISTRATION/OAuth2 Dynamic Client Registration Script.js @@ -0,0 +1,71 @@ +/* + * Copyright 2025 Ping Identity Corporation. All Rights Reserved + * + * This code is to be used exclusively in connection with Ping Identity + * Corporation software or services. Ping Identity Corporation only offers + * such software or services to legal entities who have entered into a + * binding license agreement with Ping Identity Corporation. + */ + +/* + * This script is run after the following Dynamic Client Registration operations: CREATE, UPDATE, DELETE. + * + * Defined variables: + * Common script bindings for next-generation scripts (1) + * requestProperties - An unmodifiable map of the following request properties: + * requestUri - The request URI. + * realm - The realm that the request relates to. + * requestParams - A map of the request params and/or posted data. + * Each value is a list of one or more properties. + * Please note that these should be handled in accordance with OWASP best practices: + * https://owasp.org/www-community/vulnerabilities/Unsafe_use_of_Reflection. + * requestHeaders - A map of the request headers. + * Case-sensitive. + * requestBody - A map representing the body of the request. + * operation - A string to denote the dynamic client registration request operation. + * Possible values: CREATE, UPDATE, DELETE + * clientIdentity - The AMIdentity that represents the created or updated OAuth2Client. + * Null if the operation is DELETE. + * softwareStatement - A map representing the decoded data of the software statement from the request. + * Empty map if no software statement is provided. + * + * Return - no value is expected, any changes shall be made via the bindings directly. + * + * Reference: + * (1) Script Bindings - https://docs.pingidentity.com/pingoneaic/latest/am-scripting/script-bindings.html + */ + +// logger.info("Executing: {}", scriptName); + +/* +// Example: Update the OAuth2Client identity on CREATE +// NOTE: setAttribute() overwrites the whole attribute if it exists already +if (operation === "CREATE") { + // Read a property from the request body + var requestBody = requestProperties.get("requestBody"); + var grantType = requestBody.get("grant_type"); + + if (grantType != null) { + var grantTypes = ["[0]=authorization_code"]; + grantTypes.push("[1]=".concat(grantType)); + clientIdentity.setAttribute( "com.forgerock.openam.oauth2provider.grantTypes", grantTypes); + clientIdentity.store(); + }; +}; + +// Example: Update the OAuth2Client identity on UPDATE +// NOTE: addAttribute() adds the provided value to the set if it exists already. +// Otherwise, it sets the attribute with the single value. +if (operation === "UPDATE") { + // Example: Read a property from the software statement + var redirectUris = softwareStatement.get("redirect_uris"); + if (redirectUris != null) { + var firstUri = redirectUris[0]; + }; + + if (firstUri != null) { + clientIdentity.addAttribute("com.forgerock.openam.oauth2provider.redirectionURIs", "[0]=".concat(firstUri)); + clientIdentity.store(); + }; +}; +*/ diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_EVALUATE_SCOPE/OAuth2 Evaluate Scope Script.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_EVALUATE_SCOPE/OAuth2 Evaluate Scope Script.js new file mode 100644 index 000000000..604267728 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_EVALUATE_SCOPE/OAuth2 Evaluate Scope Script.js @@ -0,0 +1,52 @@ +/* + * Copyright 2021 ForgeRock AS. All Rights Reserved + * Use of this code requires a commercial software license with ForgeRock AS. + * or with one of its affiliates. All use shall be exclusively subject + * to such license between the licensee and ForgeRock AS. + */ + +/* + * This script lets you populate the scopes with profile attribute values when the tokeninfo endpoint is called. + * For example, if one of the scopes is mail, AM sets mail to the resource owner's email address in the token information returned. + * + * Defined variables: + * accessToken - AccessToken (1). + * The access token to be updated. + * Mutable object, all changes to the access token will be reflected. + * identity - AMIdentity (2). + * The client's identity if present or the resource owner's identity. Can be null. + * scriptName - String (primitive). + * Always present, the display name of the script. + * logger - Always present, the "OAuth2Provider" debug logger instance: + * https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-logger.html#scripting-api-global-logger. + * Corresponding log files will be prefixed with: scripts.OAUTH2_ACCESS_TOKEN_MODIFICATION. + * httpClient - HTTP Client (3). + * Always present, the HTTP Client instance: + * https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-http-client.html#scripting-api-global-http-client. + * + * Return - a Map of the access token's information (4). + * + * Class reference: + * (1) AccessToken - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/oauth2/core/AccessToken.html. + * (2) AMIdentity - https://backstage.forgerock.com/docs/am/7/apidocs/com/sun/identity/idm/AMIdentity.html. + * (3) Client - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/http/Client.html. + * (4) Map - https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashMap.html. + */ + +/** + * Default evaluate scope script to use as a template for new scripts. + */ + +(function () { + var map = new java.util.HashMap(); + if (identity !== null) { + var scopes = accessToken.getScope().toArray(); + scopes.forEach(function (scope) { + var attributes = identity.getAttribute(scope).toArray(); + map.put(scope, attributes.join(",")); + }); + } else { + logger.error('identity is null'); + } + return map; +}()); diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_MAY_ACT/OAuth2 May Act Script.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_MAY_ACT/OAuth2 May Act Script.js new file mode 100644 index 000000000..efb3fdd86 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_MAY_ACT/OAuth2 May Act Script.js @@ -0,0 +1,76 @@ +/* + * Copyright 2021-2025 Ping Identity Corporation. All Rights Reserved + * + * This code is to be used exclusively in connection with Ping Identity + * Corporation software or services. Ping Identity Corporation only offers + * such software or services to legal entities who have entered into a + * binding license agreement with Ping Identity Corporation. + */ + +/* + * This script lets you add may_act field + * to an OAuth2 access token + * or OIDC ID Token + * object with the setMayAct method. + * + * Defined variables: + * token - AccessToken (1) or org.forgerock.openidconnect.OpenIdConnectToken. + * The token to be updated. + * Mutable object, all changes to the token will be reflected. + * scopes - Set (6). + * Always present, the requested scopes. + * requestProperties - Unmodifiable Map (5). + * Always present, contains a map of request properties: + * requestUri - The request URI. + * realm - The realm that the request relates to. + * requestParams - A map of the request params and/or posted data. + * Each value is a list of one or more properties. + * Please note that these should be handled in accordance with OWASP best practices: + * https://owasp.org/www-community/vulnerabilities/Unsafe_use_of_Reflection. + * clientProperties - Unmodifiable Map (5). + * Present if the client specified in the request was identified, contains a map of client properties: + * clientId - The client's URI for the request locale. + * allowedGrantTypes - List of the allowed grant types (org.forgerock.oauth2.core.GrantType) for the client. + * allowedResponseTypes - List of the allowed response types for the client. + * allowedScopes - List of the allowed scopes for the client. + * customProperties - A map of the custom properties of the client. + * Lists or maps will be included as sub-maps; for example: + * customMap[Key1]=Value1 will be returned as customMap -> Key1 -> Value1. + * To add custom properties to a client, update the Custom Properties field + * in AM Console > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Advanced. + * identity - AMIdentity (3). + * Always present, the identity of the resource owner. + * session - SSOToken (4). + * Present if the request contains the session cookie, the user's session object. + * scriptName - String (primitive). + * Always present, the display name of the script. + * logger - Always present, the "OAuth2Provider" debug logger instance: + * https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-logger.html#scripting-api-global-logger. + * Corresponding log files will be prefixed with: scripts.OAUTH2_MAY_ACT. + * + * Return - no value is expected, changes shall be made to the token parameter directly. + * + * Class reference: + * (1) AccessToken - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/oauth2/core/AccessToken.html. + * (3) AMIdentity - https://backstage.forgerock.com/docs/am/7/apidocs/com/sun/identity/idm/AMIdentity.html. + * (4) SSOToken - https://backstage.forgerock.com/docs/am/7/apidocs/com/iplanet/sso/SSOToken.html. + * (5) Map - https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashMap.html, + * or https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/LinkedHashMap.html. + * (6) Set - https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashSet.html. + */ + +/* EXAMPLE +(function () { + var frJava = JavaImporter( + org.forgerock.json.JsonValue + ); + + var mayAct = frJava.JsonValue.json(frJava.JsonValue.object()); + mayAct.put('client_id', 'myClient'); + mayAct.put('sub', '(usr!myActor)'); + + token.setMayAct(mayAct); + + // No return value is expected. Let it be undefined. +}()); +*/ diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_SCRIPTED_JWT_ISSUER/OAuth2 JWT Issuer Script.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_SCRIPTED_JWT_ISSUER/OAuth2 JWT Issuer Script.js new file mode 100644 index 000000000..5b25559ff --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_SCRIPTED_JWT_ISSUER/OAuth2 JWT Issuer Script.js @@ -0,0 +1,76 @@ +/* + * Copyright 2022-2025 Ping Identity Corporation. All Rights Reserved + * + * This code is to be used exclusively in connection with Ping Identity + * Corporation software or services. Ping Identity Corporation only offers + * such software or services to legal entities who have entered into a + * binding license agreement with Ping Identity Corporation. + */ + +/* + * This script lets you to derive the configuration for a dynamic JWT issuer from the issuer string. + * A JWT issuer is made up of the following: + * - issuer - the identifier of the entity that issues JWTs + * - resource owner subject claim - the name of the claim in the JWT that identifies the resource owner + * - consented scope claim - the name of the claim in the JWT that represents scope that the resource owner + * has already consented to externally + * - authorized subjects - the set of principal identifiers that are authorized to be used as resource owners + * by the issuer + * - JWKs - either a set of JWKs or connection details for obtaining that set, that are the public keys that + * can verify the signature on the issued JWTs. + * + * Defined variables: + * issuer - String + * The issuer from the bearer JWT. + * realm - String + * The path of the realm that is handling the request. + * scriptName - String. + * Always present, the display name of the script. + * logger - Always present, the script debug logger instance: + * https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-logger.html#scripting-api-global-logger. + * Corresponding log files will be prefixed with: scripts.OAUTH2_SCRIPTED_JWT_ISSUER. + * httpClient - HTTP Client (1). + * Always present, the HTTP Client instance: + * https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-http-client.html#scripting-api-global-http-client. + * idRepository - Identity Repository (2). Always present. + * secrets - Secrets accessor (3). Always present. + * + * Return - org.forgerock.oauth2.core.TrustedJwtIssuerConfig (4) - the configuration of the trusted JWT issuer. + * + * Class reference: + * (1) Client - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/http/Client.html. + * (2) ScriptedIdentityRepository - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/openam/scripting/api/identity/ScriptedIdentityRepository.html. + * (3) ScriptedSecrets - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/openam/scripting/api/secrets/ScriptedSecrets.html. + * (4) TrustedJwtIssuerConfig - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/oauth2/core/TrustedJwtIssuerConfig.html. + */ + +/* EXAMPLE +(function () { + var frJava = JavaImporter( + org.forgerock.oauth2.core.TrustedJwtIssuerConfig, + java.util.Collections + ); + + var iss = idRepository.getIdentity(issuer); + if (iss == null) { + logger.message('No issuer found for: '+issuer); + return null; + } + logger.message('Found issuer: '+iss); + // in this example either a JWK set or a URI to a JWK set are in the postalAddress attribute + var jwksAttrs = iss.getAttributeValues('postalAddress'); + var jwkSet = jwksAttrs.length === 0 ? null : jwksAttrs[0]; + var config = new frJava.TrustedJwtIssuerConfig( + issuer, + 'sub', + 'scope', + // in this example, valid subjects are stored in the mail attribute + iss.getAttributeValues('mail'), + jwkSet.startsWith('{') ? jwkSet : null, + jwkSet.startsWith('http') ? jwkSet : null, + '5 minutes', + '1 minute' + ); + return config; +}()); +*/ diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_VALIDATE_SCOPE/OAuth2 Validate Scope Script.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_VALIDATE_SCOPE/OAuth2 Validate Scope Script.js new file mode 100644 index 000000000..4b9368aa6 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OAUTH2_VALIDATE_SCOPE/OAuth2 Validate Scope Script.js @@ -0,0 +1,85 @@ +/* + * Copyright 2021 ForgeRock AS. All Rights Reserved + * Use of this code requires a commercial software license with ForgeRock AS. + * or with one of its affiliates. All use shall be exclusively subject + * to such license between the licensee and ForgeRock AS. + */ + +/* + * This script validates the requested scopes against the allowed scopes. + * If no scopes are requested, default scopes are assumed. + * The script has four top level functions that could be executed during the different OAuth2 flows: + * - validateAuthorizationScope + * - validateAccessTokenScope + * - validateRefreshTokenScope + * - validateBackChannelAuthorizationScope + * + * Defined variables: + * requestedScopes - Set (1). + * The set of requested scopes. + * defaultScopes - Set (1). + * The set of default scopes. + * allowedScopes - Set (1). + * The set of allowed scopes. + * scriptName - String (primitive). + * Always present, the display name of the script. + * logger - Always present, the debug logger instance: + * https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-logger.html#scripting-api-global-logger. + * Corresponding log files will be prefixed with: scripts.OAUTH2_VALIDATE_SCOPE + * httpClient - HTTP Client (2). + * Always present, the HTTP Client instance: + * https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-http-client.html#scripting-api-global-http-client. + * + * Throws InvalidScopeException: + * - if there are no scopes requested and default scopes are empty + * - if a requested scope is not allowed + * + * Return - a Set of validated scopes (1). + * + * Class reference: + * (1) Set - https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashSet.html. + * (2) Client - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/http/Client.html. + */ + +/** + * Default validate scope script. + */ +function validateScopes () { + var frJava = JavaImporter( + org.forgerock.oauth2.core.exceptions.InvalidScopeException + ); + + var scopes; + if (requestedScopes == null || requestedScopes.isEmpty()) { + scopes = defaultScopes; + } else { + scopes = new java.util.HashSet(allowedScopes); + scopes.retainAll(requestedScopes); + if (requestedScopes.size() > scopes.size()) { + var invalidScopes = new java.util.HashSet(requestedScopes); + invalidScopes.removeAll(allowedScopes); + throw new frJava.InvalidScopeException('Unknown/invalid scope(s)'); + } + } + + if (scopes == null || scopes.isEmpty()) { + throw new frJava.InvalidScopeException('No scope requested and no default scope configured'); + } + return scopes; +} + +function validateAuthorizationScope () { + return validateScopes(); +} + +function validateAccessTokenScope () { + return validateScopes(); +} + +function validateRefreshTokenScope () { + return validateScopes(); +} + +function validateBackChannelAuthorizationScope () { + return validateScopes(); +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OIDC_CLAIMS/OIDC Claims Script.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OIDC_CLAIMS/OIDC Claims Script.js new file mode 100644 index 000000000..b2f53ad69 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/OIDC_CLAIMS/OIDC Claims Script.js @@ -0,0 +1,621 @@ +/* + * Copyright 2014-2025 Ping Identity Corporation. All Rights Reserved + * + * This code is to be used exclusively in connection with Ping Identity + * Corporation software or services. Ping Identity Corporation only offers + * such software or services to legal entities who have entered into a + * binding license agreement with Ping Identity Corporation. + */ + +/* + * This script computes claim values returned in ID tokens and/or at the UserInfo Endpoint. + * The claim values are computed for: + * the claims derived from the requested scopes, + * the claims provided by the authorization server, + * and the claims requested by the client via the claims parameter. + * + * In the CONFIGURATION AND CUSTOMIZATION section, you can + * define the scope-to-claims mapping, and + * assign to each claim a resolver function that will compute the claim value. + * + * Defined variables (class references are provided below): + * scopes - Set (6). + * Always present, the requested scopes. + * claims - Map (5). + * Always present, default server provided claims. + * claimObjects - List (7, 2). + * Always present, the default server provided claims. + * requestedClaims - Map> (5). + * Always present, not empty if the request contains the claims parameter and the server has enabled + * claims_parameter_supported. A map of the requested claims to possible values, otherwise empty; + * requested claims with no requested values will have a key but no value in the map. A key with + * a single value in its Set (6) indicates that this is the only value that should be returned. + * requestedTypedClaims - List (7, 2). + * Always present, the requested claims. + * Requested claims with no requested values will have a claim with no values. + * A claim with a single value indicates this is the only value that should be returned. + * claimsLocales - List (7). + * The values from the 'claims_locales' parameter. + * See https://openid.net/specs/openid-connect-core-1_0.html#ClaimsLanguagesAndScripts for the OIDC specification details. + * requestProperties - Unmodifiable Map (5). + * Always present, contains a map of request properties: + * requestUri - The request URI. + * realm - The realm that the request relates to. + * requestParams - A map of the request params and/or posted data. + * Each value is a list of one or more properties. + * Please note that these should be handled in accordance with OWASP best practices: + * https://owasp.org/www-community/vulnerabilities/Unsafe_use_of_Reflection. + * clientProperties - Unmodifiable Map (5). + * Present if the client specified in the request was identified, contains a map of client properties: + * clientId - The client's URI for the request locale. + * allowedGrantTypes - List of the allowed grant types (org.forgerock.oauth2.core.GrantType) for the client. + * allowedResponseTypes - List of the allowed response types for the client. + * allowedScopes - List of the allowed scopes for the client. + * customProperties - A map of the custom properties of the client. + * Lists or maps will be included as sub-maps; for example: + * customMap[Key1]=Value1 will be returned as customMap -> Key1 -> Value1. + * To add custom properties to a client, update the Custom Properties field + * in AM Console > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Advanced. + * identity - AMIdentity (3). + * Always present, the identity of the resource owner. + * session - SSOToken (4). + * Present if the request contains the session cookie, the user's session object. + * scriptName - String (primitive). + * Always present, the display name of the script. + * logger - Always present, the "OAuth2Provider" debug logger instance: + * https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-logger.html#scripting-api-global-logger. + * Corresponding files will be prefixed with: scripts.OIDC_CLAIMS. + * httpClient - HTTP Client (8). + * Always present, the HTTP Client instance: + * https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-http-client.html#scripting-api-global-http-client. + * In order to use the client, you may need to add + * org.forgerock.http.Client, + * org.forgerock.http.protocol.*, + * and org.forgerock.util.promise.PromiseImpl + * to the allowed Java classes in the scripting engine configuration, as described in: + * https://backstage.forgerock.com/docs/am/7/scripting-guide/script-engine-security.html + * + * Return - a new UserInfoClaims(Map values, Map> compositeScopes) (1) object. + * The result of the last statement in the script is returned to the server. + * Currently, the Immediately Invoked Function Expression (also known as Self-Executing Anonymous Function) + * is the last (and only) statement in this script, and its return value will become the script result. + * Do not use "return variable" statement outside of a function definition. + * See RESULTS section for additional details. + * + * Class reference: + * (1) UserInfoClaims - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/oauth2/core/UserInfoClaims.html. + * (2) Claim - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/openidconnect/Claim.html). + * An instance of org.forgerock.openidconnect.Claim has methods to access + * the claim name, requested values, locale, and whether the claim is essential. + * (3) AMIdentity - https://backstage.forgerock.com/docs/am/7/apidocs/com/sun/identity/idm/AMIdentity.html. + * (4) SSOToken - https://backstage.forgerock.com/docs/am/7/apidocs/com/iplanet/sso/SSOToken.html. + * (5) Map - https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashMap.html, + * or https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/LinkedHashMap.html. + * (6) Set - https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashSet.html. + * (7) List - https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ArrayList.html. + * (8) Client - https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/http/Client.html. +*/ + +(function () { + // SETUP + + /** + * Claim processing utilities. + * An object that contains reusable functions for processing claims. + * @see CLAIM PROCESSING UTILITIES section for details. + */ + var utils = getUtils(); + + // CONFIGURATION AND CUSTOMIZATION + + /** + * OAuth 2.0 scope values (scopes) can be used by the Client to request OIDC claims. + * + * Call this configuration method, and pass in as the first argument + * an object that maps a scope value to an array of claim names + * to specify which claims need to be processed and returned for the requested scopes. + * @see {@link https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims} + * for the scope values that could be used to request claims as defined in the OIDC specification. + * + * Below, find a default configuration that is expected to work in the current environment. + * + * CUSTOMIZATION + * You can choose the claim names returned for a scope. + */ + utils.setScopeClaimsMap({ + profile: [ + 'name', + 'family_name', + 'given_name', + 'zoneinfo', + 'locale' + ], + email: ['email'], + address: ['address'], + phone: ['phone_number'] + }); + + /** + * In this script, each claim + * derived from the requested scopes, + * provided by the authorization server, and + * requested by the client via the claims parameter + * will be processed by a function associated with the claim name. + * + * Call this configuration method, and pass in as the first argument + * an object that maps a claim name to a resolver function, + * which will be automatically executed for each claim processed by the script. + * + * The claim resolver function will receive the requested claim information + * in an instance of org.forgerock.openidconnect.Claim as the first argument. + * @see {@link https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/openidconnect/Claim.html} + * for details on the Claim class. + * + * If the claim resolver function returns a value, + * other than undefined or null, + * the claim will be included in the script's results. + * + * The Claim instance provides methods to check + * what the name of the claim is, + * which values the claim request contains, + * whether the claim is essential, and + * which locale the claim is associated with. + * The resolver function can consider this information when computing and returning the claim value. + * + * Below, find a default configuration that is expected to work in the current environment. + * A reusable function, utils.getUserProfileClaimResolver(String attribute-name), + * is called to return a claim resolver function based on a user profile attribute. + * @see CLAIM RESOLVERS section for the implementation details and examples. + * For the address claim, an example of a claim resolver that uses another claim resolver is provided. + * + * CUSTOMIZATION + * You can reuse the predefined utils methods with your custom arguments. + * You can also specify a custom resolver function for a claim name, + * that will compute and return the claim value—as shown in the commented out example below. + */ + utils.setClaimResolvers({ + /* + // An example of a simple claim resolver function that is defined for a claim + // directly in the configuration object: + custom-claim-name: function (requestedClaim) { + // In this case, initially, the claim value comes straight from a user profile attribute value: + var claimValue = identity.getAttribute('custom-attribute-name').toArray()[0] + + // Optionally, provide additional logic for processing (filtering, formatting, etc.) the claim value. + // You can use: + // requestedClaim.getName() + // requestedClaim.getValues() + // requestedClaim.getLocale() + // requestedClaim.isEssential() + + return claimValue + }, + */ + /** + * The use of utils.getUserProfileClaimResolver shows how + * an argument passed to a function that returns a claim resolver + * becomes available to the resolver function (via its lexical context). + */ + name: utils.getUserProfileClaimResolver('cn'), + family_name: utils.getUserProfileClaimResolver('sn'), + given_name: utils.getUserProfileClaimResolver('givenname'), + zoneinfo: utils.getUserProfileClaimResolver('preferredtimezone'), + locale: utils.getUserProfileClaimResolver('preferredlocale'), + email: utils.getUserProfileClaimResolver('mail'), + address: utils.getAddressClaimResolver( + /** + * The passed in user profile claim resolver function + * can be used by the address claim resolver function + * to obtain the claim value to be formatted as per the OIDC specification: + * @see https://openid.net/specs/openid-connect-core-1_0.html#AddressClaim. + */ + utils.getUserProfileClaimResolver('postaladdress') + ), + phone_number: utils.getUserProfileClaimResolver('telephonenumber') + }); + + // CLAIM PROCESSING UTILITIES + + /** + * @returns {object} An object that contains reusable claim processing utilities. + * @see PUBLIC METHODS section and the return statement for the list of exported functions. + */ + function getUtils () { + // IMPORT JAVA + + /** + * Provides Java scripting functionality. + * @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino/Scripting_Java#javaimporter_constructor}. + */ + var frJava = JavaImporter( + org.forgerock.oauth2.core.exceptions.InvalidRequestException, + org.forgerock.oauth2.core.UserInfoClaims, + org.forgerock.openidconnect.Claim, + + java.util.LinkedHashMap, + java.util.ArrayList + ); + + // SET UP CONFIGURATION + + /** + * Placeholder for a configuration option that contains + * an object that maps the supported scope values (scopes) + * and the corresponding claim names for each scope value. + */ + var scopeClaimsMap; + + /** + * Placeholder for a configuration option that contains + * an object that maps the supported claim names + * and the resolver functions returning the claim value. + */ + var claimResolvers; + + /** + * A (public) method that accepts an object that maps the supported scopes and the corresponding claim names, + * and assigns it to a (private) variable that serves as a configuration option. + * @param {object} params - An object that maps each supported scope value to an array of claim names, + * in order to specify which claims need to be processed for the requested scopes. + * @see {@link https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims} for details. + * @param {string[]} [params.profile] - An array of claim names to be returned if the profile scope is requested. + * @param {string[]} [params.email] - An array of claim names to be returned if the email scope is requested. + * @param {string[]} [params.address] - An array of claim names to be returned if the address scope is requested. + * @param {string[]} [params.phone] - An array of claim names to be returned if the phone scope is requested. + * @returns {undefined} + */ + function setScopeClaimsMap(params) { + scopeClaimsMap = params; + } + + /** + * A (public) method that accepts an object that maps the supported claim names + * and the resolver functions returning the claim value, + * and assigns it to a (private) variable that serves as a configuration option. + * @param {object} params - An object that maps + * each supported claim name to a function that computes and returns the claim value. + */ + function setClaimResolvers(params) { + claimResolvers = params; + } + + // CLAIM RESOLVERS + + /** + * Claim resolvers are functions that return a claim value. + * @param {*} + * @returns {*} + */ + + /** + * Defines a claim resolver based on a user profile attribute. + * @param {string} attributeName - Name of the user profile attribute. + * @returns {function} A function that will determine the claim value + * based on the user profile attribute and the (requested) claim properties. + */ + function getUserProfileClaimResolver (attributeName) { + /** + * Resolves a claim with a user profile attribute value. + * Returns undefined if the identity attribute is not populated, + * OR if the claim has requested values that do not contain the identity attribute value. + * ATTENTION: the aforementioned comparison is case-sensitive. + * @param {org.forgerock.openidconnect.Claim} claim + * An object that provides methods to obtain information/requirements associated with a claim. + * @see {@link https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/openidconnect/Claim.html} for details. + * @returns {string|HashSet|undefined} + */ + function resolveClaim(claim) { + var userProfileValue; + + if (identity) { + userProfileValue = getClaimValueFromSet(claim, identity.getAttribute(attributeName)); + + if (userProfileValue && !userProfileValue.isEmpty()) { + if (!claim.getValues() || claim.getValues().isEmpty() || claim.getValues().contains(userProfileValue)) { + return userProfileValue; + } + } + } + } + + return resolveClaim; + } + + /** + * Returns an address claim resolver based on a claim value obtained with another claim resolver. + * @param {function} resolveClaim - A function that returns a claim value. + * @returns {function} A function that will accept a claim as an argument, + * run the claim resolver function for the claim and obtain the claim value, + * and apply additional formatting to the value before returning it. + */ + function getAddressClaimResolver (resolveClaim) { + /** + * Creates an address claim object from a value returned by a claim resolver, + * and returns the address claim object as the claim value. + * @see {@link https://openid.net/specs/openid-connect-core-1_0.html#AddressClaim}. + * The claim value is obtained with a claim resolving function available from the closure. + * @param {org.forgerock.openidconnect.Claim} claim + * An object that provides methods to obtain information/requirements associated with a claim. + * @see {@link https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/openidconnect/Claim.html} for details. + * @returns {java.util.LinkedHashMap|undefined} The address claim object created from a claim value. + */ + function resolveAddressClaim(claim) { + var claimValue = resolveClaim(claim); + var addressObject; + + if (isClaimValueValid(claimValue)) { + addressObject = new frJava.LinkedHashMap(); + + addressObject.put('formatted', claimValue); + + return addressObject; + } + } + + return resolveAddressClaim; + } + + /** + * Returns an essential claim resolver based on a claim value obtained with another claim resolver. + * @param {function} resolveClaim - A function that returns a claim value. + * @returns {function} A function that will accept a claim as an argument, + * run the claim resolver function for the claim and obtain the claim value, + * and apply additional logic for essential claims. + */ + function getEssentialClaimResolver (resolveClaim) { + /** + * Returns a claim value or throws an error. + * The claim value is obtained with a claim resolving function available from the closure. + * Throws an exception if the claim is essential and no value is returned for the claim. + * + * Use of this resolver is optional. + * @see {@link https://openid.net/specs/openid-connect-core-1_0.html#IndividualClaimsRequests} stating: + * "Note that even if the Claims are not available because the End-User did not authorize their release or they are not present, + * the Authorization Server MUST NOT generate an error when Claims are not returned, whether they are Essential or Voluntary, + * unless otherwise specified in the description of the specific claim." + * + * @param {org.forgerock.openidconnect.Claim} claim + * An object that provides methods to obtain information/requirements associated with a claim. + * @see {@link https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/openidconnect/Claim.html} for details. + * @returns {*} + * @throws {org.forgerock.oauth2.core.exceptions.InvalidRequestException} + */ + function resolveEssentialClaim(claim) { + var claimValue = resolveClaim(claim); + + if (claim.isEssential() && !isClaimValueValid(claimValue)) { + throw new frJava.InvalidRequestException('Could not provide value for essential claim: ' + claim.getName()); + } + + return claimValue; + } + + return resolveEssentialClaim; + } + + /** + * Provides default resolution for a claim. + * Use it if a claim-specific resolver is not defined in the configuration. + * @param {org.forgerock.openidconnect.Claim} claim + * An object that provides methods to obtain information/requirements associated with a claim. + * @see {@link https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/openidconnect/Claim.html} for details. + * @returns {*} A single value associated with this claim. + */ + function resolveAnyClaim (claim) { + if (claim.getValues().size() === 1) { + return claim.getValues().toArray()[0]; + } + } + + // UTILITIES + + /** + * Returns claim value from a set. + * If the set contains a single value, returns the value. + * If the set contains multiple values, returns the set. + * Otherwise, returns undefined. + * + * @param {org.forgerock.openidconnect.Claim} claim + * An object that provides methods to obtain information/requirements associated with a claim. + * @see {@link https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/openidconnect/Claim.html} for details. + * @param {java.util.HashSet} set The set—for example, a user profile attribute value. + * @returns {string|java.util.HashSet|undefined} + */ + function getClaimValueFromSet (claim, set) { + if (set && set.size()) { + if (set.size() === 1) { + return set.toArray()[0]; + } else { + return set; + } + } else if (logger.warningEnabled()) { + logger.warning('OIDC Claims script. Got an empty set for claim: ' + claim.getName()); + } + } + + function isClaimValueValid (claimValue) { + if (typeof claimValue === 'undefined' || claimValue === null) { + return false; + } + + return true; + } + + // CLAIM PROCESSING + + /** + * Constructs and returns an object populated with the computed claim values + * and the requested scopes mapped to the claim names. + * @returns {org.forgerock.oauth2.core.UserInfoClaims} The object to be returned to the authorization server. + * @see {@link https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/oauth2/core/UserInfoClaims.html}. + * @see RESULTS section for the use of this function. + */ + function getUserInfoClaims () { + return new frJava.UserInfoClaims(getComputedClaims(), getCompositeScopes()); + } + + /** + * Creates a map of (requested) claim names populated with the computed claim values. + * @returns {java.util.LinkedHashMap} + * A map of the requested claim names and the corresponding claim values. + */ + function getComputedClaims () { + /** + * Creates a complete list of claim objects from: + * the claims derived from the scopes, + * the claims provided by the authorization server, + * and the claims requested by the client. + * @returns {java.util.ArrayList} + * Returns a complete list of org.forgerock.openidconnect.Claim objects available to the script. + * @see {@link https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/openidconnect/Claim.html} for the claim object details. + */ + function getClaims() { + /** + * Returns a list of claim objects for the requested scopes. + * Uses the scopeClaimsMap configuration option to derive the claim names; + * no other properties of a claim derived from a scope are populated. + * @returns {java.util.ArrayList} + * A list of org.forgerock.openidconnect.Claim objects derived from the requested scopes. + * @see {@link https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/openidconnect/Claim.html} for the claim object details. + */ + function convertScopeToClaims() { + var claims = new frJava.ArrayList(); + + scopes.toArray().forEach(function (scope) { + if (String(scope) !== 'openid' && scopeClaimsMap[scope]) { + scopeClaimsMap[scope].forEach(function (claimName) { + claims.add(new frJava.Claim(claimName)); + }); + } + }); + + return claims; + } + + var claims = new frJava.ArrayList(); + + claims.addAll(convertScopeToClaims()); + claims.addAll(claimObjects); + claims.addAll(requestedTypedClaims); + + return claims; + } + + /** + * Computes and returns a claim value. + * To obtain the claim value, uses the resolver function specified for the claim in the claimResolvers configuration object. + * @see claimResolvers + * If no resolver function is found, uses the default claim resolver function. + * + * @param {org.forgerock.openidconnect.Claim} claim + * An object that provides methods to obtain information/requirements associated with a claim. + * @see {@link https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/openidconnect/Claim.html} for details. + * @returns {*} Claim value. + * @throws {org.forgerock.oauth2.core.exceptions.InvalidRequestException} + * Rethrows this exception if a claim resolver throws it. + * You can throw org.forgerock.oauth2.core.exceptions.InvalidRequestException from your custom claim resolver + * if you want to terminate the claim processing. + */ + function computeClaim(claim) { + var resolveClaim; + var message; + + try { + resolveClaim = claimResolvers[claim.getName()] || resolveAnyClaim; + + return resolveClaim(claim); + } catch (e) { + message = 'OIDC Claims script exception. Unable to resolve OIDC Claim. ' + e; + + if (String(e).indexOf('org.forgerock.oauth2.core.exceptions.InvalidRequestException') !== -1) { + throw e; + } + + if (logger.warningEnabled()) { + logger.warning(message); + } + } + } + + var computedClaims = new frJava.LinkedHashMap(); + + getClaims().toArray().forEach(function (claim) { + var claimValue = computeClaim(claim); + + if (isClaimValueValid(claimValue)) { + computedClaims.put(claim.getName(), claimValue); + } else { + /** + * If a claim has been processed, but appears in the list again, + * and its value cannot be computed under the new conditions, + * the claim is removed from the final result. + * + * For example, a claim could be mapped to a scope and found in the user profile, + * but also requested by the client with required values that don't match the computed one. + * @see {link https://openid.net/specs/openid-connect-core-1_0.html#IndividualClaimsRequests}. + * for the relevant OIDC specification details. + */ + computedClaims.remove(claim.getName()); + } + }); + + return computedClaims; + } + + /** + * Creates a map of requested scopes and the corresponding claim names. + * @returns {java.util.LinkedHashMap} + */ + function getCompositeScopes () { + var compositeScopes = new frJava.LinkedHashMap(); + + scopes.toArray().forEach(function (scope) { + var scopeClaims = new frJava.ArrayList(); + + if (scopeClaimsMap[scope]) { + scopeClaimsMap[scope].forEach(function (claimName) { + scopeClaims.add(claimName); + }); + } + + if (scopeClaims.size()) { + compositeScopes.put(scope, scopeClaims); + } + }); + + return compositeScopes; + } + + // PUBLIC METHODS + + return { + setScopeClaimsMap: setScopeClaimsMap, + setClaimResolvers: setClaimResolvers, + getUserProfileClaimResolver: getUserProfileClaimResolver, + getAddressClaimResolver: getAddressClaimResolver, + getEssentialClaimResolver: getEssentialClaimResolver, + getUserInfoClaims: getUserInfoClaims + }; + } + + // RESULTS + + /** + * This script returns an instance of the org.forgerock.oauth2.core.UserInfoClaims class + * populated with the computed claim values and + * the requested scopes mapped to the claim names. + * @see {@link https://backstage.forgerock.com/docs/am/7/apidocs/org/forgerock/oauth2/core/UserInfoClaims.html}. + * + * Assigning it to a variable gives you an opportunity + * to log the content of the returned value during development. + */ + var userInfoClaims = utils.getUserInfoClaims(); + + /* + logger.error(scriptName + ' results:') + logger.error('Values: ' + userInfoClaims.getValues()) + logger.error('Scopes: ' + userInfoClaims.getCompositeScopes()) + */ + + return userInfoClaims; +}()); diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/POLICY_CONDITION/Scripted Policy Condition.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/POLICY_CONDITION/Scripted Policy Condition.js new file mode 100644 index 000000000..b02879e23 --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/POLICY_CONDITION/Scripted Policy Condition.js @@ -0,0 +1,143 @@ +/* + * Copyright 2015-2025 Ping Identity Corporation. All Rights Reserved + * + * This code is to be used exclusively in connection with Ping Identity + * Corporation software or services. Ping Identity Corporation only offers + * such software or services to legal entities who have entered into a + * binding license agreement with Ping Identity Corporation. + */ +/** + * This is a Policy Condition example script. It demonstrates how to access a user's information, + * use that information in external HTTP calls and make a policy decision based on the outcome. + */ + +var userAddress, userIP, resourceHost; + +if (validateAndInitializeParameters()) { + + var countryFromUserAddress = getCountryFromUserAddress(); + logger.message("Country retrieved from user's address: " + countryFromUserAddress); + var countryFromUserIP = getCountryFromUserIP(); + logger.message("Country retrieved from user's IP: " + countryFromUserIP); + var countryFromResourceURI = getCountryFromResourceURI(); + logger.message("Country retrieved from resource URI: " + countryFromResourceURI); + + if (countryFromUserAddress === countryFromUserIP && countryFromUserAddress === countryFromResourceURI) { + logger.message("Authorization Succeeded"); + responseAttributes.put("countryOfOrigin", [countryFromUserAddress]); + authorized = true; + } else { + logger.message("Authorization Failed"); + authorized = false; + } + +} else { + logger.message("Required parameters not found. Authorization Failed."); + authorized = false; +} + +/** + * Use the user's address to lookup their country of residence. + * + * @returns {*} The user's country of residence. + */ +function getCountryFromUserAddress() { + + var request = new org.forgerock.http.protocol.Request(); + request.setUri("http://maps.googleapis.com/maps/api/geocode/json?address=" + encodeURIComponent(userAddress)); + request.setMethod("GET"); + + var response = httpClient.send(request).get(); + logResponse(response); + + var geocode = JSON.parse(response.getEntity()); + var i; + for (i = 0; i < geocode.results.length; i++) { + var result = geocode.results[i]; + var j; + for (j = 0; j < result.address_components.length; i++) { + if (result.address_components[i].types[0] == "country") { + return result.address_components[i].long_name; + } + } + } +} + +/** + * Use the user's IP to lookup the country from which the request originated. + * + * @returns {*} The country from which the request originated. + */ +function getCountryFromUserIP() { + var request = new org.forgerock.http.protocol.Request(); + request.setUri("http://ip-api.com/json/" + userIP); + request.setMethod("GET"); + + var response = httpClient.send(request).get(); + logResponse(response); + + var result = JSON.parse(response.getEntity()); + if (result) { + return result.country; + } +} + +/** + * Use the requested resource's host name to lookup the country where the resource is hosted. + * + * @returns {*} The country in which the resource is hosted. + */ +function getCountryFromResourceURI() { + var request = new org.forgerock.http.protocol.Request(); + request.setUri("http://ip-api.com/json/" + encodeURIComponent(resourceHost)); + request.setMethod("GET"); + + var response = httpClient.send(request).get(); + logResponse(response); + + var result = JSON.parse(response.getEntity()); + if (result) { + return result.country; + } +} + +/** + * Retrieve and validate the variables required to make the external HTTP calls. + * + * @returns {boolean} Will be true if validation was successful. + */ +function validateAndInitializeParameters() { + var userAddressSet = identity.getAttribute("postalAddress"); + if (userAddressSet == null || userAddressSet.isEmpty()) { + logger.warning("No address specified for user: " + username); + return false; + } + userAddress = userAddressSet.iterator().next(); + logger.message("User address: " + userAddress); + + if (!environment) { + logger.warning("No environment parameters specified in the evaluation request."); + return false; + } + + var ipSet = environment.get("IP"); + if (ipSet == null || ipSet.isEmpty()) { + logger.warning("No IP specified in the evaluation request environment parameters."); + return false; + } + userIP = ipSet.iterator().next(); + logger.message("User IP: " + userIP); + + if (!resourceURI) { + logger.warning("No resource URI specified."); + return false; + } + resourceHost = resourceURI.match(/^(.*:\/\/)(www\.)?([A-Za-z0-9\-\.]+)(:[0-9]+)?(.*)$/)[3]; + logger.message("Resource host: " + resourceHost); + + return true; +} + +function logResponse(response) { + logger.message("User REST Call. Status: " + response.getStatus() + ", Body: " + response.getEntity()); +} diff --git a/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/SAML2_IDP_ADAPTER/SAML2 IDP Adapter Script.js b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/SAML2_IDP_ADAPTER/SAML2 IDP Adapter Script.js new file mode 100644 index 000000000..31670ca4d --- /dev/null +++ b/test/e2e/exports/fr-config-manager/realms/scripts/scripts-content/SAML2_IDP_ADAPTER/SAML2 IDP Adapter Script.js @@ -0,0 +1,149 @@ +/* + * Copyright 2021 ForgeRock AS. All Rights Reserved + * Use of this code requires a commercial software license with ForgeRock AS. + * or with one of its affiliates. All use shall be exclusively subject + * to such license between the licensee and ForgeRock AS. + */ + +/* + * The script has these top level functions that could be executed during a SAML2 flow. + * - preSingleSignOn + * - preAuthentication + * - preSendResponse + * - preSignResponse + * - preSendFailureResponse + * + * Please see the javadoc for the interface definition and more information about these methods. + * https://backstage.forgerock.com/docs/am/7.2/apidocs/com/sun/identity/saml2/plugins/SAML2IdentityProviderAdapter.html + * Note that the initialize method is not supported in the scripts. + * + * Defined variables. Check the documentation on the respective functions for the variables available to it. + * + * hostedEntityId - String + * Entity ID for the hosted IDP + * realm - String + * Realm of the hosted IDP + * idpAdapterScriptHelper - IdpAdapterScriptHelper (1) + * An instance of IdpAdapterScriptHelper containing helper methods. See Javadoc for more details. + * request - HttpServletRequest (2) + * Servlet request object + * response - HttpServletResponse (3) + * Servlet response object + * authnRequest - AuthnRequest (4) + * The original authentication request sent from SP + * reqId - String + * The id to use for continuation of processing if the adapter redirects + * res - Response (5) + * The SAML Response + * session - SSOToken (6) + * The single sign-on session. The reference type of this is Object and would need to be casted to SSOToken. + * relayState - String + * The relayState that will be used in the redirect + * faultCode - String + * the fault code that will be returned in the SAML response + * faultDetail - String + * the fault detail that will be returned in the SAML response + * logger - Logger instance + * https://backstage.forgerock.com/docs/am/7/scripting-guide/scripting-api-global-logger.html#scripting-api-global-logger. + * Corresponding log files will be prefixed with: scripts.