UNPKG

@roadiehq/catalog-backend-module-okta

Version:

A set of Backstage catalog providers for Okta

191 lines (185 loc) 6.78 kB
'use strict'; var OktaEntityProvider = require('./OktaEntityProvider.cjs.js'); require('lodash'); var groupNamingStrategyFactory = require('./groupNamingStrategies/groupNamingStrategyFactory.cjs.js'); var userNamingStrategyFactory = require('./userNamingStrategies/userNamingStrategyFactory.cjs.js'); require('slugify'); var userEntityFromOktaUser = require('./userEntityFromOktaUser.cjs.js'); var groupEntityFromOktaGroup = require('./groupEntityFromOktaGroup.cjs.js'); var accountConfig = require('./accountConfig.cjs.js'); var errors = require('@backstage/errors'); var getOktaGroups = require('./getOktaGroups.cjs.js'); var getParentGroup = require('./getParentGroup.cjs.js'); var GroupTree = require('./GroupTree.cjs.js'); var types = require('./types.cjs.js'); var chunk = require('lodash/chunk'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; } var chunk__default = /*#__PURE__*/_interopDefaultCompat(chunk); const DEFAULT_CHUNK_SIZE = 250; class OktaOrgEntityProvider extends OktaEntityProvider.OktaEntityProvider { groupNamingStrategy; userNamingStrategy; groupEntityFromOktaGroup; userEntityFromOktaUser; includeEmptyGroups; hierarchyConfig; customAttributesToAnnotationAllowlist; chunkSize; static fromConfig(config, options) { const oktaConfig = accountConfig.getAccountConfig(config); if (options.parentGroupField && !options.hierarchyConfig?.parentKey) { options.hierarchyConfig = { parentKey: `profile.${options.parentGroupField}` }; } return new OktaOrgEntityProvider(oktaConfig, options); } constructor(accountConfig, options) { super(accountConfig, options); this.groupNamingStrategy = groupNamingStrategyFactory.groupNamingStrategyFactory( options.groupNamingStrategy ); this.userNamingStrategy = userNamingStrategyFactory.userNamingStrategyFactory( options.userNamingStrategy ); this.groupEntityFromOktaGroup = options?.groupTransformer || groupEntityFromOktaGroup.groupEntityFromOktaGroup; this.userEntityFromOktaUser = options.userTransformer || userEntityFromOktaUser.userEntityFromOktaUser; this.includeEmptyGroups = !!options.includeEmptyGroups; this.hierarchyConfig = options.hierarchyConfig; this.customAttributesToAnnotationAllowlist = options.customAttributesToAnnotationAllowlist || []; this.chunkSize = options.chunkSize || DEFAULT_CHUNK_SIZE; } getProviderName() { return `okta-org:all`; } async run() { if (!this.connection) { throw new Error("Not initialized"); } this.logger.info("Providing user and group resources from okta"); let groupResources = []; const userResources = {}; let providedUserCount = 0; let providedGroupCount = 0; const client = this.getClient(this.account.orgUrl, [ "okta.groups.read", "okta.users.read" ]); const defaultAnnotations = await this.buildDefaultAnnotations(); const allUsers = await client.userApi.listUsers({ search: this.account.userFilter }); await allUsers.each((rawUser) => { const user = types.asOktaUser(rawUser); try { const userName = this.userNamingStrategy(user); userResources[userName] = this.userEntityFromOktaUser( user, this.userNamingStrategy, { annotations: defaultAnnotations } ); } catch (e) { this.logger.warn( `Failed to add user: ${errors.isError(e) ? e.message : "unknown error"}` ); } }); providedUserCount = Object.values(userResources).length; const oktaGroups = await getOktaGroups.getOktaGroups({ client, groupFilter: this.account.groupFilter, key: this.hierarchyConfig?.key, groupNamingStrategy: this.groupNamingStrategy, logger: this.logger }); for (const chunkOfGroups of chunk__default.default( Object.values(oktaGroups), this.chunkSize )) { const promiseResults = await Promise.allSettled( chunkOfGroups.map(async (group) => { const members = []; const groupUsers = await client.groupApi.listGroupUsers({ groupId: group.id }); await groupUsers.each((rawUser) => { const user = types.asOktaUser(rawUser); try { const userName = this.userNamingStrategy(user); if (userResources[userName]) { members.push(userName); } } catch (e) { this.logger.warn( `failed to add user to group: ${errors.isError(e) ? e.message : "unknown error"}` ); } }); const parentGroup = getParentGroup.getParentGroup({ parentKey: this.hierarchyConfig?.parentKey, group, oktaGroups }); const profileAnnotations = this.getCustomAnnotations( group, this.customAttributesToAnnotationAllowlist ); const annotations = { ...defaultAnnotations, ...profileAnnotations }; try { const groupEntity = this.groupEntityFromOktaGroup( group, this.groupNamingStrategy, { annotations, members }, parentGroup ); return groupEntity; } catch (e) { throw new Error( `failed to add group: ${errors.isError(e) ? e.message : "unknown error"}` ); } }) ); for (const promise of promiseResults) { if (promise.status === "fulfilled") { groupResources.push(promise.value); } else { this.logger.info( errors.isError(promise.reason) ? promise.reason.message : "unknown error" ); } } } if (!this.includeEmptyGroups) { this.logger.info( `Found ${groupResources.length} groups in okta, pruning the empty ones` ); groupResources = new GroupTree.GroupTree(groupResources).getGroups({ pruneEmptyMembers: true }); } providedGroupCount = groupResources.length; await this.connection.applyMutation({ type: "full", entities: [...Object.values(userResources), ...groupResources].map( (entity) => ({ entity, locationKey: this.getProviderName() }) ) }); this.logger.info( `Finished providing ${providedUserCount} user and ${providedGroupCount} group resources from okta` ); } } exports.OktaOrgEntityProvider = OktaOrgEntityProvider; //# sourceMappingURL=OktaOrgEntityProvider.cjs.js.map