add configuration to use search criteria to select groups

Signed-off-by: Guilherme Oenning <goenning@eshopworld.com>
This commit is contained in:
Guilherme Oenning
2022-02-22 10:03:20 +00:00
parent 7ee2f47049
commit a097678475
8 changed files with 67 additions and 6 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-msgraph': patch
---
add configuration to use search criteria to select groups
@@ -153,7 +153,9 @@ export type MicrosoftGraphProviderConfig = {
userFilter?: string;
userExpand?: string[];
userGroupMemberFilter?: string;
userGroupMemberSearch?: string;
groupFilter?: string;
groupSearch?: string;
};
// @public
@@ -161,6 +163,7 @@ export function normalizeEntityName(name: string): string;
// @public
export type ODataQuery = {
search?: string;
filter?: string;
expand?: string[];
select?: string[];
@@ -183,7 +186,9 @@ export function readMicrosoftGraphOrg(
options: {
userExpand?: string[];
userFilter?: string;
userGroupMemberSearch?: string;
userGroupMemberFilter?: string;
groupSearch?: string;
groupFilter?: string;
userTransformer?: UserTransformer;
groupTransformer?: GroupTransformer;
+12
View File
@@ -73,12 +73,24 @@ export interface Config {
* E.g. "securityEnabled eq false and mailEnabled eq true"
*/
groupFilter?: string;
/**
* The search criteria to apply to extract users by groups memberships.
*
* E.g. "\"displayName:-team\"" would only match groups which contain '-team'
*/
groupSearch?: string;
/**
* The filter to apply to extract users by groups memberships.
*
* E.g. "displayName eq 'Backstage Users'"
*/
userGroupMemberFilter?: string;
/**
* The search criteria to apply to extract groups.
*
* E.g. "\"displayName:-team\"" would only match groups which contain '-team'
*/
userGroupMemberSearch?: string;
}>;
};
};
@@ -27,6 +27,10 @@ import { MicrosoftGraphProviderConfig } from './config';
* @public
*/
export type ODataQuery = {
/**
* search resources within a collection matching a free-text search expression.
*/
search?: string;
/**
* filter a collection of resources
*/
@@ -135,6 +139,7 @@ export class MicrosoftGraphClient {
async requestApi(path: string, query?: ODataQuery): Promise<Response> {
const queryString = qs.stringify(
{
$search: query?.search,
$filter: query?.filter,
$select: query?.select?.join(','),
$expand: query?.expand?.join(','),
@@ -167,6 +172,11 @@ export class MicrosoftGraphClient {
return await fetch(url, {
headers: {
Authorization: `Bearer ${token.accessToken}`,
// Eventual consistency is required to use $search.
// Groups/Users are not changed that frequently to require strong consistency
// If a new user/group is not found, it'll eventually be imported on a subsequent call
ConsistencyLevel: 'eventual'
},
});
}
@@ -64,12 +64,24 @@ export type MicrosoftGraphProviderConfig = {
* E.g. "displayName eq 'Backstage Users'"
*/
userGroupMemberFilter?: string;
/**
* The search criteria to apply to extract users by groups memberships.
*
* E.g. "\"displayName:-team\"" would only match groups which contain '-team'
*/
userGroupMemberSearch?: string;
/**
* The filter to apply to extract groups.
*
* E.g. "securityEnabled eq false and mailEnabled eq true"
*/
groupFilter?: string;
/**
* The search criteria to apply to extract groups.
*
* E.g. "\"displayName:-team\"" would only match groups which contain '-team'
*/
groupSearch?: string;
};
/**
@@ -93,18 +105,21 @@ export function readMicrosoftGraphConfig(
: 'https://login.microsoftonline.com';
const tenantId = providerConfig.getString('tenantId');
const clientId = providerConfig.getString('clientId');
const clientSecret = providerConfig.getString('clientSecret');
const userFilter = providerConfig.getOptionalString('userFilter');
const userGroupMemberFilter = providerConfig.getOptionalString(
'userGroupMemberFilter',
);
const groupFilter = providerConfig.getOptionalString('groupFilter');
const clientSecret = providerConfig.getString("clientSecret");
const userFilter = providerConfig.getOptionalString("userFilter");
const userGroupMemberFilter = providerConfig.getOptionalString("userGroupMemberFilter");
const userGroupMemberSearch = providerConfig.getOptionalString("userGroupMemberSearch");
const groupFilter = providerConfig.getOptionalString("groupFilter");
const groupSearch = providerConfig.getOptionalString("groupSearch");
if (userFilter && userGroupMemberFilter) {
throw new Error(
`userFilter and userGroupMemberFilter are mutually exclusive, only one can be specified.`,
);
}
if (userFilter && userGroupMemberSearch) {
throw new Error(`userGroupMemberSearch cannot be specified when userFilter is defined.`);
}
providers.push({
target,
@@ -114,7 +129,9 @@ export function readMicrosoftGraphConfig(
clientSecret,
userFilter,
userGroupMemberFilter,
userGroupMemberSearch,
groupFilter,
groupSearch
});
}
@@ -137,6 +137,7 @@ export async function readMicrosoftGraphUsers(
export async function readMicrosoftGraphUsersInGroups(
client: MicrosoftGraphClient,
options: {
userGroupMemberSearch?: string;
userGroupMemberFilter?: string;
transformer?: UserTransformer;
logger: Logger;
@@ -155,6 +156,7 @@ export async function readMicrosoftGraphUsersInGroups(
const groupMemberUsers: Set<string> = new Set();
for await (const group of client.getGroups({
search: options?.userGroupMemberSearch,
filter: options?.userGroupMemberFilter,
})) {
// Process all groups in parallel, otherwise it can take quite some time
@@ -324,6 +326,7 @@ export async function readMicrosoftGraphGroups(
client: MicrosoftGraphClient,
tenantId: string,
options?: {
groupSearch?: string;
groupFilter?: string;
groupTransformer?: GroupTransformer;
organizationTransformer?: OrganizationTransformer;
@@ -351,6 +354,7 @@ export async function readMicrosoftGraphGroups(
const promises: Promise<void>[] = [];
for await (const group of client.getGroups({
search: options?.groupSearch,
filter: options?.groupFilter,
})) {
// Process all groups in parallel, otherwise it can take quite some time
@@ -504,7 +508,9 @@ export async function readMicrosoftGraphOrg(
options: {
userExpand?: string[];
userFilter?: string;
userGroupMemberSearch?: string;
userGroupMemberFilter?: string;
groupSearch?: string;
groupFilter?: string;
userTransformer?: UserTransformer;
groupTransformer?: GroupTransformer;
@@ -519,6 +525,7 @@ export async function readMicrosoftGraphOrg(
client,
{
userGroupMemberFilter: options.userGroupMemberFilter,
userGroupMemberSearch: options.userGroupMemberSearch,
transformer: options.userTransformer,
logger: options.logger,
},
@@ -535,6 +542,7 @@ export async function readMicrosoftGraphOrg(
}
const { groups, rootGroup, groupMember, groupMemberOf } =
await readMicrosoftGraphGroups(client, tenantId, {
groupSearch: options?.groupSearch,
groupFilter: options?.groupFilter,
groupTransformer: options?.groupTransformer,
organizationTransformer: options?.organizationTransformer,
@@ -123,7 +123,9 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider {
{
userFilter: provider.userFilter,
userGroupMemberFilter: provider.userGroupMemberFilter,
userGroupMemberSearch: provider.userGroupMemberSearch,
groupFilter: provider.groupFilter,
groupSearch: provider.groupSearch,
groupTransformer: this.options.groupTransformer,
userTransformer: this.options.userTransformer,
organizationTransformer: this.options.organizationTransformer,
@@ -108,7 +108,9 @@ export class MicrosoftGraphOrgReaderProcessor implements CatalogProcessor {
userExpand: provider.userExpand,
userFilter: provider.userFilter,
userGroupMemberFilter: provider.userGroupMemberFilter,
userGroupMemberSearch: provider.userGroupMemberSearch,
groupFilter: provider.groupFilter,
groupSearch: provider.groupSearch,
userTransformer: this.userTransformer,
groupTransformer: this.groupTransformer,
organizationTransformer: this.organizationTransformer,