diff --git a/src/api/classic/SecretStoreApi.ts b/src/api/classic/SecretStoreApi.ts new file mode 100644 index 00000000..823c4217 --- /dev/null +++ b/src/api/classic/SecretStoreApi.ts @@ -0,0 +1,173 @@ +import util from 'util'; + +import { State } from '../../shared/State'; +import { getConfigPath, getRealmPathGlobal } from '../../utils/ForgeRockUtils'; +import { + AmConfigEntityInterface, + IdObjectSkeletonInterface, + PagedResult, +} from '../ApiTypes'; +import { generateAmApi } from '../BaseApi'; + +const secretStoreURLTemplate = '%s/json%s/%s/secrets/stores/%s/%s'; +const secretStoresURLTemplate = + '%s/json%s/%s/secrets/stores?_action=nextdescendents'; +const secretStoreMappingURLTemplate = secretStoreURLTemplate + '/mappings/%s'; +const secretStoreMappingsURLTemplate = + secretStoreURLTemplate + '/mappings?_queryFilter=true'; + +const secretTypesThatIgnoreId = ['EnvironmentAndSystemPropertySecretStore']; + +const apiVersion = 'protocol=2.1,resource=%s'; +const globalVersion = '1.0'; +const realmVersion = '2.0'; +const getApiConfig = (globalConfig) => { + return { + apiVersion: util.format( + apiVersion, + globalConfig ? globalVersion : realmVersion + ), + }; +}; + +export type SecretStoreSkeleton = AmConfigEntityInterface; + +export type SecretStoreMappingSkeleton = IdObjectSkeletonInterface & { + secretId: string; + aliases: string[]; +}; + +/** + * Get all secret stores + * @param {boolean} globalConfig true if the secret store is global, false otherwise. Default: false. + * @returns {Promise>} a promise that resolves to an array of secret store objects + */ +export async function getSecretStores({ + globalConfig = false, + state, +}: { + globalConfig: boolean; + state: State; +}): Promise> { + const urlString = util.format( + secretStoresURLTemplate, + state.getHost(), + getRealmPathGlobal(globalConfig, state), + getConfigPath(globalConfig) + ); + const { data } = await generateAmApi({ + resource: getApiConfig(globalConfig), + state, + }).post(urlString, undefined, { + withCredentials: true, + }); + return data; +} + +/** + * Get secret store mappings + * @param {string} secretStoreId Secret store id + * @param {string} secretStoreTypeId Secret store type id + * @param {boolean} globalConfig true if the secret store is global, false otherwise. Default: false. + * @returns {Promise} a promise that resolves to an array of secret store mapping objects + */ +export async function getSecretStoreMappings({ + secretStoreId, + secretStoreTypeId, + globalConfig = false, + state, +}: { + secretStoreId: string; + secretStoreTypeId: string; + globalConfig: boolean; + state: State; +}): Promise> { + const urlString = util.format( + secretStoreMappingsURLTemplate, + state.getHost(), + getRealmPathGlobal(globalConfig, state), + getConfigPath(globalConfig), + secretStoreTypeId, + secretStoreId + ); + const { data } = await generateAmApi({ + resource: getApiConfig(globalConfig), + state, + }).get(urlString, { + withCredentials: true, + }); + return data; +} + +/** + * Put secret store + * @param {SecretStoreSkeleton} secretStoreData secret store to import + * @param {boolean} globalConfig true if the secret store is global, false otherwise. Default: false. + * @returns {Promise} a promise that resolves to a secret store object + */ +export async function putSecretStore({ + secretStoreData, + globalConfig = false, + state, +}: { + secretStoreData: SecretStoreSkeleton; + globalConfig: boolean; + state: State; +}): Promise { + const urlString = util.format( + secretStoreURLTemplate, + state.getHost(), + getRealmPathGlobal(globalConfig, state), + getConfigPath(globalConfig), + secretStoreData._type._id, + secretTypesThatIgnoreId.includes(secretStoreData._type._id) + ? '' + : secretStoreData._id + ); + const { data } = await generateAmApi({ + resource: getApiConfig(globalConfig), + state, + }).put(urlString, secretStoreData, { + withCredentials: true, + }); + return data; +} + +/** + * Put secret store mapping + * @param {string} secretStoreId Secret store id + * @param {string} secretStoreTypeId Secret store type id + * @param {SecretStoreMappingSkeleton} secretStoreMappingData secret store mapping to import + * @param {boolean} globalConfig true if the secret store mapping is global, false otherwise. Default: false. + * @returns {Promise} a promise that resolves to a secret store mapping object + */ +export async function putSecretStoreMapping({ + secretStoreId, + secretStoreTypeId, + secretStoreMappingData, + globalConfig = false, + state, +}: { + secretStoreId: string; + secretStoreTypeId: string; + secretStoreMappingData: SecretStoreMappingSkeleton; + globalConfig: boolean; + state: State; +}): Promise { + const urlString = util.format( + secretStoreMappingURLTemplate, + state.getHost(), + getRealmPathGlobal(globalConfig, state), + getConfigPath(globalConfig), + secretStoreTypeId, + secretStoreId, + secretStoreMappingData._id + ); + const { data } = await generateAmApi({ + resource: getApiConfig(globalConfig), + state, + }).put(urlString, secretStoreMappingData, { + withCredentials: true, + }); + return data; +} diff --git a/src/lib/FrodoLib.ts b/src/lib/FrodoLib.ts index e07632d0..a8291ce5 100644 --- a/src/lib/FrodoLib.ts +++ b/src/lib/FrodoLib.ts @@ -9,6 +9,7 @@ import AuthenticationSettingsOps, { AuthenticationSettings, } from '../ops/AuthenticationSettingsOps'; import CirclesOfTrustOps, { CirclesOfTrust } from '../ops/CirclesOfTrustOps'; +import SecretStoreOps, { SecretStore } from '../ops/classic/SecretStoreOps'; import ServerOps, { Server } from '../ops/classic/ServerOps'; import AdminFederationOps, { AdminFederation, @@ -186,6 +187,7 @@ export type Frodo = { script: Script; server: Server; + secretStore: SecretStore; service: Service; session: Session; @@ -354,6 +356,7 @@ const FrodoLib = (config: StateInterface = {}): Frodo => { script: ScriptOps(state), server: ServerOps(state), + secretStore: SecretStoreOps(state), service: ServiceOps(state), session: SessionOps(state), diff --git a/src/ops/classic/SecretStoreOps.test.ts b/src/ops/classic/SecretStoreOps.test.ts new file mode 100644 index 00000000..a9df1010 --- /dev/null +++ b/src/ops/classic/SecretStoreOps.test.ts @@ -0,0 +1,142 @@ +/** + * To record and update snapshots, you must perform 3 steps in order: + * + * 1. Record API responses + * + * Recording requires an available classic deployment, since secret stores + * can only be accessed in classic. Set FRODO_HOST and FRODO_REALM + * environment variables or alternatively FRODO_DEPLOY=classic + * in order to appropriately record requests to the classic deployment. + * + * To record API responses, you must call the test:record script and + * override all the connection state required to connect to the + * env to record from: + * + * ATTENTION: For the recording to succeed, you MUST make sure to use a + * user account, not a service account. + * + * FRODO_DEBUG=1 FRODO_HOST=frodo-dev npm run test:record SecretStoreOps + * + * The above command assumes that you have a connection profile for + * 'frodo-dev' on your development machine. + * + * 2. Update snapshots + * + * After recording API responses, you must manually update/create snapshots + * by running: + * + * FRODO_DEBUG=1 npm run test:update SecretStoreOps + * + * 3. Test your changes + * + * If 1 and 2 didn't produce any errors, you are ready to run the tests in + * replay mode and make sure they all succeed as well: + * + * FRODO_DEBUG=1 npm run test:only SecretStoreOps + * + * Note: FRODO_DEBUG=1 is optional and enables debug logging for some output + * in case things don't function as expected + */ +import { autoSetupPolly, setDefaultState } from "../../utils/AutoSetupPolly"; +import { filterRecording } from "../../utils/PollyUtils"; +import * as SecretStoreOps from "./SecretStoreOps"; +import { state } from "../../lib/FrodoLib"; +import Constants from "../../shared/Constants"; + +const ctx = autoSetupPolly(); + +describe('SecretStoreOps', () => { + beforeEach(async () => { + if (process.env.FRODO_POLLY_MODE === 'record') { + ctx.polly.server.any().on('beforePersist', (_req, recording) => { + filterRecording(recording); + }); + } + setDefaultState(Constants.CLASSIC_DEPLOYMENT_TYPE_KEY); + }); + + describe('createSecretStoreExportTemplate()', () => { + test('0: Method is implemented', async () => { + expect(SecretStoreOps.createSecretStoreExportTemplate).toBeDefined(); + }); + + test('1: Create SecretStore Export Template', async () => { + const response = SecretStoreOps.createSecretStoreExportTemplate({ state }); + expect(response).toMatchSnapshot({ + meta: expect.any(Object), + }); + }); + }); + + describe('readSecretStore()', () => { + test('0: Method is implemented', async () => { + expect(SecretStoreOps.readSecretStore).toBeDefined(); + }); + //TODO: create tests + }); + + describe('readSecretStores()', () => { + test('0: Method is implemented', async () => { + expect(SecretStoreOps.readSecretStores).toBeDefined(); + }); + + test('1: Read realm SecretStores', async () => { + const response = await SecretStoreOps.readSecretStores({ globalConfig: false, state }); + expect(response).toMatchSnapshot(); + }); + + test('2: Read global SecretStores', async () => { + const response = await SecretStoreOps.readSecretStores({ globalConfig: true, state }); + expect(response).toMatchSnapshot(); + }); + }); + + describe('exportSecretStore()', () => { + test('0: Method is implemented', async () => { + expect(SecretStoreOps.exportSecretStore).toBeDefined(); + }); + //TODO: create tests + }); + + describe('exportSecretStores()', () => { + test('0: Method is implemented', async () => { + expect(SecretStoreOps.exportSecretStores).toBeDefined(); + }); + + test('1: Export realm SecretStores', async () => { + const response = await SecretStoreOps.exportSecretStores({ globalConfig: false, state }); + expect(response).toMatchSnapshot({ + meta: expect.any(Object), + }); + }); + + test('2: Export global SecretStores', async () => { + const response = await SecretStoreOps.exportSecretStores({ globalConfig: true, state }); + expect(response).toMatchSnapshot({ + meta: expect.any(Object), + }); + }); + }); + + describe('updateSecretStore()', () => { + test('0: Method is implemented', async () => { + expect(SecretStoreOps.updateSecretStore).toBeDefined(); + }); + //TODO: create tests + }); + + describe('updateSecretStoreMapping()', () => { + test('0: Method is implemented', async () => { + expect(SecretStoreOps.updateSecretStoreMapping).toBeDefined(); + }); + //TODO: create tests + }); + + describe('importSecretStores()', () => { + test('0: Method is implemented', async () => { + expect(SecretStoreOps.importSecretStores).toBeDefined(); + }); + //TODO: create tests + }); + +}); diff --git a/src/ops/classic/SecretStoreOps.ts b/src/ops/classic/SecretStoreOps.ts new file mode 100644 index 00000000..1f9062e3 --- /dev/null +++ b/src/ops/classic/SecretStoreOps.ts @@ -0,0 +1,538 @@ +import { + getSecretStoreMappings, + getSecretStores, + putSecretStore, + putSecretStoreMapping, + SecretStoreMappingSkeleton, + SecretStoreSkeleton, +} from '../../api/classic/SecretStoreApi'; +import { State } from '../../shared/State'; +import { + createProgressIndicator, + debugMessage, + printMessage, + stopProgressIndicator, + updateProgressIndicator, +} from '../../utils/Console'; +import { getMetadata } from '../../utils/ExportImportUtils'; +import { FrodoError } from '../FrodoError'; +import { ExportMetaData } from '../OpsTypes'; + +export type SecretStore = { + /** + * Create an empty secret store export template + * @returns {SecretStoreExportInterface} an empty secret store export template + */ + createSecretStoreExportTemplate(): SecretStoreExportInterface; + /** + * Read secret store by id + * @param {string} secretStoreId Secret store id + * @param {boolean} globalConfig true if global secret store is the target of the operation, false otherwise. Default: false. + * @returns {Promise} a promise that resolves to a secret store object + */ + readSecretStore( + secretStoreId: string, + globalConfig: boolean + ): Promise; + /** + * Read all secret stores. + * @param {boolean} globalConfig true if global secret stores are the target of the operation, false otherwise. Default: false. + * @returns {Promise} a promise that resolves to an array of secret store objects + */ + readSecretStores(globalConfig: boolean): Promise; + /** + * Read secret store mappings + * @param {string} secretStoreId Secret store id + * @param {string} secretStoreTypeId Secret store type id + * @param {boolean} globalConfig true if the secret store is global, false otherwise. Default: false. + * @returns {Promise} a promise that resolves to an array of secret store mapping objects + */ + readSecretStoreMappings( + secretStoreId: string, + secretStoreTypeId: string, + globalConfig: boolean + ): Promise; + /** + * Export a single secret store by id. The response can be saved to file as is. + * @param {string} secretStoreId Secret store id + * @param {boolean} globalConfig true if global secret store is the target of the operation, false otherwise. Default: false. + * @returns {Promise} Promise resolving to a SecretStoreExportInterface object. + */ + exportSecretStore( + secretStoreId: string, + globalConfig: boolean + ): Promise; + /** + * Export all secret stores. The response can be saved to file as is. + * @param {boolean} globalConfig true if global secret stores are the target of the operation, false otherwise. Default: false. + * @returns {Promise} Promise resolving to a SecretStoreExportInterface object. + */ + exportSecretStores( + globalConfig: boolean + ): Promise; + /** + * Update secret store + * @param {SecretStoreSkeleton} secretStoreData secret store to import + * @param {boolean} globalConfig true if the secret store is global, false otherwise. Default: false. + * @returns {Promise} a promise that resolves to a secret store object + */ + updateSecretStore( + secretStoreData: SecretStoreSkeleton, + globalConfig: boolean + ): Promise; + /** + * Update secret store mapping + * @param {string} secretStoreId Secret store id + * @param {string} secretStoreTypeId Secret store type id + * @param {SecretStoreMappingSkeleton} secretStoreMappingData secret store mapping to import + * @param {boolean} globalConfig true if the secret store mapping is global, false otherwise. Default: false. + * @returns {Promise} a promise that resolves to a secret store mapping object + */ + updateSecretStoreMapping( + secretStoreId: string, + secretStoreTypeId: string, + secretStoreMappingData: SecretStoreMappingSkeleton, + globalConfig: boolean + ): Promise; + /** + * Import secret stores and mappings + * @param {SecretStoreExportInterface} importData secret store import data + * @param {boolean} globalConfig true if the secret store mapping is global, false otherwise. Default: false. + * @param {string} secretStoreId optional secret store id. If supplied, only the secret store of that id is imported. + * @returns {Promise} the imported secret stores and mappings + */ + importSecretStores( + importData: SecretStoreExportInterface, + globalConfig: boolean, + secretStoreId?: string + ): Promise; +}; + +export default (state: State): SecretStore => { + return { + createSecretStoreExportTemplate(): SecretStoreExportInterface { + return createSecretStoreExportTemplate({ state }); + }, + async readSecretStore( + secretStoreId: string, + globalConfig: boolean = false + ): Promise { + return readSecretStore({ secretStoreId, globalConfig, state }); + }, + async readSecretStores( + globalConfig: boolean = false + ): Promise { + return readSecretStores({ globalConfig, state }); + }, + async readSecretStoreMappings( + secretStoreId: string, + secretStoreTypeId: string, + globalConfig: boolean = false + ): Promise { + return readSecretStoreMappings({ + secretStoreId, + secretStoreTypeId, + globalConfig, + state, + }); + }, + async exportSecretStore( + secretStoreId: string, + globalConfig: boolean = false + ): Promise { + return exportSecretStore({ secretStoreId, globalConfig, state }); + }, + async exportSecretStores( + globalConfig: boolean = false + ): Promise { + return exportSecretStores({ globalConfig, state }); + }, + async updateSecretStore( + secretStoreData: SecretStoreSkeleton, + globalConfig: boolean = false + ): Promise { + return updateSecretStore({ + secretStoreData, + globalConfig, + state, + }); + }, + async updateSecretStoreMapping( + secretStoreId: string, + secretStoreTypeId: string, + secretStoreMappingData: SecretStoreMappingSkeleton, + globalConfig: boolean = false + ): Promise { + return updateSecretStoreMapping({ + secretStoreId, + secretStoreTypeId, + secretStoreMappingData, + globalConfig, + state, + }); + }, + async importSecretStores( + importData: SecretStoreExportInterface, + globalConfig: boolean = false, + secretStoreId?: string + ): Promise { + return importSecretStores({ + importData, + globalConfig, + secretStoreId, + state, + }); + }, + }; +}; + +export type SecretStoreExportSkeleton = SecretStoreSkeleton & { + mappings: SecretStoreMappingSkeleton[]; +}; + +export interface SecretStoreExportInterface { + meta?: ExportMetaData; + secretstore: Record; +} + +/** + * Create an empty secret store export template + * @returns {SecretStoreExportInterface} an empty secret store export template + */ +export function createSecretStoreExportTemplate({ + state, +}: { + state: State; +}): SecretStoreExportInterface { + return { + meta: getMetadata({ state }), + secretstore: {}, + }; +} + +/** + * Read secret store by id + * @param {string} secretStoreId Secret store id + * @param {boolean} globalConfig true if global secret store is the target of the operation, false otherwise. Default: false. + * @returns {Promise} a promise that resolves to a secret store object + */ +export async function readSecretStore({ + secretStoreId, + globalConfig = false, + state, +}: { + secretStoreId: string; + globalConfig: boolean; + state: State; +}): Promise { + try { + const found = (await readSecretStores({ globalConfig, state })).filter( + (secretStore) => secretStore._id === secretStoreId + ); + if (found.length === 1) { + return found[0]; + } + throw new Error(`Secret store with id '${secretStoreId}' not found!`); + } catch (error) { + throw new FrodoError(`Error reading secret store ${secretStoreId}`, error); + } +} + +/** + * Read all secret stores. + * @param {boolean} globalConfig true if global secret stores are the target of the operation, false otherwise. Default: false. + * @returns {Promise} a promise that resolves to an array of secret store objects + */ +export async function readSecretStores({ + globalConfig = false, + state, +}: { + globalConfig: boolean; + state: State; +}): Promise { + try { + debugMessage({ + message: `SecretStoreOps.readSecretStores: start`, + state, + }); + const { result } = await getSecretStores({ globalConfig, state }); + debugMessage({ message: `SecretStoreOps.readSecretStores: end`, state }); + return result; + } catch (error) { + throw new FrodoError(`Error reading secret stores`, error); + } +} + +/** + * Read secret store mappings + * @param {string} secretStoreId Secret store id + * @param {string} secretStoreTypeId Secret store type id + * @param {boolean} globalConfig true if the secret store is global, false otherwise. Default: false. + * @returns {Promise} a promise that resolves to an array of secret store mapping objects + */ +export async function readSecretStoreMappings({ + secretStoreId, + secretStoreTypeId, + globalConfig = false, + state, +}: { + secretStoreId: string; + secretStoreTypeId: string; + globalConfig: boolean; + state: State; +}): Promise { + try { + debugMessage({ + message: `SecretStoreOps.readSecretStoreMappings: start`, + state, + }); + const { result } = await getSecretStoreMappings({ + secretStoreId, + secretStoreTypeId, + globalConfig, + state, + }); + debugMessage({ + message: `SecretStoreOps.readSecretStoreMappings: end`, + state, + }); + return result; + } catch (error) { + if (error.httpStatus === 404 || error.response?.status === 404) { + //Ignore this case since not all secret stores have mappings + } else { + throw new FrodoError( + `Error reading secret store mappings for the secret store '${secretStoreId}'`, + error + ); + } + } +} + +/** + * Export a single secret store by id. The response can be saved to file as is. + * @param {string} secretStoreId Secret store id + * @param {boolean} globalConfig true if global secret store is the target of the operation, false otherwise. Default: false. + * @returns {Promise} Promise resolving to a SecretStoreExportInterface object. + */ +export async function exportSecretStore({ + secretStoreId, + globalConfig = false, + state, +}: { + secretStoreId: string; + globalConfig: boolean; + state: State; +}): Promise { + try { + const secretStore = (await readSecretStore({ + secretStoreId, + globalConfig, + state, + })) as SecretStoreExportSkeleton; + secretStore.mappings = await readSecretStoreMappings({ + secretStoreId, + secretStoreTypeId: secretStore._type._id, + globalConfig, + state, + }); + const exportData = createSecretStoreExportTemplate({ state }); + exportData.secretstore[secretStoreId] = + secretStore as SecretStoreExportSkeleton; + return exportData; + } catch (error) { + throw new FrodoError( + `Error exporting secret store ${secretStoreId}`, + error + ); + } +} + +/** + * Export all secret stores. The response can be saved to file as is. + * @param {boolean} globalConfig true if global secret stores are the target of the operation, false otherwise. Default: false. + * @returns {Promise} Promise resolving to a SecretStoreExportInterface object. + */ +export async function exportSecretStores({ + globalConfig = false, + state, +}: { + globalConfig: boolean; + state: State; +}): Promise { + let indicatorId: string; + try { + debugMessage({ + message: `SecretStoreOps.exportSecretStores: start`, + state, + }); + const exportData = createSecretStoreExportTemplate({ state }); + const secretStores = await readSecretStores({ globalConfig, state }); + indicatorId = createProgressIndicator({ + total: secretStores.length, + message: 'Exporting secret stores...', + state, + }); + for (const secretStore of secretStores) { + updateProgressIndicator({ + id: indicatorId, + message: `Exporting secret store ${secretStore._id}`, + state, + }); + try { + secretStore.mappings = await readSecretStoreMappings({ + secretStoreId: secretStore._id, + secretStoreTypeId: secretStore._type._id, + globalConfig, + state, + }); + } catch (e) { + printMessage({ + message: `Unable to export mapping for secret store with id '${secretStore._id}': ${e.message}`, + type: 'error', + state, + }); + } + exportData.secretstore[secretStore._id] = + secretStore as SecretStoreExportSkeleton; + } + stopProgressIndicator({ + id: indicatorId, + message: `Exported ${secretStores.length} secret stores.`, + state, + }); + debugMessage({ message: `SecretStoreOps.exportSecretStores: end`, state }); + return exportData; + } catch (error) { + stopProgressIndicator({ + id: indicatorId, + message: `Error exporting secret stores.`, + status: 'fail', + state, + }); + throw new FrodoError(`Error reading secret stores`, error); + } +} + +/** + * Update secret store + * @param {SecretStoreSkeleton} secretStoreData secret store to import + * @param {boolean} globalConfig true if the secret store is global, false otherwise. Default: false. + * @returns {Promise} a promise that resolves to a secret store object + */ +export async function updateSecretStore({ + secretStoreData, + globalConfig, + state, +}: { + secretStoreData: SecretStoreSkeleton; + globalConfig: boolean; + state: State; +}): Promise { + return putSecretStore({ + secretStoreData, + globalConfig, + state, + }); +} + +/** + * Update secret store mapping + * @param {string} secretStoreId Secret store id + * @param {string} secretStoreTypeId Secret store type id + * @param {SecretStoreMappingSkeleton} secretStoreMappingData secret store mapping to import + * @param {boolean} globalConfig true if the secret store mapping is global, false otherwise. Default: false. + * @returns {Promise} a promise that resolves to a secret store mapping object + */ +export async function updateSecretStoreMapping({ + secretStoreId, + secretStoreTypeId, + secretStoreMappingData, + globalConfig, + state, +}: { + secretStoreId: string; + secretStoreTypeId: string; + secretStoreMappingData: SecretStoreMappingSkeleton; + globalConfig: boolean; + state: State; +}): Promise { + return putSecretStoreMapping({ + secretStoreId, + secretStoreTypeId, + secretStoreMappingData, + globalConfig, + state, + }); +} +/** + * Import secret stores and mappings + * @param {SecretStoreExportInterface} importData secret store import data + * @param {boolean} globalConfig true if the secret store mapping is global, false otherwise. Default: false. + * @param {string} secretStoreId optional secret store id. If supplied, only the secret store of that id is imported. + * @returns {Promise} the imported secret stores and mappings + */ +export async function importSecretStores({ + importData, + globalConfig, + secretStoreId, + state, +}: { + importData: SecretStoreExportInterface; + globalConfig: boolean; + secretStoreId?: string; + state: State; +}): Promise { + const errors = []; + try { + debugMessage({ + message: `SecretStoreOps.importSecretStores: start`, + state, + }); + const response = []; + for (const secretStore of Object.values(importData.secretstore)) { + try { + if (secretStoreId && secretStore._id !== secretStoreId) { + continue; + } + let mappings; + if (secretStore.mappings) { + mappings = []; + for (const mapping of secretStore.mappings) { + mappings.push( + updateSecretStoreMapping({ + secretStoreId: secretStore._id, + secretStoreTypeId: secretStore._type._id, + secretStoreMappingData: mapping, + globalConfig, + state, + }) + ); + } + mappings = await Promise.all(mappings); + } + delete secretStore.mappings; + const result = await updateSecretStore({ + secretStoreData: secretStore, + globalConfig, + state, + }); + result.mappings = mappings; + response.push(result); + } catch (error) { + errors.push(error); + } + } + if (errors.length > 0) { + throw new FrodoError(`Error importing secret stores`, errors); + } + debugMessage({ message: `SecretStoreOps.importSecretStores: end`, state }); + return response; + } catch (error) { + // re-throw previously caught errors + if (errors.length > 0) { + throw error; + } + throw new FrodoError(`Error importing secret stores`, error); + } +} diff --git a/src/test/mock-recordings/SecretStoreOps_2115179242/exportSecretStores_2218839234/1-Export-realm-SecretStores_100994395/recording.har b/src/test/mock-recordings/SecretStoreOps_2115179242/exportSecretStores_2218839234/1-Export-realm-SecretStores_100994395/recording.har new file mode 100644 index 00000000..d46ce44d --- /dev/null +++ b/src/test/mock-recordings/SecretStoreOps_2115179242/exportSecretStores_2218839234/1-Export-realm-SecretStores_100994395/recording.har @@ -0,0 +1,150 @@ +{ + "log": { + "_recordingName": "SecretStoreOps/exportSecretStores()/1: Export realm SecretStores", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "6baad0bba4f335062a535223ebb6dd9f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/2.0.3" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-a2dfc818-3386-45b1-a59e-2b70074f5e94" + }, + { + "name": "accept-api-version", + "value": "protocol=2.0,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.classic.com:8080" + } + ], + "headersSize": 591, + "httpVersion": "HTTP/1.1", + "method": "POST", + "queryString": [ + { + "name": "_action", + "value": "nextdescendents" + } + ], + "url": "http://openam-frodo-dev.classic.com:8080/am/json/realms/root/realm-config/secrets/stores?_action=nextdescendents" + }, + "response": { + "bodySize": 13, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 13, + "text": "{\"result\":[]}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "13" + }, + { + "name": "date", + "value": "Thu, 15 Aug 2024 18:35:37 GMT" + }, + { + "name": "keep-alive", + "value": "timeout=20" + }, + { + "name": "connection", + "value": "keep-alive" + } + ], + "headersSize": 464, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2024-08-15T18:35:37.477Z", + "time": 18, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 18 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/src/test/mock-recordings/SecretStoreOps_2115179242/exportSecretStores_2218839234/2-Export-global-SecretStores_2554154006/recording.har b/src/test/mock-recordings/SecretStoreOps_2115179242/exportSecretStores_2218839234/2-Export-global-SecretStores_2554154006/recording.har new file mode 100644 index 00000000..32dbf328 --- /dev/null +++ b/src/test/mock-recordings/SecretStoreOps_2115179242/exportSecretStores_2218839234/2-Export-global-SecretStores_2554154006/recording.har @@ -0,0 +1,558 @@ +{ + "log": { + "_recordingName": "SecretStoreOps/exportSecretStores()/2: Export global SecretStores", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "c6d303acc9dfe3da7b43bb1f201d83d1", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/2.0.3" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-a2dfc818-3386-45b1-a59e-2b70074f5e94" + }, + { + "name": "accept-api-version", + "value": "protocol=2.0,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.classic.com:8080" + } + ], + "headersSize": 580, + "httpVersion": "HTTP/1.1", + "method": "POST", + "queryString": [ + { + "name": "_action", + "value": "nextdescendents" + } + ], + "url": "http://openam-frodo-dev.classic.com:8080/am/json/global-config/secrets/stores?_action=nextdescendents" + }, + "response": { + "bodySize": 723, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 723, + "text": "{\"result\":[{\"storePassword\":\"storepass\",\"providerName\":\"SunJCE\",\"file\":\"/home/prestonhales/am/security/keystores/keystore.jceks\",\"storetype\":\"JCEKS\",\"leaseExpiryDuration\":5,\"keyEntryPassword\":\"entrypass\",\"_id\":\"default-keystore\",\"_type\":{\"_id\":\"KeyStoreSecretStore\",\"name\":\"Keystore\",\"collection\":true}},{\"directory\":\"/home/prestonhales/am/security/secrets/encrypted\",\"format\":\"ENCRYPTED_PLAIN\",\"_id\":\"default-passwords-store\",\"_type\":{\"_id\":\"FileSystemSecretStore\",\"name\":\"File System Secret Volumes\",\"collection\":true}},{\"format\":\"BASE64\",\"_id\":\"EnvironmentAndSystemPropertySecretStore\",\"_type\":{\"_id\":\"EnvironmentAndSystemPropertySecretStore\",\"name\":\"Environment and System Property Secrets Store\",\"collection\":false}}]}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "723" + }, + { + "name": "date", + "value": "Thu, 15 Aug 2024 18:35:37 GMT" + }, + { + "name": "keep-alive", + "value": "timeout=20" + }, + { + "name": "connection", + "value": "keep-alive" + } + ], + "headersSize": 465, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2024-08-15T18:35:37.516Z", + "time": 10, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 10 + } + }, + { + "_id": "7b0a9b322d1263a64d7a14c13f9a91ec", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/2.0.3" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-a2dfc818-3386-45b1-a59e-2b70074f5e94" + }, + { + "name": "accept-api-version", + "value": "protocol=2.0,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.classic.com:8080" + } + ], + "headersSize": 619, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "_queryFilter", + "value": "true" + } + ], + "url": "http://openam-frodo-dev.classic.com:8080/am/json/global-config/secrets/stores/KeyStoreSecretStore/default-keystore/mappings?_queryFilter=true" + }, + "response": { + "bodySize": 9388, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 9388, + "text": "{\"result\":[{\"_id\":\"am.applications.agents.remote.consent.request.signing.ES256\",\"_rev\":\"1192664276\",\"secretId\":\"am.applications.agents.remote.consent.request.signing.ES256\",\"aliases\":[\"es256test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.applications.agents.remote.consent.request.signing.ES384\",\"_rev\":\"288173840\",\"secretId\":\"am.applications.agents.remote.consent.request.signing.ES384\",\"aliases\":[\"es384test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.applications.agents.remote.consent.request.signing.ES512\",\"_rev\":\"-294942577\",\"secretId\":\"am.applications.agents.remote.consent.request.signing.ES512\",\"aliases\":[\"es512test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.applications.agents.remote.consent.request.signing.RSA\",\"_rev\":\"1911324886\",\"secretId\":\"am.applications.agents.remote.consent.request.signing.RSA\",\"aliases\":[\"rsajwtsigningkey\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.authentication.nodes.persistentcookie.encryption\",\"_rev\":\"-91845293\",\"secretId\":\"am.authentication.nodes.persistentcookie.encryption\",\"aliases\":[\"test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.authn.authid.signing.HMAC\",\"_rev\":\"934473037\",\"secretId\":\"am.authn.authid.signing.HMAC\",\"aliases\":[\"hmacsigningtest\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.authn.trees.transientstate.encryption\",\"_rev\":\"1917709756\",\"secretId\":\"am.authn.trees.transientstate.encryption\",\"aliases\":[\"directenctest\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.default.applications.federation.entity.providers.saml2.idp.encryption\",\"_rev\":\"1907232131\",\"secretId\":\"am.default.applications.federation.entity.providers.saml2.idp.encryption\",\"aliases\":[\"test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.default.applications.federation.entity.providers.saml2.idp.signing\",\"_rev\":\"1976286662\",\"secretId\":\"am.default.applications.federation.entity.providers.saml2.idp.signing\",\"aliases\":[\"rsajwtsigningkey\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.default.applications.federation.entity.providers.saml2.sp.encryption\",\"_rev\":\"1974801991\",\"secretId\":\"am.default.applications.federation.entity.providers.saml2.sp.encryption\",\"aliases\":[\"test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.default.applications.federation.entity.providers.saml2.sp.signing\",\"_rev\":\"-86805022\",\"secretId\":\"am.default.applications.federation.entity.providers.saml2.sp.signing\",\"aliases\":[\"rsajwtsigningkey\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.default.authentication.modules.persistentcookie.encryption\",\"_rev\":\"-239710853\",\"secretId\":\"am.default.authentication.modules.persistentcookie.encryption\",\"aliases\":[\"test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.default.authentication.modules.persistentcookie.signing\",\"_rev\":\"1188815885\",\"secretId\":\"am.default.authentication.modules.persistentcookie.signing\",\"aliases\":[\"hmacsigningtest\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.default.authentication.nodes.persistentcookie.signing\",\"_rev\":\"986410257\",\"secretId\":\"am.default.authentication.nodes.persistentcookie.signing\",\"aliases\":[\"hmacsigningtest\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.global.services.oauth2.oidc.agent.idtoken.signing\",\"_rev\":\"-122487018\",\"secretId\":\"am.global.services.oauth2.oidc.agent.idtoken.signing\",\"aliases\":[\"rsajwtsigningkey\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.global.services.saml2.client.storage.jwt.encryption\",\"_rev\":\"2003184760\",\"secretId\":\"am.global.services.saml2.client.storage.jwt.encryption\",\"aliases\":[\"directenctest\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.global.services.session.clientbased.encryption.AES\",\"_rev\":\"599325994\",\"secretId\":\"am.global.services.session.clientbased.encryption.AES\",\"aliases\":[\"aestest\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.global.services.session.clientbased.signing.HMAC\",\"_rev\":\"952853781\",\"secretId\":\"am.global.services.session.clientbased.signing.HMAC\",\"aliases\":[\"hmacsigningtest\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.iot.jwt.issuer.signing\",\"_rev\":\"-1095047595\",\"secretId\":\"am.services.iot.jwt.issuer.signing\",\"aliases\":[\"hmacsigningtest\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.jwt.authenticity.signing\",\"_rev\":\"-1210340267\",\"secretId\":\"am.services.oauth2.jwt.authenticity.signing\",\"aliases\":[\"hmacsigningtest\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.oidc.decryption.RSA.OAEP\",\"_rev\":\"-75049409\",\"secretId\":\"am.services.oauth2.oidc.decryption.RSA.OAEP\",\"aliases\":[\"test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.oidc.decryption.RSA.OAEP.256\",\"_rev\":\"-108687993\",\"secretId\":\"am.services.oauth2.oidc.decryption.RSA.OAEP.256\",\"aliases\":[\"test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.oidc.decryption.RSA1.5\",\"_rev\":\"2073465911\",\"secretId\":\"am.services.oauth2.oidc.decryption.RSA1.5\",\"aliases\":[\"test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.oidc.rp.idtoken.encryption\",\"_rev\":\"2025247879\",\"secretId\":\"am.services.oauth2.oidc.rp.idtoken.encryption\",\"aliases\":[\"test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.oidc.rp.jwt.authenticity.signing\",\"_rev\":\"-152865330\",\"secretId\":\"am.services.oauth2.oidc.rp.jwt.authenticity.signing\",\"aliases\":[\"rsajwtsigningkey\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.oidc.signing.ES256\",\"_rev\":\"1010246364\",\"secretId\":\"am.services.oauth2.oidc.signing.ES256\",\"aliases\":[\"es256test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.oidc.signing.ES384\",\"_rev\":\"105751800\",\"secretId\":\"am.services.oauth2.oidc.signing.ES384\",\"aliases\":[\"es384test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.oidc.signing.ES512\",\"_rev\":\"-477362537\",\"secretId\":\"am.services.oauth2.oidc.signing.ES512\",\"aliases\":[\"es512test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.oidc.signing.RSA\",\"_rev\":\"2112649438\",\"secretId\":\"am.services.oauth2.oidc.signing.RSA\",\"aliases\":[\"rsajwtsigningkey\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.remote.consent.request.encryption\",\"_rev\":\"1156224168\",\"secretId\":\"am.services.oauth2.remote.consent.request.encryption\",\"aliases\":[\"selfserviceenctest\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.remote.consent.response.decryption\",\"_rev\":\"2022034763\",\"secretId\":\"am.services.oauth2.remote.consent.response.decryption\",\"aliases\":[\"test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.remote.consent.response.signing.RSA\",\"_rev\":\"-219924262\",\"secretId\":\"am.services.oauth2.remote.consent.response.signing.RSA\",\"aliases\":[\"rsajwtsigningkey\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.stateless.signing.ES256\",\"_rev\":\"1077337120\",\"secretId\":\"am.services.oauth2.stateless.signing.ES256\",\"aliases\":[\"es256test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.stateless.signing.ES384\",\"_rev\":\"172846524\",\"secretId\":\"am.services.oauth2.stateless.signing.ES384\",\"aliases\":[\"es384test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.stateless.signing.ES512\",\"_rev\":\"-410267929\",\"secretId\":\"am.services.oauth2.stateless.signing.ES512\",\"aliases\":[\"es512test\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.stateless.signing.HMAC\",\"_rev\":\"-1093456131\",\"secretId\":\"am.services.oauth2.stateless.signing.HMAC\",\"aliases\":[\"hmacsigningtest\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.stateless.signing.RSA\",\"_rev\":\"1960097294\",\"secretId\":\"am.services.oauth2.stateless.signing.RSA\",\"aliases\":[\"rsajwtsigningkey\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.oauth2.stateless.token.encryption\",\"_rev\":\"1900916088\",\"secretId\":\"am.services.oauth2.stateless.token.encryption\",\"aliases\":[\"directenctest\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.saml2.metadata.signing.RSA\",\"_rev\":\"2008235726\",\"secretId\":\"am.services.saml2.metadata.signing.RSA\",\"aliases\":[\"rsajwtsigningkey\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}},{\"_id\":\"am.services.uma.pct.encryption\",\"_rev\":\"1883661748\",\"secretId\":\"am.services.uma.pct.encryption\",\"aliases\":[\"directenctest\"],\"_type\":{\"_id\":\"mappings\",\"name\":\"Mappings\",\"collection\":true}}],\"resultCount\":40,\"pagedResultsCookie\":null,\"totalPagedResultsPolicy\":\"NONE\",\"totalPagedResults\":-1,\"remainingPagedResults\":-1}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "protocol=2.0,resource=1.0, resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "transfer-encoding", + "value": "chunked" + }, + { + "name": "date", + "value": "Thu, 15 Aug 2024 18:35:37 GMT" + }, + { + "name": "keep-alive", + "value": "timeout=20" + }, + { + "name": "connection", + "value": "keep-alive" + } + ], + "headersSize": 499, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2024-08-15T18:35:37.536Z", + "time": 48, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 48 + } + }, + { + "_id": "a849040f5abdab05d9c89abc330f4e11", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/2.0.3" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-a2dfc818-3386-45b1-a59e-2b70074f5e94" + }, + { + "name": "accept-api-version", + "value": "protocol=2.0,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.classic.com:8080" + } + ], + "headersSize": 628, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "_queryFilter", + "value": "true" + } + ], + "url": "http://openam-frodo-dev.classic.com:8080/am/json/global-config/secrets/stores/FileSystemSecretStore/default-passwords-store/mappings?_queryFilter=true" + }, + "response": { + "bodySize": 99, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 99, + "text": "{\"code\":404,\"reason\":\"Not Found\",\"message\":\"Resource 'default-passwords-store/mappings' not found\"}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "99" + }, + { + "name": "date", + "value": "Thu, 15 Aug 2024 18:35:37 GMT" + }, + { + "name": "keep-alive", + "value": "timeout=20" + }, + { + "name": "connection", + "value": "keep-alive" + } + ], + "headersSize": 464, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 404, + "statusText": "Not Found" + }, + "startedDateTime": "2024-08-15T18:35:37.591Z", + "time": 4, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 4 + } + }, + { + "_id": "eebc5f870cfc1afef69c42fafb3efd16", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/2.0.3" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-a2dfc818-3386-45b1-a59e-2b70074f5e94" + }, + { + "name": "accept-api-version", + "value": "protocol=2.0,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.classic.com:8080" + } + ], + "headersSize": 662, + "httpVersion": "HTTP/1.1", + "method": "GET", + "queryString": [ + { + "name": "_queryFilter", + "value": "true" + } + ], + "url": "http://openam-frodo-dev.classic.com:8080/am/json/global-config/secrets/stores/EnvironmentAndSystemPropertySecretStore/EnvironmentAndSystemPropertySecretStore/mappings?_queryFilter=true" + }, + "response": { + "bodySize": 115, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 115, + "text": "{\"code\":404,\"reason\":\"Not Found\",\"message\":\"Resource 'EnvironmentAndSystemPropertySecretStore/mappings' not found\"}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "115" + }, + { + "name": "date", + "value": "Thu, 15 Aug 2024 18:35:37 GMT" + }, + { + "name": "keep-alive", + "value": "timeout=20" + }, + { + "name": "connection", + "value": "keep-alive" + } + ], + "headersSize": 465, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 404, + "statusText": "Not Found" + }, + "startedDateTime": "2024-08-15T18:35:37.610Z", + "time": 4, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 4 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/src/test/mock-recordings/SecretStoreOps_2115179242/readSecretStores_3885400800/1-Read-realm-SecretStores_1859803097/recording.har b/src/test/mock-recordings/SecretStoreOps_2115179242/readSecretStores_3885400800/1-Read-realm-SecretStores_1859803097/recording.har new file mode 100644 index 00000000..b4760f9f --- /dev/null +++ b/src/test/mock-recordings/SecretStoreOps_2115179242/readSecretStores_3885400800/1-Read-realm-SecretStores_1859803097/recording.har @@ -0,0 +1,150 @@ +{ + "log": { + "_recordingName": "SecretStoreOps/readSecretStores()/1: Read realm SecretStores", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "6baad0bba4f335062a535223ebb6dd9f", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/2.0.3" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-a2dfc818-3386-45b1-a59e-2b70074f5e94" + }, + { + "name": "accept-api-version", + "value": "protocol=2.0,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.classic.com:8080" + } + ], + "headersSize": 591, + "httpVersion": "HTTP/1.1", + "method": "POST", + "queryString": [ + { + "name": "_action", + "value": "nextdescendents" + } + ], + "url": "http://openam-frodo-dev.classic.com:8080/am/json/realms/root/realm-config/secrets/stores?_action=nextdescendents" + }, + "response": { + "bodySize": 13, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 13, + "text": "{\"result\":[]}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "13" + }, + { + "name": "date", + "value": "Thu, 15 Aug 2024 18:35:37 GMT" + }, + { + "name": "keep-alive", + "value": "timeout=20" + }, + { + "name": "connection", + "value": "keep-alive" + } + ], + "headersSize": 464, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2024-08-15T18:35:37.397Z", + "time": 26, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 26 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/src/test/mock-recordings/SecretStoreOps_2115179242/readSecretStores_3885400800/2-Read-global-SecretStores_3480416460/recording.har b/src/test/mock-recordings/SecretStoreOps_2115179242/readSecretStores_3885400800/2-Read-global-SecretStores_3480416460/recording.har new file mode 100644 index 00000000..0a574ef2 --- /dev/null +++ b/src/test/mock-recordings/SecretStoreOps_2115179242/readSecretStores_3885400800/2-Read-global-SecretStores_3480416460/recording.har @@ -0,0 +1,150 @@ +{ + "log": { + "_recordingName": "SecretStoreOps/readSecretStores()/2: Read global SecretStores", + "creator": { + "comment": "persister:fs", + "name": "Polly.JS", + "version": "6.0.6" + }, + "entries": [ + { + "_id": "c6d303acc9dfe3da7b43bb1f201d83d1", + "_order": 0, + "cache": {}, + "request": { + "bodySize": 0, + "cookies": [], + "headers": [ + { + "name": "accept", + "value": "application/json, text/plain, */*" + }, + { + "name": "content-type", + "value": "application/json" + }, + { + "name": "user-agent", + "value": "@rockcarver/frodo-lib/2.0.3" + }, + { + "name": "x-forgerock-transactionid", + "value": "frodo-a2dfc818-3386-45b1-a59e-2b70074f5e94" + }, + { + "name": "accept-api-version", + "value": "protocol=2.0,resource=1.0" + }, + { + "name": "cookie", + "value": "iPlanetDirectoryPro=" + }, + { + "name": "accept-encoding", + "value": "gzip, compress, deflate, br" + }, + { + "name": "host", + "value": "openam-frodo-dev.classic.com:8080" + } + ], + "headersSize": 580, + "httpVersion": "HTTP/1.1", + "method": "POST", + "queryString": [ + { + "name": "_action", + "value": "nextdescendents" + } + ], + "url": "http://openam-frodo-dev.classic.com:8080/am/json/global-config/secrets/stores?_action=nextdescendents" + }, + "response": { + "bodySize": 723, + "content": { + "mimeType": "application/json;charset=UTF-8", + "size": 723, + "text": "{\"result\":[{\"storePassword\":\"storepass\",\"providerName\":\"SunJCE\",\"file\":\"/home/prestonhales/am/security/keystores/keystore.jceks\",\"storetype\":\"JCEKS\",\"leaseExpiryDuration\":5,\"keyEntryPassword\":\"entrypass\",\"_id\":\"default-keystore\",\"_type\":{\"_id\":\"KeyStoreSecretStore\",\"name\":\"Keystore\",\"collection\":true}},{\"directory\":\"/home/prestonhales/am/security/secrets/encrypted\",\"format\":\"ENCRYPTED_PLAIN\",\"_id\":\"default-passwords-store\",\"_type\":{\"_id\":\"FileSystemSecretStore\",\"name\":\"File System Secret Volumes\",\"collection\":true}},{\"format\":\"BASE64\",\"_id\":\"EnvironmentAndSystemPropertySecretStore\",\"_type\":{\"_id\":\"EnvironmentAndSystemPropertySecretStore\",\"name\":\"Environment and System Property Secrets Store\",\"collection\":false}}]}" + }, + "cookies": [], + "headers": [ + { + "name": "x-frame-options", + "value": "SAMEORIGIN" + }, + { + "name": "x-content-type-options", + "value": "nosniff" + }, + { + "name": "cache-control", + "value": "private" + }, + { + "name": "content-api-version", + "value": "resource=1.0" + }, + { + "name": "content-security-policy", + "value": "default-src 'none';frame-ancestors 'none';sandbox" + }, + { + "name": "cross-origin-opener-policy", + "value": "same-origin" + }, + { + "name": "cross-origin-resource-policy", + "value": "same-origin" + }, + { + "name": "expires", + "value": "0" + }, + { + "name": "pragma", + "value": "no-cache" + }, + { + "name": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "name": "content-length", + "value": "723" + }, + { + "name": "date", + "value": "Thu, 15 Aug 2024 18:35:37 GMT" + }, + { + "name": "keep-alive", + "value": "timeout=20" + }, + { + "name": "connection", + "value": "keep-alive" + } + ], + "headersSize": 465, + "httpVersion": "HTTP/1.1", + "redirectURL": "", + "status": 200, + "statusText": "OK" + }, + "startedDateTime": "2024-08-15T18:35:37.441Z", + "time": 19, + "timings": { + "blocked": -1, + "connect": -1, + "dns": -1, + "receive": 0, + "send": 0, + "ssl": -1, + "wait": 19 + } + } + ], + "pages": [], + "version": "1.2" + } +} diff --git a/src/test/snapshots/ops/classic/SecretStoreOps.test.js.snap b/src/test/snapshots/ops/classic/SecretStoreOps.test.js.snap new file mode 100644 index 00000000..3f8b309f --- /dev/null +++ b/src/test/snapshots/ops/classic/SecretStoreOps.test.js.snap @@ -0,0 +1,620 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SecretStoreOps createSecretStoreExportTemplate() 1: Create SecretStore Export Template 1`] = ` +{ + "meta": Any, + "secretstore": {}, +} +`; + +exports[`SecretStoreOps exportSecretStores() 1: Export realm SecretStores 1`] = ` +{ + "meta": Any, + "secretstore": {}, +} +`; + +exports[`SecretStoreOps exportSecretStores() 2: Export global SecretStores 1`] = ` +{ + "meta": Any, + "secretstore": { + "EnvironmentAndSystemPropertySecretStore": { + "_id": "EnvironmentAndSystemPropertySecretStore", + "_type": { + "_id": "EnvironmentAndSystemPropertySecretStore", + "collection": false, + "name": "Environment and System Property Secrets Store", + }, + "format": "BASE64", + "mappings": undefined, + }, + "default-keystore": { + "_id": "default-keystore", + "_type": { + "_id": "KeyStoreSecretStore", + "collection": true, + "name": "Keystore", + }, + "file": "/home/prestonhales/am/security/keystores/keystore.jceks", + "keyEntryPassword": "entrypass", + "leaseExpiryDuration": 5, + "mappings": [ + { + "_id": "am.applications.agents.remote.consent.request.signing.ES256", + "_rev": "1192664276", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "es256test", + ], + "secretId": "am.applications.agents.remote.consent.request.signing.ES256", + }, + { + "_id": "am.applications.agents.remote.consent.request.signing.ES384", + "_rev": "288173840", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "es384test", + ], + "secretId": "am.applications.agents.remote.consent.request.signing.ES384", + }, + { + "_id": "am.applications.agents.remote.consent.request.signing.ES512", + "_rev": "-294942577", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "es512test", + ], + "secretId": "am.applications.agents.remote.consent.request.signing.ES512", + }, + { + "_id": "am.applications.agents.remote.consent.request.signing.RSA", + "_rev": "1911324886", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "rsajwtsigningkey", + ], + "secretId": "am.applications.agents.remote.consent.request.signing.RSA", + }, + { + "_id": "am.authentication.nodes.persistentcookie.encryption", + "_rev": "-91845293", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "test", + ], + "secretId": "am.authentication.nodes.persistentcookie.encryption", + }, + { + "_id": "am.authn.authid.signing.HMAC", + "_rev": "934473037", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "hmacsigningtest", + ], + "secretId": "am.authn.authid.signing.HMAC", + }, + { + "_id": "am.authn.trees.transientstate.encryption", + "_rev": "1917709756", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "directenctest", + ], + "secretId": "am.authn.trees.transientstate.encryption", + }, + { + "_id": "am.default.applications.federation.entity.providers.saml2.idp.encryption", + "_rev": "1907232131", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "test", + ], + "secretId": "am.default.applications.federation.entity.providers.saml2.idp.encryption", + }, + { + "_id": "am.default.applications.federation.entity.providers.saml2.idp.signing", + "_rev": "1976286662", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "rsajwtsigningkey", + ], + "secretId": "am.default.applications.federation.entity.providers.saml2.idp.signing", + }, + { + "_id": "am.default.applications.federation.entity.providers.saml2.sp.encryption", + "_rev": "1974801991", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "test", + ], + "secretId": "am.default.applications.federation.entity.providers.saml2.sp.encryption", + }, + { + "_id": "am.default.applications.federation.entity.providers.saml2.sp.signing", + "_rev": "-86805022", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "rsajwtsigningkey", + ], + "secretId": "am.default.applications.federation.entity.providers.saml2.sp.signing", + }, + { + "_id": "am.default.authentication.modules.persistentcookie.encryption", + "_rev": "-239710853", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "test", + ], + "secretId": "am.default.authentication.modules.persistentcookie.encryption", + }, + { + "_id": "am.default.authentication.modules.persistentcookie.signing", + "_rev": "1188815885", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "hmacsigningtest", + ], + "secretId": "am.default.authentication.modules.persistentcookie.signing", + }, + { + "_id": "am.default.authentication.nodes.persistentcookie.signing", + "_rev": "986410257", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "hmacsigningtest", + ], + "secretId": "am.default.authentication.nodes.persistentcookie.signing", + }, + { + "_id": "am.global.services.oauth2.oidc.agent.idtoken.signing", + "_rev": "-122487018", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "rsajwtsigningkey", + ], + "secretId": "am.global.services.oauth2.oidc.agent.idtoken.signing", + }, + { + "_id": "am.global.services.saml2.client.storage.jwt.encryption", + "_rev": "2003184760", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "directenctest", + ], + "secretId": "am.global.services.saml2.client.storage.jwt.encryption", + }, + { + "_id": "am.global.services.session.clientbased.encryption.AES", + "_rev": "599325994", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "aestest", + ], + "secretId": "am.global.services.session.clientbased.encryption.AES", + }, + { + "_id": "am.global.services.session.clientbased.signing.HMAC", + "_rev": "952853781", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "hmacsigningtest", + ], + "secretId": "am.global.services.session.clientbased.signing.HMAC", + }, + { + "_id": "am.services.iot.jwt.issuer.signing", + "_rev": "-1095047595", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "hmacsigningtest", + ], + "secretId": "am.services.iot.jwt.issuer.signing", + }, + { + "_id": "am.services.oauth2.jwt.authenticity.signing", + "_rev": "-1210340267", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "hmacsigningtest", + ], + "secretId": "am.services.oauth2.jwt.authenticity.signing", + }, + { + "_id": "am.services.oauth2.oidc.decryption.RSA.OAEP", + "_rev": "-75049409", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "test", + ], + "secretId": "am.services.oauth2.oidc.decryption.RSA.OAEP", + }, + { + "_id": "am.services.oauth2.oidc.decryption.RSA.OAEP.256", + "_rev": "-108687993", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "test", + ], + "secretId": "am.services.oauth2.oidc.decryption.RSA.OAEP.256", + }, + { + "_id": "am.services.oauth2.oidc.decryption.RSA1.5", + "_rev": "2073465911", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "test", + ], + "secretId": "am.services.oauth2.oidc.decryption.RSA1.5", + }, + { + "_id": "am.services.oauth2.oidc.rp.idtoken.encryption", + "_rev": "2025247879", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "test", + ], + "secretId": "am.services.oauth2.oidc.rp.idtoken.encryption", + }, + { + "_id": "am.services.oauth2.oidc.rp.jwt.authenticity.signing", + "_rev": "-152865330", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "rsajwtsigningkey", + ], + "secretId": "am.services.oauth2.oidc.rp.jwt.authenticity.signing", + }, + { + "_id": "am.services.oauth2.oidc.signing.ES256", + "_rev": "1010246364", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "es256test", + ], + "secretId": "am.services.oauth2.oidc.signing.ES256", + }, + { + "_id": "am.services.oauth2.oidc.signing.ES384", + "_rev": "105751800", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "es384test", + ], + "secretId": "am.services.oauth2.oidc.signing.ES384", + }, + { + "_id": "am.services.oauth2.oidc.signing.ES512", + "_rev": "-477362537", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "es512test", + ], + "secretId": "am.services.oauth2.oidc.signing.ES512", + }, + { + "_id": "am.services.oauth2.oidc.signing.RSA", + "_rev": "2112649438", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "rsajwtsigningkey", + ], + "secretId": "am.services.oauth2.oidc.signing.RSA", + }, + { + "_id": "am.services.oauth2.remote.consent.request.encryption", + "_rev": "1156224168", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "selfserviceenctest", + ], + "secretId": "am.services.oauth2.remote.consent.request.encryption", + }, + { + "_id": "am.services.oauth2.remote.consent.response.decryption", + "_rev": "2022034763", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "test", + ], + "secretId": "am.services.oauth2.remote.consent.response.decryption", + }, + { + "_id": "am.services.oauth2.remote.consent.response.signing.RSA", + "_rev": "-219924262", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "rsajwtsigningkey", + ], + "secretId": "am.services.oauth2.remote.consent.response.signing.RSA", + }, + { + "_id": "am.services.oauth2.stateless.signing.ES256", + "_rev": "1077337120", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "es256test", + ], + "secretId": "am.services.oauth2.stateless.signing.ES256", + }, + { + "_id": "am.services.oauth2.stateless.signing.ES384", + "_rev": "172846524", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "es384test", + ], + "secretId": "am.services.oauth2.stateless.signing.ES384", + }, + { + "_id": "am.services.oauth2.stateless.signing.ES512", + "_rev": "-410267929", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "es512test", + ], + "secretId": "am.services.oauth2.stateless.signing.ES512", + }, + { + "_id": "am.services.oauth2.stateless.signing.HMAC", + "_rev": "-1093456131", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "hmacsigningtest", + ], + "secretId": "am.services.oauth2.stateless.signing.HMAC", + }, + { + "_id": "am.services.oauth2.stateless.signing.RSA", + "_rev": "1960097294", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "rsajwtsigningkey", + ], + "secretId": "am.services.oauth2.stateless.signing.RSA", + }, + { + "_id": "am.services.oauth2.stateless.token.encryption", + "_rev": "1900916088", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "directenctest", + ], + "secretId": "am.services.oauth2.stateless.token.encryption", + }, + { + "_id": "am.services.saml2.metadata.signing.RSA", + "_rev": "2008235726", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "rsajwtsigningkey", + ], + "secretId": "am.services.saml2.metadata.signing.RSA", + }, + { + "_id": "am.services.uma.pct.encryption", + "_rev": "1883661748", + "_type": { + "_id": "mappings", + "collection": true, + "name": "Mappings", + }, + "aliases": [ + "directenctest", + ], + "secretId": "am.services.uma.pct.encryption", + }, + ], + "providerName": "SunJCE", + "storePassword": "storepass", + "storetype": "JCEKS", + }, + "default-passwords-store": { + "_id": "default-passwords-store", + "_type": { + "_id": "FileSystemSecretStore", + "collection": true, + "name": "File System Secret Volumes", + }, + "directory": "/home/prestonhales/am/security/secrets/encrypted", + "format": "ENCRYPTED_PLAIN", + "mappings": undefined, + }, + }, +} +`; + +exports[`SecretStoreOps readSecretStores() 1: Read realm SecretStores 1`] = `[]`; + +exports[`SecretStoreOps readSecretStores() 2: Read global SecretStores 1`] = ` +[ + { + "_id": "default-keystore", + "_type": { + "_id": "KeyStoreSecretStore", + "collection": true, + "name": "Keystore", + }, + "file": "/home/prestonhales/am/security/keystores/keystore.jceks", + "keyEntryPassword": "entrypass", + "leaseExpiryDuration": 5, + "providerName": "SunJCE", + "storePassword": "storepass", + "storetype": "JCEKS", + }, + { + "_id": "default-passwords-store", + "_type": { + "_id": "FileSystemSecretStore", + "collection": true, + "name": "File System Secret Volumes", + }, + "directory": "/home/prestonhales/am/security/secrets/encrypted", + "format": "ENCRYPTED_PLAIN", + }, + { + "_id": "EnvironmentAndSystemPropertySecretStore", + "_type": { + "_id": "EnvironmentAndSystemPropertySecretStore", + "collection": false, + "name": "Environment and System Property Secrets Store", + }, + "format": "BASE64", + }, +] +`;