Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { frodo } from '@rockcarver/frodo-lib';
import { Option } from 'commander';

import { configManagerExportCustomNodes } from '../../../configManagerOps/FrConfigCustomNodesOps';
import { getTokens } from '../../../ops/AuthenticateOps';
import { verboseMessage } from '../../../utils/Console';
import { FrodoCommand } from '../../FrodoCommand';

const { CLOUD_DEPLOYMENT_TYPE_KEY, FORGEOPS_DEPLOYMENT_TYPE_KEY } =
frodo.utils.constants;

const deploymentTypes = [
CLOUD_DEPLOYMENT_TYPE_KEY,
FORGEOPS_DEPLOYMENT_TYPE_KEY,
];

export default function setup() {
const program = new FrodoCommand(
'frodo config-manager pull custom-nodes',
[],
deploymentTypes
);

program
.description('Export custom nodes.')
.addOption(
new Option(
'-n, --node-name <node-name>',
'Custom node display name. If specified, only one custom node is exported.'
)
)
.action(async (host, realm, user, password, options, command) => {
command.handleDefaultArgsAndOpts(
host,
realm,
user,
password,
options,
command
);

if (await getTokens(false, true, deploymentTypes)) {
if (options.nodeName) {
verboseMessage(
`Fetching custom node with name '${options.nodeName}'`
);
} else {
verboseMessage('Fetching custom nodes');
}
const outcome = await configManagerExportCustomNodes(options.nodeName);
if (!outcome) process.exitCode = 1;
} else {
process.exitCode = 1;
}
});

return program;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import ConnectorMappings from './config-manager-pull-connector-mappings';
import CookieDomains from './config-manager-pull-cookie-domains';
import CORS from './config-manager-pull-cors';
import CSP from './config-manager-pull-csp';
import CustomNodes from './config-manager-pull-custom-nodes';
import EmailProvider from './config-manager-pull-email-provider';
import EmailTemplates from './config-manager-pull-email-templates';
import Endpoints from './config-manager-pull-endpoints';
Expand Down Expand Up @@ -52,6 +53,7 @@ export default function setup() {
program.addCommand(CookieDomains().name('cookie-domains'));
program.addCommand(CORS().name('cors'));
program.addCommand(CSP().name('csp'));
program.addCommand(CustomNodes().name('custom-nodes'));
program.addCommand(EmailProvider().name('email-provider'));
program.addCommand(EmailTemplates().name('email-templates'));
program.addCommand(Endpoints().name('endpoints'));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { frodo } from '@rockcarver/frodo-lib';
import { Option } from 'commander';

import { configManagerImportAuthentication } from '../../../configManagerOps/FrConfigAuthenticationOps';
import { getTokens } from '../../../ops/AuthenticateOps';
import { printMessage, verboseMessage } from '../../../utils/Console';
import { FrodoCommand } from '../../FrodoCommand';

const { CLOUD_DEPLOYMENT_TYPE_KEY, FORGEOPS_DEPLOYMENT_TYPE_KEY } =
frodo.utils.constants;

const deploymentTypes = [
CLOUD_DEPLOYMENT_TYPE_KEY,
FORGEOPS_DEPLOYMENT_TYPE_KEY,
];

export default function setup() {
const program = new FrodoCommand(
'frodo config-manager push authentication',
[],
deploymentTypes
);

program
.description('Import authentication objects.')
.addOption(
new Option(
'-r, --realm <realm>',
'Specifies the realm to import from. Only the configuration from this realm will be imported.'
)
)
.action(async (host, realm, user, password, options, command) => {
command.handleDefaultArgsAndOpts(
host,
realm,
user,
password,
options,
command
);
if (await getTokens(false, true, deploymentTypes)) {
verboseMessage('Importing config entity authentication');
const outcome = await configManagerImportAuthentication(options.realm);
if (!outcome) process.exitCode = 1;
}
// unrecognized combination of options or no options
else {
printMessage(
'Unrecognized combination of options or no options...',
'error'
);
program.help();
process.exitCode = 1;
}
});

return program;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { frodo } from '@rockcarver/frodo-lib';
import { Option } from 'commander';

import { configManagerImportConnectors } from '../../../configManagerOps/FrConfigConnectorDefinitionsOps';
import { getTokens } from '../../../ops/AuthenticateOps';
import { verboseMessage } from '../../../utils/Console';
import { FrodoCommand } from '../../FrodoCommand';

const { CLOUD_DEPLOYMENT_TYPE_KEY, FORGEOPS_DEPLOYMENT_TYPE_KEY } =
frodo.utils.constants;

const deploymentTypes = [
CLOUD_DEPLOYMENT_TYPE_KEY,
FORGEOPS_DEPLOYMENT_TYPE_KEY,
];

export default function setup() {
const program = new FrodoCommand(
'frodo config-manager push connector-definitions',
[],
deploymentTypes
);

program
.description('Import connector definitions.')
.addOption(
new Option(
'-n, --name <name>',
'Connector definition name; imports only the specified connector definition.'
)
)
.action(async (host, realm, user, password, options, command) => {
command.handleDefaultArgsAndOpts(
host,
realm,
user,
password,
options,
command
);

if (await getTokens(false, true, deploymentTypes)) {
verboseMessage('Importing connector definitions');
const outcome = await configManagerImportConnectors(options.name);
if (!outcome) process.exitCode = 1;
} else {
process.exitCode = 1;
}
});

return program;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { FrodoStubCommand } from '../../FrodoCommand';
import AccessConfig from './config-manager-push-access-config';
import Audit from './config-manager-push-audit';
import Authentication from './config-manager-push-authentication';
import ConnectorDefinitions from './config-manager-push-connector-definitions';
import CookieDomains from './config-manager-push-cookie-domain';
import EmailProvider from './config-manager-push-email-provider';
import EmailTemplates from './config-manager-push-email-templates';
Expand Down Expand Up @@ -39,6 +41,8 @@ export default function setup() {
program.addCommand(CookieDomains().name('cookie-domains'));
program.addCommand(ServiceObjects().name('service-objects'));
program.addCommand(UiConfig().name('ui-config'));
program.addCommand(Authentication().name('authentication'));
program.addCommand(ConnectorDefinitions().name('connector-definitions'));

return program;
}
64 changes: 62 additions & 2 deletions src/configManagerOps/FrConfigAuthenticationOps.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { frodo, state } from '@rockcarver/frodo-lib';
import { AuthenticationSettingsExportInterface } from '@rockcarver/frodo-lib/types/ops/AuthenticationSettingsOps';
import fs from 'fs';

import { printError } from '../utils/Console';
import { realmList } from '../utils/FrConfig';

const { readAuthenticationSettings: _readAuthenticationSettings } =
frodo.authn.settings;
const {
readAuthenticationSettings: _readAuthenticationSettings,
importAuthenticationSettings,
} = frodo.authn.settings;
const { getFilePath, saveJsonToFile } = frodo.utils;

/**
Expand Down Expand Up @@ -47,3 +51,59 @@ export async function configManagerExportAuthentication(
}
return false;
}

/**
* Import authentication configuration from the fr-config-manager format.
* @param {string} realm The realm of the authentication configuration being imported. If not supplied, will import all authentication configuration.
* @return {Promise<boolean>} a promise that resolves to true if successful, false otherwise
*/
export async function configManagerImportAuthentication(
realm?: string
): Promise<boolean> {
try {
if (realm) {
const filePath = getFilePath(
`realms/${realm}/realm-config/authentication.json`
);
const fileContent = fs.readFileSync(filePath, 'utf-8');
const authData = JSON.parse(fileContent);
delete authData._rev;
const importData: AuthenticationSettingsExportInterface = {
authentication: authData,
};

await importAuthenticationSettings(importData, false);
} else {
const realmsPath = getFilePath(`realms/`);
const realmDirs = fs.readdirSync(realmsPath);
for (const realmName of realmDirs) {
await state.setRealm(realmName);
let realmPath;

if (realmName === 'realm-config') {
await state.setRealm('/');
realmPath = getFilePath(`realms/realm-config/authentication.json`);
} else {
await state.setRealm(realmName);
realmPath = getFilePath(
`realms/${realmName}/realm-config/authentication.json`
);
}

const fileContent = fs.readFileSync(realmPath, 'utf-8');
const authData = JSON.parse(fileContent);
delete authData._rev;
const importData: AuthenticationSettingsExportInterface = {
authentication: authData,
};

await importAuthenticationSettings(importData, false);
}
}

return true;
} catch (error) {
printError(error, `Error importing authentication settings`);
}
return false;
}
43 changes: 43 additions & 0 deletions src/configManagerOps/FrConfigConnectorDefinitionsOps.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { frodo } from '@rockcarver/frodo-lib';
import { ConnectorSkeleton } from '@rockcarver/frodo-lib/types/ops/ConnectorOps';
import fs from 'fs';

import { printError, verboseMessage } from '../utils/Console';

const { connector } = frodo.idm;
const { getFilePath, saveJsonToFile } = frodo.utils;
const { importConfigEntities } = frodo.idm.config;
type ByName = { connectorName: string };
type BySkeleton = { c: ConnectorSkeleton };

Expand Down Expand Up @@ -74,3 +76,44 @@ export async function configManagerExportConnectorDefinitionsAll(): Promise<bool
printError(error);
}
}

/**
* Import all connectors in fr-config-manager format
* @param {string} name optional name of connector definition to import
* @returns {Promise<boolean>} true if successful, false otherwise
*/
export async function configManagerImportConnectors(
name?: string
): Promise<boolean> {
try {
const connMappingDir = getFilePath('sync/connectors/');
const connMappingFiles = fs.readdirSync(connMappingDir);
const connMappingImportData = { idm: {} };

if (name) {
const filePath = getFilePath(`sync/connectors/${name}.json`);
const fileData = fs.readFileSync(filePath, 'utf8');
const importData = JSON.parse(fileData);
const id = importData._id;
connMappingImportData.idm[id] = importData;
await importConfigEntities(connMappingImportData);
} else {
for (const connMappingFile of connMappingFiles) {
const filePath = getFilePath(`sync/connectors/`);
const fileData = fs.readFileSync(
`${filePath}/${connMappingFile}`,
'utf-8'
);
const importData = JSON.parse(fileData);
const id = importData._id;
connMappingImportData.idm[id] = importData;
}
await importConfigEntities(connMappingImportData);
}

return true;
} catch (error) {
printError(error, `Error exporting mappings to files`);
}
return false;
}
47 changes: 47 additions & 0 deletions src/configManagerOps/FrConfigCustomNodesOps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { frodo } from '@rockcarver/frodo-lib';

import { printError } from '../utils/Console';

const { saveJsonToFile, getFilePath, saveTextToFile } = frodo.utils;
const { readCustomNode, readCustomNodes } = frodo.authn.node;

/**
* Export all custom nodes to 'custom-nodes/nodes' directory.
* Each custom node will be exported as a JSON file with a reference to its script file.
* The script content will be saved in a separate .js file.
* @param {string} name Optional display name of a custom node to export. If not provided, all custom nodes will be exported.
* @returns {Promise<boolean>} True if export was successful
*/
export async function configManagerExportCustomNodes(
name?: string
): Promise<boolean> {
try {
let customNodes;
if (name) {
const customNode = await readCustomNode(undefined, name);
customNodes = [customNode];
} else {
customNodes = await readCustomNodes();
}

for (const node of customNodes) {
const nodeDir = getFilePath(
`custom-nodes/nodes/${node.displayName}/`,
true
);
const scriptFileName = `${node.displayName}.js`;
const jsonFileName = `${node.displayName}.json`;

saveTextToFile(`${node.script}`, nodeDir + scriptFileName);
node.script = { file: scriptFileName };

const filePath = nodeDir + jsonFileName;
saveJsonToFile(node, filePath, false);
}

return true;
} catch (error) {
printError(error);
return false;
}
}
Loading