WIP: address feedback
Signed-off-by: Jessica He <jhe@redhat.com>
This commit is contained in:
parent
d33c1c66ce
commit
80303eb9ea
|
|
@ -32,3 +32,4 @@ yarn.lock @backstage/community-plugins
|
|||
/workspaces/tech-insights @backstage/community-plugins-maintainers @xantier
|
||||
/workspaces/report-portal @backstage/community-plugins-maintainers @yashoswalyo
|
||||
/workspaces/redhat-resource-optimization @backstage/community-plugins-maintainers
|
||||
/workspaces/pingidentity @backstage/community-plugins-maintainers @jessicajhee
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ catalog:
|
|||
envId: ${PING_IDENTITY_ENV_ID}
|
||||
clientId: ${PING_IDENTITY_CLIENT_ID}
|
||||
clientSecret: ${PING_IDENTITY_CLIENT_SECRET}
|
||||
userQuerySize: 2
|
||||
groupQuerySize: 2
|
||||
schedule: # Mandatory; same options as in TaskScheduleDefinition
|
||||
# supports cron, ISO duration, "human duration" as used in code
|
||||
frequency: { seconds: 30 } # Customize this to fit your needs
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"version": "1.29.0"
|
||||
"version": "1.29.2"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@ apiVersion: backstage.io/v1alpha1
|
|||
kind: Component
|
||||
metadata:
|
||||
name: pingidentity
|
||||
description: An example of a Backstage application.
|
||||
# Example for optional annotations
|
||||
# annotations:
|
||||
# github.com/project-slug: backstage/backstage
|
||||
# backstage.io/techdocs-ref: dir:.
|
||||
title: '@backstage-community/pingidentity'
|
||||
description: An Backstage plugin that ingests users and groups from Ping Identity into the catalog.
|
||||
spec:
|
||||
type: website
|
||||
owner: john@example.com
|
||||
type: backstage-backend-plugin-module
|
||||
owner: jessicajhee
|
||||
lifecycle: experimental
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -22,10 +22,6 @@ export interface Config {
|
|||
* The envId where the application is located
|
||||
*/
|
||||
envId: string;
|
||||
/**
|
||||
* Schedule configuration for refresh tasks.
|
||||
*/
|
||||
schedule?: SchedulerServiceTaskScheduleDefinitionConfig;
|
||||
/**
|
||||
* PingIdentityClientCredentials
|
||||
*/
|
||||
|
|
@ -38,6 +34,26 @@ export interface Config {
|
|||
* @visibility secret
|
||||
*/
|
||||
clientSecret: string;
|
||||
/**
|
||||
* Schedule configuration for refresh tasks.
|
||||
*/
|
||||
schedule?: SchedulerServiceTaskScheduleDefinitionConfig;
|
||||
/**
|
||||
* The number of users to query at a time.
|
||||
* @defaultValue 100
|
||||
* @remarks
|
||||
* This is a performance optimization to avoid querying too many users at once.
|
||||
* @see https://apidocs.pingidentity.com/pingone/platform/v1/api/#paging-ordering-and-filtering-collections
|
||||
*/
|
||||
userQuerySize?: number;
|
||||
/**
|
||||
* The number of groups to query at a time.
|
||||
* @defaultValue 100
|
||||
* @remarks
|
||||
* This is a performance optimization to avoid querying too many groups at once.
|
||||
* @see https://apidocs.pingidentity.com/pingone/platform/v1/api/#paging-ordering-and-filtering-collections
|
||||
*/
|
||||
groupQuerySize?: number;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ describe('PingIdentityClient', () => {
|
|||
}),
|
||||
);
|
||||
|
||||
const users = await client.getUsers();
|
||||
const users = await client.getUsers(10);
|
||||
|
||||
expect(users).toEqual([
|
||||
{
|
||||
|
|
@ -200,7 +200,7 @@ describe('PingIdentityClient', () => {
|
|||
}),
|
||||
);
|
||||
|
||||
const groups = await client.getGroups();
|
||||
const groups = await client.getGroups(10);
|
||||
|
||||
expect(groups).toEqual([
|
||||
{
|
||||
|
|
@ -231,7 +231,7 @@ describe('PingIdentityClient', () => {
|
|||
size: 1,
|
||||
_embedded: {
|
||||
groupMemberships: [
|
||||
{ name: 'Parent Group' },
|
||||
{ id: 'ParentGroup' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
|
|
@ -239,9 +239,9 @@ describe('PingIdentityClient', () => {
|
|||
}),
|
||||
);
|
||||
|
||||
const parentGroup = await client.getParentGroup('group1');
|
||||
const parentGroup = await client.getParentGroupId('group1');
|
||||
|
||||
expect(parentGroup).toBe('Parent Group');
|
||||
expect(parentGroup).toBe('ParentGroup');
|
||||
});
|
||||
|
||||
it('should return undefined if no parent group exists', async () => {
|
||||
|
|
@ -265,7 +265,7 @@ describe('PingIdentityClient', () => {
|
|||
}),
|
||||
);
|
||||
|
||||
const parentGroup = await client.getParentGroup('group1');
|
||||
const parentGroup = await client.getParentGroupId('group1');
|
||||
|
||||
expect(parentGroup).toBeUndefined();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import fetch, { Response } from 'node-fetch';
|
||||
import { PingIdentityProviderConfig } from './config';
|
||||
import { PingIdentityGroup, PingIdentityUser } from './types';
|
||||
import { PingIdentityGroup, PingIdentityResponse, PingIdentityUser } from './types';
|
||||
import { PING_IDENTITY_DEFAULT_ENTITY_QUERY_SIZE } from './constants';
|
||||
|
||||
class PingIdentityClient {
|
||||
private tokenCredential: string | null = null;
|
||||
|
|
@ -19,37 +20,59 @@ class PingIdentityClient {
|
|||
/**
|
||||
* Gets a list of all users fetched from Ping Identity API
|
||||
*
|
||||
* @param querySize - the number of users to query at a time
|
||||
*
|
||||
* @returns a list of all users fetched from Ping Identity API
|
||||
*/
|
||||
async getUsers(): Promise<PingIdentityUser[]> {
|
||||
const response = await this.requestApi('users');
|
||||
const data = await response.json();
|
||||
return data._embedded.users;
|
||||
async getUsers(querySize: number = PING_IDENTITY_DEFAULT_ENTITY_QUERY_SIZE): Promise<PingIdentityUser[]> {
|
||||
const allUsers: PingIdentityUser[] = [];
|
||||
let nextUrl: string | undefined = `users?limit=${querySize}`;
|
||||
|
||||
while (nextUrl) {
|
||||
const url = nextUrl.startsWith('http') ? nextUrl : `${this.config.apiPath}/environments/${this.config.envId}/${nextUrl}`;
|
||||
const response = await this.requestApi(url, true);
|
||||
const data: PingIdentityResponse = await response.json() as PingIdentityResponse;
|
||||
allUsers.push(...(data._embedded.users as PingIdentityUser[]));
|
||||
nextUrl = data._links?.next?.href || undefined;
|
||||
}
|
||||
|
||||
return allUsers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all groups fetched from Ping Identity API
|
||||
*
|
||||
* @param querySize - the number of groups to query at a time
|
||||
*
|
||||
* @returns a list of all groups fetched from Ping Identity API
|
||||
*/
|
||||
async getGroups(): Promise<PingIdentityGroup[]> {
|
||||
const response = await this.requestApi('groups');
|
||||
const data = await response.json();
|
||||
return data._embedded.groups;
|
||||
async getGroups(querySize: number = PING_IDENTITY_DEFAULT_ENTITY_QUERY_SIZE): Promise<PingIdentityGroup[]> {
|
||||
const allGroups: PingIdentityGroup[] = [];
|
||||
let nextUrl: string | undefined = `groups?limit=${querySize}`;
|
||||
|
||||
while (nextUrl) {
|
||||
const url = nextUrl.startsWith('http') ? nextUrl : `${this.config.apiPath}/environments/${this.config.envId}/${nextUrl}`;
|
||||
const response = await this.requestApi(url, true);
|
||||
const data: PingIdentityResponse = await response.json() as PingIdentityResponse;
|
||||
allGroups.push(...(data._embedded.groups as PingIdentityGroup[]));
|
||||
nextUrl = data._links?.next?.href || undefined;
|
||||
}
|
||||
|
||||
return allGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parent group of a given group, returns undefined if there is no parent group
|
||||
* Gets the parent group ID of a given group, returns undefined if there is no parent group
|
||||
*
|
||||
* @param groupId the group ID of a given group
|
||||
*
|
||||
* @returns the parent group of a given group, undefined if there is no parent group
|
||||
* @returns the parent group ID of a given group, undefined if there is no parent group
|
||||
*/
|
||||
async getParentGroup(groupId: string): Promise<string | undefined> {
|
||||
async getParentGroupId(groupId: string): Promise<string | undefined> {
|
||||
const response = await this.requestApi(`groups/${groupId}/memberOfGroups`);
|
||||
const data = await response.json();
|
||||
return data.size > 0
|
||||
? data._embedded.groupMemberships[0].name
|
||||
? data._embedded.groupMemberships[0].id
|
||||
: undefined;
|
||||
}
|
||||
|
||||
|
|
@ -70,11 +93,11 @@ class PingIdentityClient {
|
|||
* Makes a Ping Identity API request to the configured environment
|
||||
*
|
||||
* @param query the query to be made
|
||||
*
|
||||
* @param isFullUrl Optional - true if the given query is the full request url
|
||||
* @returns the response to the given API call
|
||||
*/
|
||||
async requestApi(query: string): Promise<Response> {
|
||||
const url = `${this.config.apiPath}/environments/${this.config.envId}/${query}`;
|
||||
async requestApi(query: string, isFullUrl?: boolean): Promise<Response> {
|
||||
const url = isFullUrl ? query : `${this.config.apiPath}/environments/${this.config.envId}/${query}`;
|
||||
let accessToken = await this.getAccessToken();
|
||||
|
||||
let response = await this.makeRequest(url, accessToken);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ describe('readProviderConfigs', () => {
|
|||
minutes: 3,
|
||||
},
|
||||
},
|
||||
userQuerySize: 100,
|
||||
groupQuerySize: 200,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -47,6 +49,8 @@ describe('readProviderConfigs', () => {
|
|||
minutes: 3,
|
||||
},
|
||||
},
|
||||
userQuerySize: 100,
|
||||
groupQuerySize: 200,
|
||||
},
|
||||
];
|
||||
expect(actual).toEqual(expected);
|
||||
|
|
|
|||
|
|
@ -46,6 +46,22 @@ export type PingIdentityProviderConfig = {
|
|||
* Schedule configuration for refresh tasks.
|
||||
*/
|
||||
schedule?: SchedulerServiceTaskScheduleDefinition;
|
||||
/**
|
||||
* The number of users to query at a time.
|
||||
* @defaultValue 100
|
||||
* @remarks
|
||||
* This is a performance optimization to avoid querying too many users at once.
|
||||
* @see https://apidocs.pingidentity.com/pingone/platform/v1/api/#paging-ordering-and-filtering-collections
|
||||
*/
|
||||
userQuerySize?: number;
|
||||
/**
|
||||
* The number of groups to query at a time.
|
||||
* @defaultValue 100
|
||||
* @remarks
|
||||
* This is a performance optimization to avoid querying too many groups at once.
|
||||
* @see https://apidocs.pingidentity.com/pingone/platform/v1/api/#paging-ordering-and-filtering-collections
|
||||
*/
|
||||
groupQuerySize?: number;
|
||||
};
|
||||
|
||||
const readProviderConfig = (
|
||||
|
|
@ -57,6 +73,10 @@ const readProviderConfig = (
|
|||
const envId = providerConfigInstance.getString('envId');
|
||||
const clientId = providerConfigInstance.getOptionalString('clientId');
|
||||
const clientSecret = providerConfigInstance.getOptionalString('clientSecret');
|
||||
const userQuerySize =
|
||||
providerConfigInstance.getOptionalNumber('userQuerySize');
|
||||
const groupQuerySize =
|
||||
providerConfigInstance.getOptionalNumber('groupQuerySize');
|
||||
|
||||
if (clientId && !clientSecret) {
|
||||
throw new Error(`clientSecret must be provided when clientId is defined.`);
|
||||
|
|
@ -80,6 +100,8 @@ const readProviderConfig = (
|
|||
clientId,
|
||||
clientSecret,
|
||||
schedule,
|
||||
userQuerySize,
|
||||
groupQuerySize,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
export const PING_IDENTITY_ID_ANNOTATION = 'pingidentity.org/id';
|
||||
export const PING_IDENTITY_ID_ANNOTATION = 'pingidentity.org/id';
|
||||
export const PING_IDENTITY_DEFAULT_ENTITY_QUERY_SIZE = 100;
|
||||
|
|
@ -11,8 +11,8 @@ describe('defaultTransformers', () => {
|
|||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Group',
|
||||
metadata: {
|
||||
annotations: { 'graph.microsoft.com/group-id': 'foo' },
|
||||
name: 'bar',
|
||||
annotations: { 'pingidentity.org/id': 'foo' },
|
||||
name: 'group one',
|
||||
},
|
||||
spec: {
|
||||
children: [],
|
||||
|
|
@ -26,11 +26,11 @@ describe('defaultTransformers', () => {
|
|||
href: ''
|
||||
}
|
||||
},
|
||||
id: 'bar',
|
||||
id: 'group1',
|
||||
environment: {
|
||||
id: ''
|
||||
},
|
||||
name: 'bar',
|
||||
name: 'group one',
|
||||
description: '',
|
||||
directMemberCounts: {
|
||||
users: 0
|
||||
|
|
@ -39,8 +39,20 @@ describe('defaultTransformers', () => {
|
|||
updatedAt: ''
|
||||
}
|
||||
const result = await defaultGroupTransformer(group, pingIdentityGroup, 'envId');
|
||||
// should not make any transformations
|
||||
expect(result).toEqual(group);
|
||||
// should normalize illegal characters in group name
|
||||
expect(result).toEqual({
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Group',
|
||||
metadata: {
|
||||
annotations: { 'pingidentity.org/id': 'foo' },
|
||||
name: 'group_one',
|
||||
},
|
||||
spec: {
|
||||
children: [],
|
||||
profile: { displayName: 'BAR' },
|
||||
type: 'team',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('tests defaultUserTransformer', async () => {
|
||||
|
|
@ -49,7 +61,7 @@ describe('defaultTransformers', () => {
|
|||
kind: 'User',
|
||||
metadata: {
|
||||
annotations: {
|
||||
'graph.microsoft.com/user-id': 'foo',
|
||||
'pingidentity.org/id': 'foo',
|
||||
},
|
||||
name: 'test~user@example.com',
|
||||
},
|
||||
|
|
@ -126,7 +138,7 @@ describe('defaultTransformers', () => {
|
|||
kind: 'User',
|
||||
metadata: {
|
||||
annotations: {
|
||||
'graph.microsoft.com/user-id': 'foo',
|
||||
'pingidentity.org/id': 'foo',
|
||||
},
|
||||
name: 'test_user_example.com',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@ import { GroupTransformer, UserTransformer } from './types';
|
|||
export const defaultGroupTransformer: GroupTransformer = async (
|
||||
entity,
|
||||
_envId,
|
||||
) => entity;
|
||||
) => {
|
||||
entity.metadata.name = entity.metadata.name.replace(/[^a-zA-Z0-9_\-\.]/g, '_');
|
||||
return entity;
|
||||
};
|
||||
|
||||
/**
|
||||
* The default user transformer if none is provided
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ describe('PingIdentity readPingIdentity', () => {
|
|||
|
||||
expect(result.groups).toHaveLength(1);
|
||||
expect(result.users).toHaveLength(2);
|
||||
expect(result.groups[0].metadata.name).toBe('Group One');
|
||||
expect(result.groups[0].metadata.name).toBe('Group_One');
|
||||
expect(result.users[0].metadata.name).toBe('user1');
|
||||
expect(result.users[1].metadata.name).toBe('user2');
|
||||
});
|
||||
|
|
@ -209,14 +209,14 @@ describe('PingIdentity readPingIdentity', () => {
|
|||
]);
|
||||
mockClient.getUsers.mockResolvedValue([exampleUser1]);
|
||||
mockClient.getUsersInGroup.mockResolvedValue(['user1']);
|
||||
mockClient.getParentGroup.mockResolvedValue(undefined);
|
||||
mockClient.getParentGroupId.mockResolvedValue(undefined);
|
||||
|
||||
const result = await readPingIdentity(mockClient);
|
||||
|
||||
expect(result.groups).toHaveLength(1);
|
||||
expect(result.users).toHaveLength(1);
|
||||
expect(result.users[0].spec.memberOf).toHaveLength(1);
|
||||
expect(result.users[0].spec.memberOf).toStrictEqual(['Group One']);
|
||||
expect(result.users[0].spec.memberOf).toStrictEqual(['Group_One']);
|
||||
});
|
||||
|
||||
it('should handle nested groups', async () => {
|
||||
|
|
@ -256,7 +256,7 @@ describe('PingIdentity readPingIdentity', () => {
|
|||
]);
|
||||
mockClient.getUsers.mockResolvedValue([]);
|
||||
mockClient.getUsersInGroup.mockResolvedValue([]);
|
||||
mockClient.getParentGroup.mockImplementation(async (groupId) => {
|
||||
mockClient.getParentGroupId.mockImplementation(async (groupId) => {
|
||||
if (groupId === 'group2') return 'group1';
|
||||
return undefined;
|
||||
});
|
||||
|
|
@ -264,9 +264,9 @@ describe('PingIdentity readPingIdentity', () => {
|
|||
const result = await readPingIdentity(mockClient);
|
||||
|
||||
expect(result.groups).toHaveLength(2);
|
||||
const groupTwo = result.groups.find(g => g.metadata.name === 'Group Two');
|
||||
const groupTwo = result.groups.find(g => g.metadata.name === 'Group_Two');
|
||||
|
||||
expect(groupTwo?.spec.parent).toBe('group1');
|
||||
expect(groupTwo?.spec.parent).toBe('Group_One');
|
||||
});
|
||||
|
||||
it('should handle errors in fetching users or groups', async () => {
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ const getEntityLocation = (
|
|||
* @param client - The `PingIdentityClient`
|
||||
* @param groups - A list of all groups
|
||||
* @param groupMembersMap - Maps group ID to all user IDs that belong in that group
|
||||
* @param userQuerySize - the number of users to query at a time
|
||||
* @param userTransformer - Optional user transformer method
|
||||
*
|
||||
* @returns a parsed list of all users fetched from Ping Identity of type `UserEntity`
|
||||
|
|
@ -65,10 +66,11 @@ const parsePingIdentityUsers = async (
|
|||
client: PingIdentityClient,
|
||||
groups: GroupEntity[],
|
||||
groupMembersMap: Map<string, Set<string>>,
|
||||
userQuerySize?: number,
|
||||
userTransformer?: UserTransformer
|
||||
): Promise<UserEntity[]> => {
|
||||
const transformer = userTransformer ?? defaultUserTransformer;
|
||||
const pingIdentityUsers: PingIdentityUser[] = await client.getUsers();
|
||||
const pingIdentityUsers: PingIdentityUser[] = await client.getUsers(userQuerySize);
|
||||
const transformedUsers: (UserEntity | undefined)[] = await Promise.all(pingIdentityUsers.map(async (user: any) => {
|
||||
const userLocation = getEntityLocation(client.getConfig(), 'users', user.id);
|
||||
return await transformer({
|
||||
|
|
@ -104,7 +106,9 @@ const parsePingIdentityUsers = async (
|
|||
* Returns a parsed list of all groups in the Ping Identity environment
|
||||
*
|
||||
* @param client - The `PingIdentityClient`
|
||||
* @param groupMembersMap - Maps group ID to all user IDs that belong in that group
|
||||
* @param groupMembersMap - Maps group ID to all user IDs that belong in that
|
||||
* @param parentGroupMap - Maps group ID to its parent group ID
|
||||
* @param groupQuerySize - the number of groups to query at a time
|
||||
* @param groupTransformer - Optional group transformer method
|
||||
*
|
||||
* @returns a parsed list of all groups fetched from Ping Identity of type `GroupEntity`
|
||||
|
|
@ -112,14 +116,20 @@ const parsePingIdentityUsers = async (
|
|||
const parsePingIdentityGroups = async (
|
||||
client: PingIdentityClient,
|
||||
groupMembersMap: Map<string, Set<string>>,
|
||||
parentGroupMap: Map<string, string>,
|
||||
groupQuerySize?: number,
|
||||
groupTransformer?: GroupTransformer
|
||||
): Promise<GroupEntity[]> => {
|
||||
const transformer = groupTransformer ?? defaultGroupTransformer;
|
||||
const pingIdentityGroups: PingIdentityGroup[] = await client.getGroups();
|
||||
const pingIdentityGroups: PingIdentityGroup[] = await client.getGroups(groupQuerySize);
|
||||
const transformedGroups: (GroupEntity | undefined)[] = await Promise.all(pingIdentityGroups.map(async (group: any) => {
|
||||
const groupLocation = getEntityLocation(client.getConfig(), 'groups', group.id);
|
||||
// add users in group to group membership map
|
||||
groupMembersMap.set(group.id, new Set(await client.getUsersInGroup(group.id)));
|
||||
// add parent group relationship to map
|
||||
const parentGroupId = await client.getParentGroupId(group.id);
|
||||
if (parentGroupId) parentGroupMap.set(group.id, parentGroupId);
|
||||
|
||||
return await transformer({
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'Group',
|
||||
|
|
@ -138,8 +148,7 @@ const parsePingIdentityGroups = async (
|
|||
displayName: group.name!,
|
||||
},
|
||||
children: [],
|
||||
parent: await client.getParentGroup(group.id),
|
||||
members: [],
|
||||
parent: undefined, // will be updated later
|
||||
}
|
||||
}, group, client.getConfig().envId);
|
||||
}));
|
||||
|
|
@ -160,6 +169,8 @@ const parsePingIdentityGroups = async (
|
|||
export const readPingIdentity = async (
|
||||
client: PingIdentityClient,
|
||||
options?: {
|
||||
userQuerySize?: number;
|
||||
groupQuerySize?: number;
|
||||
userTransformer?: UserTransformer;
|
||||
groupTransformer?: GroupTransformer;
|
||||
},
|
||||
|
|
@ -168,7 +179,23 @@ export const readPingIdentity = async (
|
|||
groups: GroupEntity[];
|
||||
}> => {
|
||||
const groupMembersMap = new Map<string, Set<string>>();
|
||||
const groups: GroupEntity[] = await parsePingIdentityGroups(client, groupMembersMap, options?.groupTransformer);
|
||||
const users: UserEntity[] = await parsePingIdentityUsers(client, groups, groupMembersMap, options?.userTransformer);
|
||||
const parentGroupMap = new Map<string, string>();
|
||||
const groups: GroupEntity[] = await parsePingIdentityGroups(client, groupMembersMap, parentGroupMap, options?.userQuerySize, options?.groupTransformer);
|
||||
// update parent/child group relationship
|
||||
const groupsMap = new Map<string, GroupEntity>();
|
||||
groups.forEach(group => {
|
||||
const groupId = group.metadata.annotations![PING_IDENTITY_ID_ANNOTATION];
|
||||
groupsMap.set(groupId, group);
|
||||
});
|
||||
|
||||
groups.forEach((group) => {
|
||||
const parentGroupId = parentGroupMap.get(group.metadata.annotations![PING_IDENTITY_ID_ANNOTATION]);
|
||||
if (parentGroupId) {
|
||||
const parentGroup = groupsMap.get(parentGroupId);
|
||||
group.spec.parent = parentGroup?.metadata.name;
|
||||
}
|
||||
});
|
||||
|
||||
const users: UserEntity[] = await parsePingIdentityUsers(client, groups, groupMembersMap, options?.groupQuerySize, options?.userTransformer);
|
||||
return { users, groups };
|
||||
};
|
||||
|
|
@ -35,6 +35,31 @@ export type GroupTransformer = (
|
|||
envId: string,
|
||||
) => Promise<GroupEntity | undefined>;
|
||||
|
||||
/**
|
||||
* Ping Identity API response type
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface PingIdentityResponse {
|
||||
_links: {
|
||||
self: {
|
||||
href: string;
|
||||
};
|
||||
prev?: {
|
||||
href: string;
|
||||
};
|
||||
next?: {
|
||||
href: string;
|
||||
};
|
||||
};
|
||||
_embedded: {
|
||||
users?: PingIdentityUser [];
|
||||
groups?: PingIdentityGroup[];
|
||||
};
|
||||
count?: number; // total count of items in the collection
|
||||
size?: number; // count of the current page of results
|
||||
}
|
||||
|
||||
/**
|
||||
* Ping Identity user type
|
||||
*
|
||||
|
|
|
|||
|
|
@ -143,6 +143,8 @@ export class PingIdentityEntityProvider implements EntityProvider {
|
|||
const client = new PingIdentityClient(provider);
|
||||
const { users, groups } = await readPingIdentity(client,
|
||||
{
|
||||
userQuerySize: this.options.provider.userQuerySize,
|
||||
groupQuerySize: this.options.provider.groupQuerySize,
|
||||
userTransformer: this.options.userTransformer,
|
||||
groupTransformer: this.options.groupTransformer,
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue