@rockcarver/frodo-lib 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/.eslintrc +32 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +30 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. package/.github/README.md +121 -0
  5. package/.github/workflows/pipeline.yml +287 -0
  6. package/.prettierrc +6 -0
  7. package/CHANGELOG.md +512 -0
  8. package/CODE_OF_CONDUCT.md +128 -0
  9. package/LICENSE +21 -0
  10. package/README.md +8 -0
  11. package/docs/CONTRIBUTE.md +96 -0
  12. package/docs/PIPELINE.md +169 -0
  13. package/docs/images/npm_versioning_guidelines.png +0 -0
  14. package/docs/images/release_pipeline.png +0 -0
  15. package/jsconfig.json +6 -0
  16. package/package.json +95 -0
  17. package/resources/sampleEntitiesFile.json +8 -0
  18. package/resources/sampleEnvFile.env +2 -0
  19. package/src/api/AuthenticateApi.js +33 -0
  20. package/src/api/BaseApi.js +242 -0
  21. package/src/api/CirclesOfTrustApi.js +87 -0
  22. package/src/api/EmailTemplateApi.js +37 -0
  23. package/src/api/IdmConfigApi.js +88 -0
  24. package/src/api/LogApi.js +45 -0
  25. package/src/api/ManagedObjectApi.js +62 -0
  26. package/src/api/OAuth2ClientApi.js +69 -0
  27. package/src/api/OAuth2OIDCApi.js +73 -0
  28. package/src/api/OAuth2ProviderApi.js +32 -0
  29. package/src/api/RealmApi.js +99 -0
  30. package/src/api/Saml2Api.js +176 -0
  31. package/src/api/ScriptApi.js +84 -0
  32. package/src/api/SecretsApi.js +151 -0
  33. package/src/api/ServerInfoApi.js +41 -0
  34. package/src/api/SocialIdentityProvidersApi.js +114 -0
  35. package/src/api/StartupApi.js +45 -0
  36. package/src/api/ThemeApi.js +181 -0
  37. package/src/api/TreeApi.js +207 -0
  38. package/src/api/VariablesApi.js +104 -0
  39. package/src/api/utils/ApiUtils.js +77 -0
  40. package/src/api/utils/ApiUtils.test.js +96 -0
  41. package/src/api/utils/Base64.js +62 -0
  42. package/src/index.js +32 -0
  43. package/src/index.test.js +13 -0
  44. package/src/ops/AdminOps.js +901 -0
  45. package/src/ops/AuthenticateOps.js +342 -0
  46. package/src/ops/CirclesOfTrustOps.js +350 -0
  47. package/src/ops/ConnectionProfileOps.js +254 -0
  48. package/src/ops/EmailTemplateOps.js +326 -0
  49. package/src/ops/IdmOps.js +227 -0
  50. package/src/ops/IdpOps.js +342 -0
  51. package/src/ops/JourneyOps.js +2026 -0
  52. package/src/ops/LogOps.js +357 -0
  53. package/src/ops/ManagedObjectOps.js +34 -0
  54. package/src/ops/OAuth2ClientOps.js +151 -0
  55. package/src/ops/OrganizationOps.js +85 -0
  56. package/src/ops/RealmOps.js +139 -0
  57. package/src/ops/SamlOps.js +541 -0
  58. package/src/ops/ScriptOps.js +211 -0
  59. package/src/ops/SecretsOps.js +288 -0
  60. package/src/ops/StartupOps.js +114 -0
  61. package/src/ops/ThemeOps.js +379 -0
  62. package/src/ops/VariablesOps.js +185 -0
  63. package/src/ops/templates/OAuth2ClientTemplate.json +270 -0
  64. package/src/ops/templates/OrgModelUserAttributesTemplate.json +149 -0
  65. package/src/ops/templates/cloud/GenericExtensionAttributesTemplate.json +392 -0
  66. package/src/ops/templates/cloud/managed.json +4119 -0
  67. package/src/ops/utils/Console.js +434 -0
  68. package/src/ops/utils/DataProtection.js +92 -0
  69. package/src/ops/utils/DataProtection.test.js +28 -0
  70. package/src/ops/utils/ExportImportUtils.js +146 -0
  71. package/src/ops/utils/ExportImportUtils.test.js +119 -0
  72. package/src/ops/utils/OpsUtils.js +76 -0
  73. package/src/ops/utils/Wordwrap.js +11 -0
  74. package/src/storage/SessionStorage.js +45 -0
  75. package/src/storage/StaticStorage.js +15 -0
  76. package/test/e2e/journey/baseline/ForgottenUsername.journey.json +216 -0
  77. package/test/e2e/journey/baseline/Login.journey.json +205 -0
  78. package/test/e2e/journey/baseline/PasswordGrant.journey.json +139 -0
  79. package/test/e2e/journey/baseline/ProgressiveProfile.journey.json +198 -0
  80. package/test/e2e/journey/baseline/Registration.journey.json +249 -0
  81. package/test/e2e/journey/baseline/ResetPassword.journey.json +268 -0
  82. package/test/e2e/journey/baseline/UpdatePassword.journey.json +323 -0
  83. package/test/e2e/journey/baseline/allAlphaJourneys.journeys.json +1520 -0
  84. package/test/e2e/journey/delete/ForgottenUsername.journey.json +216 -0
  85. package/test/e2e/journey/delete/Login.journey.json +205 -0
  86. package/test/e2e/journey/delete/PasswordGrant.journey.json +139 -0
  87. package/test/e2e/journey/delete/ProgressiveProfile.journey.json +198 -0
  88. package/test/e2e/journey/delete/Registration.journey.json +249 -0
  89. package/test/e2e/journey/delete/ResetPassword.journey.json +268 -0
  90. package/test/e2e/journey/delete/UpdatePassword.journey.json +323 -0
  91. package/test/e2e/journey/delete/deleteMe.journey.json +230 -0
  92. package/test/e2e/journey/list/Disabled.journey.json +43 -0
  93. package/test/e2e/journey/list/ForgottenUsername.journey.json +216 -0
  94. package/test/e2e/journey/list/Login.journey.json +205 -0
  95. package/test/e2e/journey/list/PasswordGrant.journey.json +139 -0
  96. package/test/e2e/journey/list/ProgressiveProfile.journey.json +198 -0
  97. package/test/e2e/journey/list/Registration.journey.json +249 -0
  98. package/test/e2e/journey/list/ResetPassword.journey.json +268 -0
  99. package/test/e2e/journey/list/UpdatePassword.journey.json +323 -0
  100. package/test/e2e/setup.js +107 -0
  101. package/test/e2e/theme/baseline/Contrast.theme.json +95 -0
  102. package/test/e2e/theme/baseline/Highlander.theme.json +95 -0
  103. package/test/e2e/theme/baseline/Robroy.theme.json +95 -0
  104. package/test/e2e/theme/baseline/Starter-Theme.theme.json +94 -0
  105. package/test/e2e/theme/baseline/Zardoz.theme.json +95 -0
  106. package/test/e2e/theme/import/Contrast.theme.json +95 -0
  107. package/test/e2e/theme/import/Highlander.theme.json +95 -0
  108. package/test/e2e/theme/import/Robroy.theme.json +95 -0
  109. package/test/e2e/theme/import/Starter-Theme.theme.json +94 -0
  110. package/test/e2e/theme/import/Zardoz.default.theme.json +95 -0
  111. package/test/fs_tmp/.gitkeep +2 -0
  112. package/test/global/setup.js +65 -0
@@ -0,0 +1,119 @@
1
+ import { resolve } from 'path';
2
+ import { rmSync, existsSync, readFileSync } from 'fs';
3
+ import {
4
+ convertTextArrayToBase64,
5
+ convertBase64TextToArray,
6
+ saveToFile,
7
+ validateImport,
8
+ checkTargetCompatibility,
9
+ } from './ExportImportUtils.js';
10
+ // Warning! implimentation file contains non determinisitc functions which are either; not reasonable to test or imposible
11
+ // Cause: date based non overidable functions
12
+ // Not tested: getCurrentTimestamp
13
+
14
+ const FS_TMP_DIR = resolve('.', 'test', 'fs_tmp');
15
+ const PATH_TO_ARTIFACT = resolve(FS_TMP_DIR, 'export.json');
16
+
17
+ test('convertBase64TextToArray returns an array of text lines in base64 encoding', () => {
18
+ // Arrange
19
+ const originalScript = `
20
+ function frodo() {
21
+ return 'ring to mt doom';
22
+ }
23
+ `;
24
+ const base64Script = Buffer.from(originalScript).toString('base64');
25
+ // Act
26
+ const result = convertBase64TextToArray(base64Script);
27
+ // Assert
28
+ expect(result).toEqual(originalScript.split('\n'));
29
+ });
30
+
31
+ test('convertTextArrayToBase64', () => {
32
+ // Arrange
33
+ const originalArrayOfScriptLines = `
34
+ function frodo() {
35
+ return 'ring to mt doom';
36
+ }
37
+ `;
38
+ const expected = Buffer.from(originalArrayOfScriptLines).toString('base64');
39
+ // Act
40
+ const result = convertTextArrayToBase64(
41
+ originalArrayOfScriptLines.split('\n')
42
+ );
43
+ // Assert
44
+ expect(result).toEqual(expected);
45
+ });
46
+
47
+ test('validateImport should always return true', () => {
48
+ expect(validateImport()).not.toBe(false);
49
+ });
50
+
51
+ // This function has no way to determine when its asnyc task is complete, suggest using callback or promises to allow for testing
52
+ describe.skip('file system based tests', () => {
53
+ afterAll(() => {
54
+ if (existsSync(PATH_TO_ARTIFACT)) {
55
+ rmSync(PATH_TO_ARTIFACT);
56
+ }
57
+ });
58
+
59
+ test('saveToFile should save a file to specified tmp directory with expected data format', async () => {
60
+ // Arrange
61
+ const id = `id-3021`;
62
+ const data = [
63
+ {
64
+ id,
65
+ location: 'The Shire',
66
+ character: 'Gandalf',
67
+ words: 1064,
68
+ },
69
+ ];
70
+
71
+ const expected = {
72
+ lotr: {
73
+ 'id-3021': {
74
+ id: 'id-3021',
75
+ location: 'The Shire',
76
+ character: 'Gandalf',
77
+ words: 1064,
78
+ },
79
+ },
80
+ };
81
+ // Act
82
+ saveToFile('lotr', data, 'id', PATH_TO_ARTIFACT);
83
+ const resultingJSON = JSON.parse(readFileSync(PATH_TO_ARTIFACT));
84
+ // Assert
85
+ expect(resultingJSON.lotr).toEqual(expected.lotr);
86
+ });
87
+
88
+ test('saveToFile should save a file with metadata', async () => {
89
+ // Arrange
90
+ const id = `id-3021`;
91
+ const data = [
92
+ {
93
+ id,
94
+ location: 'The Shire',
95
+ character: 'Gandalf',
96
+ words: 1064,
97
+ },
98
+ ];
99
+ // Act
100
+ saveToFile('lotr', data, 'id', PATH_TO_ARTIFACT);
101
+ const resultingJSON = JSON.parse(readFileSync(PATH_TO_ARTIFACT));
102
+ // Assert
103
+ expect(Object.keys(resultingJSON.meta)).toEqual([
104
+ 'origin',
105
+ 'exportedBy',
106
+ 'exportDate',
107
+ 'exportTool',
108
+ 'exportToolVersion',
109
+ ]);
110
+ });
111
+ });
112
+
113
+ test.skip('checkTargetCompatibility to be made testable', () => {
114
+ // Arrange
115
+ // Act
116
+ const result = checkTargetCompatibility();
117
+ // Assert
118
+ expect(result).toBe('not tested yet');
119
+ });
@@ -0,0 +1,76 @@
1
+ import storage from '../../storage/SessionStorage.js';
2
+ import * as global from '../../storage/StaticStorage.js';
3
+
4
+ // TODO: do we really need this? if yes: document
5
+ export function escapeRegExp(str) {
6
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
7
+ }
8
+
9
+ // TODO: do we really need this? if yes: document
10
+ export function replaceAll(str, find, replace) {
11
+ return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
12
+ }
13
+
14
+ /**
15
+ * Get new name when names collide
16
+ * @param {String} name to apply policy to
17
+ * @returns {String} new name according to policy
18
+ */
19
+ export function applyNameCollisionPolicy(name) {
20
+ const capturingRegex = /(.* - imported) \(([0-9]+)\)/;
21
+ const found = name.match(capturingRegex);
22
+ if (found && found.length > 0 && found.length === 3) {
23
+ // already renamed one or more times
24
+ // return the next number
25
+ return `${found[1]} (${parseInt(found[2], 10) + 1})`;
26
+ }
27
+ // first time
28
+ return `${name} - imported (1)`;
29
+ }
30
+
31
+ /**
32
+ * Get the name of the managed user object for the current realm
33
+ * @returns {String} the name of the managed user object for the current realm
34
+ */
35
+ export function getRealmManagedUser() {
36
+ let realmManagedUser = 'user';
37
+ if (
38
+ storage.session.getDeploymentType() === global.CLOUD_DEPLOYMENT_TYPE_KEY
39
+ ) {
40
+ realmManagedUser = `${storage.session.getRealm()}_user`;
41
+ }
42
+ return realmManagedUser;
43
+ }
44
+
45
+ /**
46
+ * Compare two json objects
47
+ * @param {Object} obj1 object 1
48
+ * @param {Object} obj2 object 2
49
+ * @param {[String]} ignoreKeys array of keys to ignore in comparison
50
+ * @returns {boolean} true if the two json objects have the same length and all the properties have the same value
51
+ */
52
+ export function isEqualJson(obj1, obj2, ignoreKeys = []) {
53
+ const obj1Keys = Object.keys(obj1).filter((key) => !ignoreKeys.includes(key));
54
+ const obj2Keys = Object.keys(obj2).filter((key) => !ignoreKeys.includes(key));
55
+
56
+ if (obj1Keys.length !== obj2Keys.length) {
57
+ return false;
58
+ }
59
+
60
+ for (const objKey of obj1Keys) {
61
+ if (obj1[objKey] !== obj2[objKey]) {
62
+ if (
63
+ typeof obj1[objKey] === 'object' &&
64
+ typeof obj2[objKey] === 'object'
65
+ ) {
66
+ if (!isEqualJson(obj1[objKey], obj2[objKey], ignoreKeys)) {
67
+ return false;
68
+ }
69
+ } else {
70
+ return false;
71
+ }
72
+ }
73
+ }
74
+
75
+ return true;
76
+ }
@@ -0,0 +1,11 @@
1
+ export default function wordwrap(str, len, indent = undefined) {
2
+ if (!str) return '';
3
+ return (
4
+ str.match(
5
+ new RegExp(
6
+ `(\\S.{0,${len - 1 - (indent ? indent.length : 0)}})(?=\\s+|$)`,
7
+ 'g'
8
+ )
9
+ ) || []
10
+ ).join(indent ? `\n${indent}` : '\n');
11
+ }
@@ -0,0 +1,45 @@
1
+ /* eslint-disable no-return-assign */
2
+ import fs from 'fs';
3
+ // import pkg from '../../package.json' assert { type: 'json' };
4
+
5
+ const pkg = JSON.parse(
6
+ fs.readFileSync(new URL('../../package.json', import.meta.url))
7
+ );
8
+
9
+ const _sessionStorage = {};
10
+
11
+ export default {
12
+ session: {
13
+ setItem: (key, value) => (_sessionStorage[key] = value),
14
+ getItem: (key) => _sessionStorage[key],
15
+ removeItem: (key) => delete _sessionStorage[key],
16
+ raw: _sessionStorage,
17
+ setUsername: (value) => (_sessionStorage.username = value),
18
+ getUsername: () => _sessionStorage.username,
19
+ setPassword: (value) => (_sessionStorage.password = value),
20
+ getPassword: () => _sessionStorage.password,
21
+ setTenant: (value) => (_sessionStorage.tenant = value),
22
+ getTenant: () => _sessionStorage.tenant,
23
+ setDeploymentType: (value) => (_sessionStorage.deploymentType = value),
24
+ getDeploymentType: () => _sessionStorage.deploymentType,
25
+ setRealm: (value) => (_sessionStorage.realm = value),
26
+ getRealm: () => _sessionStorage.realm,
27
+ setCookieName: (value) => (_sessionStorage.cookieName = value),
28
+ getCookieName: () => _sessionStorage.cookieName,
29
+ setCookieValue: (value) => (_sessionStorage.cookieValue = value),
30
+ getCookieValue: () => _sessionStorage.cookieValue,
31
+ setBearerToken: (value) => (_sessionStorage.bearerToken = value),
32
+ getBearerToken: () => _sessionStorage.bearerToken,
33
+ setLogApiKey: (value) => (_sessionStorage.logApiKey = value),
34
+ getLogApiKey: () => _sessionStorage.logApiKey,
35
+ setLogApiSecret: (value) => (_sessionStorage.logApiSecret = value),
36
+ getLogApiSecret: () => _sessionStorage.logApiSecret,
37
+ setAmVersion: (value) => (_sessionStorage.amVersion = value),
38
+ getAmVersion: () => _sessionStorage.amVersion,
39
+ setFrodoVersion: (value) => (_sessionStorage.frodoVersion = value),
40
+ getFrodoVersion: () =>
41
+ _sessionStorage.frodoVersion || `v${pkg.version} [${process.version}]`,
42
+ setAllowInsecureConnection: (value) => (_sessionStorage.insecure = value),
43
+ getAllowInsecureConnection: () => _sessionStorage.insecure,
44
+ },
45
+ };
@@ -0,0 +1,15 @@
1
+ export const DEFAULT_REALM_KEY = '__default__realm__';
2
+ export const CLASSIC_DEPLOYMENT_TYPE_KEY = 'classic';
3
+ export const CLOUD_DEPLOYMENT_TYPE_KEY = 'cloud';
4
+ export const FORGEOPS_DEPLOYMENT_TYPE_KEY = 'forgeops';
5
+ export const DEPLOYMENT_TYPES = [
6
+ CLASSIC_DEPLOYMENT_TYPE_KEY,
7
+ CLOUD_DEPLOYMENT_TYPE_KEY,
8
+ FORGEOPS_DEPLOYMENT_TYPE_KEY,
9
+ ];
10
+ export const DEPLOYMENT_TYPE_REALM_MAP = {
11
+ [CLASSIC_DEPLOYMENT_TYPE_KEY]: '/',
12
+ [CLOUD_DEPLOYMENT_TYPE_KEY]: 'alpha',
13
+ [FORGEOPS_DEPLOYMENT_TYPE_KEY]: '/',
14
+ };
15
+ export const FRODO_METADATA_ID = 'frodo';
@@ -0,0 +1,216 @@
1
+ {
2
+ "meta": {
3
+ "origin": "https://openam-frodo-dev.forgeblocks.com/am",
4
+ "exportedBy": "volker.scheuber@forgerock.com",
5
+ "exportDate": "2022-06-20T17:54:10.100Z",
6
+ "exportTool": "frodo",
7
+ "exportToolVersion": "v0.6.1 [v18.2.0]"
8
+ },
9
+ "innerNodes": {
10
+ "9f1e8d94-4922-481b-9e14-212b66548900": {
11
+ "_id": "9f1e8d94-4922-481b-9e14-212b66548900",
12
+ "_rev": "-1331445210",
13
+ "attributesToCollect": [
14
+ "mail"
15
+ ],
16
+ "identityAttribute": "mail",
17
+ "validateInputs": false,
18
+ "required": true,
19
+ "_type": {
20
+ "_id": "AttributeCollectorNode",
21
+ "name": "Attribute Collector",
22
+ "collection": true
23
+ },
24
+ "_outcomes": [
25
+ {
26
+ "id": "outcome",
27
+ "displayName": "Outcome"
28
+ }
29
+ ]
30
+ }
31
+ },
32
+ "nodes": {
33
+ "5e2a7c95-94af-4b23-8724-deb13853726a": {
34
+ "_id": "5e2a7c95-94af-4b23-8724-deb13853726a",
35
+ "_rev": "-1421046051",
36
+ "nodes": [
37
+ {
38
+ "_id": "9f1e8d94-4922-481b-9e14-212b66548900",
39
+ "nodeType": "AttributeCollectorNode",
40
+ "displayName": "Attribute Collector"
41
+ }
42
+ ],
43
+ "pageDescription": {
44
+ "en": "Enter your email address or <a href=\"#/service/Login\">Sign in</a>"
45
+ },
46
+ "pageHeader": {
47
+ "en": "Forgotten Username"
48
+ },
49
+ "_type": {
50
+ "_id": "PageNode",
51
+ "name": "Page Node",
52
+ "collection": true
53
+ },
54
+ "_outcomes": [
55
+ {
56
+ "id": "outcome",
57
+ "displayName": "Outcome"
58
+ }
59
+ ]
60
+ },
61
+ "b93ce36e-1976-4610-b24f-8d6760b5463b": {
62
+ "_id": "b93ce36e-1976-4610-b24f-8d6760b5463b",
63
+ "_rev": "1389809903",
64
+ "tree": "Login",
65
+ "_type": {
66
+ "_id": "InnerTreeEvaluatorNode",
67
+ "name": "Inner Tree Evaluator",
68
+ "collection": true
69
+ },
70
+ "_outcomes": [
71
+ {
72
+ "id": "true",
73
+ "displayName": "True"
74
+ },
75
+ {
76
+ "id": "false",
77
+ "displayName": "False"
78
+ }
79
+ ]
80
+ },
81
+ "bf9ea8d5-9802-4f26-9664-a21840faac23": {
82
+ "_id": "bf9ea8d5-9802-4f26-9664-a21840faac23",
83
+ "_rev": "-626658673",
84
+ "identityAttribute": "mail",
85
+ "identifier": "userName",
86
+ "_type": {
87
+ "_id": "IdentifyExistingUserNode",
88
+ "name": "Identify Existing User",
89
+ "collection": true
90
+ },
91
+ "_outcomes": [
92
+ {
93
+ "id": "true",
94
+ "displayName": "True"
95
+ },
96
+ {
97
+ "id": "false",
98
+ "displayName": "False"
99
+ }
100
+ ]
101
+ },
102
+ "d9a79f01-2ce3-4be2-a28a-975f35c3c8ca": {
103
+ "_id": "d9a79f01-2ce3-4be2-a28a-975f35c3c8ca",
104
+ "_rev": "2035832000",
105
+ "emailSuspendMessage": {
106
+ "en": "An email has been sent to the address you entered. Click the link in that email to proceed."
107
+ },
108
+ "emailTemplateName": "forgottenUsername",
109
+ "identityAttribute": "mail",
110
+ "emailAttribute": "mail",
111
+ "objectLookup": true,
112
+ "_type": {
113
+ "_id": "EmailSuspendNode",
114
+ "name": "Email Suspend Node",
115
+ "collection": true
116
+ },
117
+ "_outcomes": [
118
+ {
119
+ "id": "outcome",
120
+ "displayName": "Outcome"
121
+ }
122
+ ]
123
+ }
124
+ },
125
+ "scripts": {},
126
+ "emailTemplates": {
127
+ "forgottenUsername": {
128
+ "_id": "emailTemplate/forgottenUsername",
129
+ "enabled": true,
130
+ "from": "",
131
+ "subject": {
132
+ "en": "Account Information - username",
133
+ "fr": "Informations sur le compte - nom d'utilisateur"
134
+ },
135
+ "message": {
136
+ "en": "<html><head></head><body style=\"background-color: #324054; color: #455469; padding: 60px; text-align: center;\"><div class=\"content\" style=\"background-color: #fff; border-radius: 4px; margin: 0 auto; padding: 48px; width: 235px;\"><p>{{#if object.userName}}Your username is '{{object.userName}}'.</p><p>{{else}}If you received this email in error, please disregard.{{/if}}</p><p><a href=\"{{object.resumeURI}}\" style=\"text-decoration: none; color: #109cf1;\">Click here to login</a></p></div></body></html>",
137
+ "fr": "<html><head></head><body style=\"background-color: #324054; color: #455469; padding: 60px; text-align: center;\"><div class=\"content\" style=\"background-color: #fff; border-radius: 4px; margin: 0 auto; padding: 48px; width: 235px;\">{{#if object.userName}}<p>Votre nom d'utilisateur est '{{object.userName}}'.</p>{{else}}Si vous avez reçu cet e-mail par erreur, veuillez ne pas en tenir compte.{{/if}}<p><a href=\"{{object.resumeURI}}\" style=\"text-decoration: none; color: #109cf1;\">Cliquez ici pour vous connecter</a></p></div></body></html>"
138
+ },
139
+ "html": {
140
+ "en": "<html><body>{{#if object.userName}}<p>Your username is '{{object.userName}}'.</p>{{else}}If you received this email in error, please disregard.{{/if}}<p><a href=\"{{object.resumeURI}}\">Click here to login</a></p></body></html>",
141
+ "fr": "<html><body>{{#if object.userName}}<p>Votre nom d'utilisateur est '{{object.userName}}'.</p>{{else}}Si vous avez reçu cet e-mail par erreur, veuillez ne pas en tenir compte.{{/if}}<p><a href=\"{{object.resumeURI}}\">Cliquez ici pour vous connecter</a></p></body></html>"
142
+ },
143
+ "styles": "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}",
144
+ "defaultLocale": "en",
145
+ "mimeType": "text/html"
146
+ }
147
+ },
148
+ "socialIdentityProviders": {},
149
+ "themes": [],
150
+ "saml2Entities": {},
151
+ "circlesOfTrust": {},
152
+ "tree": {
153
+ "_id": "ForgottenUsername",
154
+ "_rev": "-1762040244",
155
+ "identityResource": "managed/alpha_user",
156
+ "uiConfig": {
157
+ "categories": "[\"Username Reset\"]"
158
+ },
159
+ "entryNodeId": "5e2a7c95-94af-4b23-8724-deb13853726a",
160
+ "nodes": {
161
+ "5e2a7c95-94af-4b23-8724-deb13853726a": {
162
+ "connections": {
163
+ "outcome": "bf9ea8d5-9802-4f26-9664-a21840faac23"
164
+ },
165
+ "displayName": "Page Node",
166
+ "nodeType": "PageNode",
167
+ "x": 139,
168
+ "y": 146
169
+ },
170
+ "b93ce36e-1976-4610-b24f-8d6760b5463b": {
171
+ "connections": {
172
+ "false": "e301438c-0bd0-429c-ab0c-66126501069a",
173
+ "true": "70e691a5-1e33-4ac3-a356-e7b6d60d92e0"
174
+ },
175
+ "displayName": "Inner Tree Evaluator",
176
+ "nodeType": "InnerTreeEvaluatorNode",
177
+ "x": 767,
178
+ "y": 188
179
+ },
180
+ "bf9ea8d5-9802-4f26-9664-a21840faac23": {
181
+ "connections": {
182
+ "false": "d9a79f01-2ce3-4be2-a28a-975f35c3c8ca",
183
+ "true": "d9a79f01-2ce3-4be2-a28a-975f35c3c8ca"
184
+ },
185
+ "displayName": "Identify Existing User",
186
+ "nodeType": "IdentifyExistingUserNode",
187
+ "x": 324,
188
+ "y": 152
189
+ },
190
+ "d9a79f01-2ce3-4be2-a28a-975f35c3c8ca": {
191
+ "connections": {
192
+ "outcome": "b93ce36e-1976-4610-b24f-8d6760b5463b"
193
+ },
194
+ "displayName": "Email Suspend Node",
195
+ "nodeType": "EmailSuspendNode",
196
+ "x": 563,
197
+ "y": 193
198
+ }
199
+ },
200
+ "description": "Forgotten Username Tree",
201
+ "staticNodes": {
202
+ "70e691a5-1e33-4ac3-a356-e7b6d60d92e0": {
203
+ "x": 970,
204
+ "y": 149
205
+ },
206
+ "e301438c-0bd0-429c-ab0c-66126501069a": {
207
+ "x": 982,
208
+ "y": 252
209
+ },
210
+ "startNode": {
211
+ "x": 50,
212
+ "y": 25
213
+ }
214
+ }
215
+ }
216
+ }
@@ -0,0 +1,205 @@
1
+ {
2
+ "meta": {
3
+ "origin": "https://openam-frodo-dev.forgeblocks.com/am",
4
+ "exportedBy": "volker.scheuber@forgerock.com",
5
+ "exportDate": "2022-06-20T17:54:11.826Z",
6
+ "exportTool": "frodo",
7
+ "exportToolVersion": "v0.6.1 [v18.2.0]"
8
+ },
9
+ "innerNodes": {
10
+ "7354982f-57b6-4b04-9ddc-f1dd1e1e07d0": {
11
+ "_id": "7354982f-57b6-4b04-9ddc-f1dd1e1e07d0",
12
+ "_rev": "-2064640544",
13
+ "usernameAttribute": "userName",
14
+ "validateInput": false,
15
+ "_type": {
16
+ "_id": "ValidatedUsernameNode",
17
+ "name": "Platform Username",
18
+ "collection": true
19
+ },
20
+ "_outcomes": [
21
+ {
22
+ "id": "outcome",
23
+ "displayName": "Outcome"
24
+ }
25
+ ]
26
+ },
27
+ "0c80c39b-4813-4e67-b4fb-5a0bba85f994": {
28
+ "_id": "0c80c39b-4813-4e67-b4fb-5a0bba85f994",
29
+ "_rev": "-1763423776",
30
+ "validateInput": false,
31
+ "passwordAttribute": "password",
32
+ "_type": {
33
+ "_id": "ValidatedPasswordNode",
34
+ "name": "Platform Password",
35
+ "collection": true
36
+ },
37
+ "_outcomes": [
38
+ {
39
+ "id": "outcome",
40
+ "displayName": "Outcome"
41
+ }
42
+ ]
43
+ }
44
+ },
45
+ "nodes": {
46
+ "2998c1c9-f4c8-4a00-b2c6-3426783ee49d": {
47
+ "_id": "2998c1c9-f4c8-4a00-b2c6-3426783ee49d",
48
+ "_rev": "-656534578",
49
+ "_type": {
50
+ "_id": "DataStoreDecisionNode",
51
+ "name": "Data Store Decision",
52
+ "collection": true
53
+ },
54
+ "_outcomes": [
55
+ {
56
+ "id": "true",
57
+ "displayName": "True"
58
+ },
59
+ {
60
+ "id": "false",
61
+ "displayName": "False"
62
+ }
63
+ ]
64
+ },
65
+ "33b24514-3e50-4180-8f08-ab6f4e51b07e": {
66
+ "_id": "33b24514-3e50-4180-8f08-ab6f4e51b07e",
67
+ "_rev": "-1405518667",
68
+ "tree": "ProgressiveProfile",
69
+ "_type": {
70
+ "_id": "InnerTreeEvaluatorNode",
71
+ "name": "Inner Tree Evaluator",
72
+ "collection": true
73
+ },
74
+ "_outcomes": [
75
+ {
76
+ "id": "true",
77
+ "displayName": "True"
78
+ },
79
+ {
80
+ "id": "false",
81
+ "displayName": "False"
82
+ }
83
+ ]
84
+ },
85
+ "a12bc72f-ad97-4f1e-a789-a1fa3dd566c8": {
86
+ "_id": "a12bc72f-ad97-4f1e-a789-a1fa3dd566c8",
87
+ "_rev": "-1594114",
88
+ "nodes": [
89
+ {
90
+ "_id": "7354982f-57b6-4b04-9ddc-f1dd1e1e07d0",
91
+ "nodeType": "ValidatedUsernameNode",
92
+ "displayName": "Platform Username"
93
+ },
94
+ {
95
+ "_id": "0c80c39b-4813-4e67-b4fb-5a0bba85f994",
96
+ "nodeType": "ValidatedPasswordNode",
97
+ "displayName": "Platform Password"
98
+ }
99
+ ],
100
+ "pageDescription": {
101
+ "en": "New here? <a href=\"#/service/Registration\">Create an account</a><br><a href=\"#/service/ForgottenUsername\">Forgot username?</a><a href=\"#/service/ResetPassword\"> Forgot password?</a>"
102
+ },
103
+ "pageHeader": {
104
+ "en": "Sign In"
105
+ },
106
+ "_type": {
107
+ "_id": "PageNode",
108
+ "name": "Page Node",
109
+ "collection": true
110
+ },
111
+ "_outcomes": [
112
+ {
113
+ "id": "outcome",
114
+ "displayName": "Outcome"
115
+ }
116
+ ]
117
+ },
118
+ "bba3e0d8-8525-4e82-bf48-ac17f7988917": {
119
+ "_id": "bba3e0d8-8525-4e82-bf48-ac17f7988917",
120
+ "_rev": "2098371942",
121
+ "identityAttribute": "userName",
122
+ "_type": {
123
+ "_id": "IncrementLoginCountNode",
124
+ "name": "Increment Login Count",
125
+ "collection": true
126
+ },
127
+ "_outcomes": [
128
+ {
129
+ "id": "outcome",
130
+ "displayName": "Outcome"
131
+ }
132
+ ]
133
+ }
134
+ },
135
+ "scripts": {},
136
+ "emailTemplates": {},
137
+ "socialIdentityProviders": {},
138
+ "themes": [],
139
+ "saml2Entities": {},
140
+ "circlesOfTrust": {},
141
+ "tree": {
142
+ "_id": "Login",
143
+ "_rev": "174084184",
144
+ "identityResource": "managed/alpha_user",
145
+ "uiConfig": {
146
+ "categories": "[\"Authentication\"]"
147
+ },
148
+ "entryNodeId": "a12bc72f-ad97-4f1e-a789-a1fa3dd566c8",
149
+ "nodes": {
150
+ "2998c1c9-f4c8-4a00-b2c6-3426783ee49d": {
151
+ "connections": {
152
+ "false": "e301438c-0bd0-429c-ab0c-66126501069a",
153
+ "true": "bba3e0d8-8525-4e82-bf48-ac17f7988917"
154
+ },
155
+ "displayName": "Data Store Decision",
156
+ "nodeType": "DataStoreDecisionNode",
157
+ "x": 315,
158
+ "y": 140
159
+ },
160
+ "33b24514-3e50-4180-8f08-ab6f4e51b07e": {
161
+ "connections": {
162
+ "false": "e301438c-0bd0-429c-ab0c-66126501069a",
163
+ "true": "70e691a5-1e33-4ac3-a356-e7b6d60d92e0"
164
+ },
165
+ "displayName": "Inner Tree Evaluator",
166
+ "nodeType": "InnerTreeEvaluatorNode",
167
+ "x": 815,
168
+ "y": 180
169
+ },
170
+ "a12bc72f-ad97-4f1e-a789-a1fa3dd566c8": {
171
+ "connections": {
172
+ "outcome": "2998c1c9-f4c8-4a00-b2c6-3426783ee49d"
173
+ },
174
+ "displayName": "Page Node",
175
+ "nodeType": "PageNode",
176
+ "x": 136,
177
+ "y": 59
178
+ },
179
+ "bba3e0d8-8525-4e82-bf48-ac17f7988917": {
180
+ "connections": {
181
+ "outcome": "33b24514-3e50-4180-8f08-ab6f4e51b07e"
182
+ },
183
+ "displayName": "Increment Login Count",
184
+ "nodeType": "IncrementLoginCountNode",
185
+ "x": 564,
186
+ "y": 132
187
+ }
188
+ },
189
+ "description": "Platform Login Tree",
190
+ "staticNodes": {
191
+ "70e691a5-1e33-4ac3-a356-e7b6d60d92e0": {
192
+ "x": 1008,
193
+ "y": 186
194
+ },
195
+ "e301438c-0bd0-429c-ab0c-66126501069a": {
196
+ "x": 624,
197
+ "y": 267
198
+ },
199
+ "startNode": {
200
+ "x": 50,
201
+ "y": 25
202
+ }
203
+ }
204
+ }
205
+ }