From 29f7cfffb7a3cb545797296aab94160a875af96b Mon Sep 17 00:00:00 2001 From: Tim Hansen Date: Sun, 1 Aug 2021 20:38:17 -0600 Subject: [PATCH 1/5] Add resolveCatalogMemberClaims method Signed-off-by: Tim Hansen --- .changeset/beige-colts-pump.md | 5 + docs/auth/identity-resolver.md | 41 +++++++ .../lib/catalog/CatalogIdentityClient.test.ts | 101 +++++++++++++++++- .../src/lib/catalog/CatalogIdentityClient.ts | 86 ++++++++++++++- 4 files changed, 227 insertions(+), 6 deletions(-) create mode 100644 .changeset/beige-colts-pump.md diff --git a/.changeset/beige-colts-pump.md b/.changeset/beige-colts-pump.md new file mode 100644 index 0000000000..a6c5fe1e1c --- /dev/null +++ b/.changeset/beige-colts-pump.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Added `resolveCatalogMemberClaims` utility to query the catalog for additional authentication claims within sign-in resolvers. diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md index 814ff63729..38d7567172 100644 --- a/docs/auth/identity-resolver.md +++ b/docs/auth/identity-resolver.md @@ -111,6 +111,47 @@ export default async function createPlugin({ ... ``` +## Resolving membership through the catalog + +If you want to provide additional claims through Sign-In resolvers but still +have the software catalog handle group (and transitive group) membership, you +can do this using the `CatalogIdentityClient` provided as context to Sign-In +resolvers: + +```ts +export default async function createPlugin({ + ... +}: PluginEnvironment): Promise { + return await createRouter({ + ... + providerFactories: { + google: createGoogleProvider({ + signIn: { + resolver: async ({ profile: { email } }, ctx) => { + const [sub] = email?.split('@') ?? ''; + // Fetch from an external system that returns entity claims like: + // 'user:default/breanna.davison' + const ent = await externalSystemClient.getUsernames(email); + + // Resolve group membership from the Backstage catalog + const claims = await ctx.catalogIdentityClient.resolveCatalogMemberClaims( + sub, + ent, + ctx.logger, + ); + const token = await ctx.tokenIssuer.issueToken(claims); + return { sub, token }; + }, + }, + }), + ... +``` + +The `resolveCatalogMemberClaims` method will retrieve the `sub` and `ent` +entities from the catalog, if possible, and check for +[memberOf](../features/software-catalog/well-known-relations.md#memberof-and-hasmember) +relations to add additional entity claims. + ## AuthHandler Similar to a custom sign-in resolver, you can also write a custom auth handler diff --git a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts index 329db316ab..6f05bef5f8 100644 --- a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts +++ b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts @@ -15,7 +15,11 @@ */ import { CatalogApi } from '@backstage/catalog-client'; -import { UserEntity } from '@backstage/catalog-model'; +import { + RELATION_MEMBER_OF, + UserEntity, + UserEntityV1alpha1, +} from '@backstage/catalog-model'; import { TokenIssuer } from '../../identity'; import { CatalogIdentityClient } from './CatalogIdentityClient'; @@ -37,12 +41,12 @@ describe('CatalogIdentityClient', () => { afterEach(() => jest.resetAllMocks()); - it('passes through the correct search params', async () => { + it('findUser passes through the correct search params', async () => { catalogApi.getEntities.mockResolvedValueOnce({ items: [{} as UserEntity] }); tokenIssuer.issueToken.mockResolvedValue('my-token'); const client = new CatalogIdentityClient({ - catalogApi: catalogApi, - tokenIssuer: tokenIssuer, + catalogApi, + tokenIssuer, }); await client.findUser({ annotations: { key: 'value' } }); @@ -62,4 +66,93 @@ describe('CatalogIdentityClient', () => { }, }); }); + + it('resolveCatalogMemberClaims resolves membership', async () => { + const mockUsers: Array = [ + { + apiVersion: 'backstage.io/v1beta1', + kind: 'User', + metadata: { + name: 'inigom', + }, + spec: { + memberOf: ['team-a'], + }, + relations: [ + { + type: RELATION_MEMBER_OF, + target: { + kind: 'Group', + namespace: 'default', + name: 'team-a', + }, + }, + ], + }, + { + apiVersion: 'backstage.io/v1beta1', + kind: 'User', + metadata: { + name: 'mpatinkin', + namespace: 'reality', + }, + spec: { + memberOf: ['screen-actors-guild'], + }, + relations: [ + { + type: RELATION_MEMBER_OF, + target: { + kind: 'Group', + namespace: 'reality', + name: 'screen-actors-guild', + }, + }, + ], + }, + ]; + catalogApi.getEntities.mockResolvedValueOnce({ items: mockUsers }); + + const client = new CatalogIdentityClient({ + catalogApi, + tokenIssuer, + }); + + const claims = await client.resolveCatalogMemberClaims('inigom', [ + 'User:default/imontoya', + 'User:reality/mpatinkin', + ]); + + expect(catalogApi.getEntities).toHaveBeenCalledWith({ + filter: [ + { + kind: 'user', + 'metadata.namespace': 'default', + 'metadata.name': 'inigom', + }, + { + kind: 'user', + 'metadata.namespace': 'default', + 'metadata.name': 'imontoya', + }, + { + kind: 'user', + 'metadata.namespace': 'reality', + 'metadata.name': 'mpatinkin', + }, + ], + }); + + expect(claims).toMatchObject({ + claims: { + sub: 'inigom', + ent: [ + 'user:default/imontoya', + 'user:reality/mpatinkin', + 'group:default/team-a', + 'group:reality/screen-actors-guild', + ], + }, + }); + }); }); diff --git a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts index 07a7190503..c1f54f74c8 100644 --- a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts +++ b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts @@ -14,10 +14,17 @@ * limitations under the License. */ +import { Logger } from 'winston'; import { ConflictError, NotFoundError } from '@backstage/errors'; import { CatalogApi } from '@backstage/catalog-client'; -import { UserEntity } from '@backstage/catalog-model'; -import { TokenIssuer } from '../../identity'; +import { + EntityName, + parseEntityRef, + RELATION_MEMBER_OF, + stringifyEntityRef, + UserEntity, +} from '@backstage/catalog-model'; +import { TokenIssuer, TokenParams } from '../../identity'; type UserQuery = { annotations: Record; @@ -64,4 +71,79 @@ export class CatalogIdentityClient { return items[0] as UserEntity; } + + /** + * Resolve additional entity claims from the catalog, using the passed-in subject and entity + * claims. Designed to be used within a `signInResolver` where additional entity claims might be + * provided, but group membership and transient group membership lean on imported catalog + * relations. + * + * Returns a claim structure that can be passed directly to `issueToken`, with the same sub and a + * superset of `ent` claims. + */ + async resolveCatalogMemberClaims( + sub: string, + ent: string[], + logger?: Logger, + ): Promise { + const subRef: EntityName = parseEntityRef(sub, { + defaultKind: 'user', + defaultNamespace: 'default', + }); + + let entityRefs: Array = []; + if (ent) { + entityRefs = ent + .map((ref: string) => { + try { + const parsedRef = parseEntityRef(ref.toLocaleLowerCase('en-US')); + return parsedRef; + } catch { + logger?.debug( + `Failed to parse entityRef from '${sub}' ent claim: ${ref}, ignoring`, + ); + return null; + } + }) + .filter((ref): ref is EntityName => ref !== null); + } + + const filter = [subRef].concat(entityRefs).map(ref => ({ + kind: ref.kind, + 'metadata.namespace': ref.namespace, + 'metadata.name': ref.name, + })); + const entities = await this.catalogApi + .getEntities({ filter }) + .then(r => r.items); + + if (entityRefs.length !== entities.length) { + const foundEntityNames = entities.map(stringifyEntityRef); + const missingEntityNames = entityRefs + .map(stringifyEntityRef) + .filter(s => !foundEntityNames.includes(s)); + logger?.debug( + `Entities not found for '${sub}' claims: ${missingEntityNames.join()}`, + ); + } + + const memberOf = entities.flatMap( + e => + e!.relations + ?.filter(r => r.type === RELATION_MEMBER_OF) + .map(r => r.target) ?? [], + ); + + const newEnt = [...new Set(entityRefs.concat(memberOf))].map( + stringifyEntityRef, + ); + + logger?.debug(`Found claims for ${sub} in the catalog: ${newEnt.join()}`); + return { + claims: { + sub, + ent: newEnt, + }, + }; + } } From 762520d1baee561c588e6eee488da3d90d86b959 Mon Sep 17 00:00:00 2001 From: Tim Hansen Date: Tue, 3 Aug 2021 08:12:04 -0600 Subject: [PATCH 2/5] Structure args, return inflated ent Signed-off-by: Tim Hansen --- docs/auth/identity-resolver.md | 12 ++++---- .../lib/catalog/CatalogIdentityClient.test.ts | 25 +++++++---------- .../src/lib/catalog/CatalogIdentityClient.ts | 28 +++++++++---------- 3 files changed, 31 insertions(+), 34 deletions(-) diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md index 38d7567172..0dc1c7434e 100644 --- a/docs/auth/identity-resolver.md +++ b/docs/auth/identity-resolver.md @@ -130,16 +130,18 @@ export default async function createPlugin({ resolver: async ({ profile: { email } }, ctx) => { const [sub] = email?.split('@') ?? ''; // Fetch from an external system that returns entity claims like: - // 'user:default/breanna.davison' + // ['user:default/breanna.davison', ...] const ent = await externalSystemClient.getUsernames(email); // Resolve group membership from the Backstage catalog - const claims = await ctx.catalogIdentityClient.resolveCatalogMemberClaims( + const fullEnt = await ctx.catalogIdentityClient.resolveCatalogMemberClaims({ sub, ent, - ctx.logger, - ); - const token = await ctx.tokenIssuer.issueToken(claims); + logger: ctx.logger, + }); + const token = await ctx.tokenIssuer.issueToken({ + claims: { sub: id, fullEnt }, + }); return { sub, token }; }, }, diff --git a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts index 6f05bef5f8..f5c3219e10 100644 --- a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts +++ b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts @@ -118,10 +118,10 @@ describe('CatalogIdentityClient', () => { tokenIssuer, }); - const claims = await client.resolveCatalogMemberClaims('inigom', [ - 'User:default/imontoya', - 'User:reality/mpatinkin', - ]); + const claims = await client.resolveCatalogMemberClaims({ + sub: 'inigom', + ent: ['User:default/imontoya', 'User:reality/mpatinkin'], + }); expect(catalogApi.getEntities).toHaveBeenCalledWith({ filter: [ @@ -143,16 +143,11 @@ describe('CatalogIdentityClient', () => { ], }); - expect(claims).toMatchObject({ - claims: { - sub: 'inigom', - ent: [ - 'user:default/imontoya', - 'user:reality/mpatinkin', - 'group:default/team-a', - 'group:reality/screen-actors-guild', - ], - }, - }); + expect(claims).toMatchObject([ + 'user:default/imontoya', + 'user:reality/mpatinkin', + 'group:default/team-a', + 'group:reality/screen-actors-guild', + ]); }); }); diff --git a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts index c1f54f74c8..7b29ed859b 100644 --- a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts +++ b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts @@ -24,12 +24,18 @@ import { stringifyEntityRef, UserEntity, } from '@backstage/catalog-model'; -import { TokenIssuer, TokenParams } from '../../identity'; +import { TokenIssuer } from '../../identity'; type UserQuery = { annotations: Record; }; +type MemberClaimQuery = { + sub: string; + ent: string[]; + logger?: Logger; +}; + /** * A catalog client tailored for reading out identity data from the catalog. */ @@ -78,14 +84,13 @@ export class CatalogIdentityClient { * provided, but group membership and transient group membership lean on imported catalog * relations. * - * Returns a claim structure that can be passed directly to `issueToken`, with the same sub and a - * superset of `ent` claims. + * Returns a superset of the `ent` argument that can be passed directly to `issueToken` as `ent`. */ - async resolveCatalogMemberClaims( - sub: string, - ent: string[], - logger?: Logger, - ): Promise { + async resolveCatalogMemberClaims({ + sub, + ent, + logger, + }: MemberClaimQuery): Promise { const subRef: EntityName = parseEntityRef(sub, { defaultKind: 'user', defaultNamespace: 'default', @@ -139,11 +144,6 @@ export class CatalogIdentityClient { ); logger?.debug(`Found claims for ${sub} in the catalog: ${newEnt.join()}`); - return { - claims: { - sub, - ent: newEnt, - }, - }; + return newEnt; } } From 4a019712b443a63d4a217e085aa9df530368b3d4 Mon Sep 17 00:00:00 2001 From: Tim Hansen Date: Tue, 3 Aug 2021 08:25:40 -0600 Subject: [PATCH 3/5] Tweak method name Signed-off-by: Tim Hansen --- .changeset/beige-colts-pump.md | 2 +- docs/auth/identity-resolver.md | 6 +++--- .../src/lib/catalog/CatalogIdentityClient.test.ts | 4 ++-- .../auth-backend/src/lib/catalog/CatalogIdentityClient.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.changeset/beige-colts-pump.md b/.changeset/beige-colts-pump.md index a6c5fe1e1c..c85a260b31 100644 --- a/.changeset/beige-colts-pump.md +++ b/.changeset/beige-colts-pump.md @@ -2,4 +2,4 @@ '@backstage/plugin-auth-backend': patch --- -Added `resolveCatalogMemberClaims` utility to query the catalog for additional authentication claims within sign-in resolvers. +Added `resolveCatalogMembership` utility to query the catalog for additional authentication claims within sign-in resolvers. diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md index 0dc1c7434e..482d4d0314 100644 --- a/docs/auth/identity-resolver.md +++ b/docs/auth/identity-resolver.md @@ -134,7 +134,7 @@ export default async function createPlugin({ const ent = await externalSystemClient.getUsernames(email); // Resolve group membership from the Backstage catalog - const fullEnt = await ctx.catalogIdentityClient.resolveCatalogMemberClaims({ + const fullEnt = await ctx.catalogIdentityClient.resolveCatalogMembership({ sub, ent, logger: ctx.logger, @@ -149,8 +149,8 @@ export default async function createPlugin({ ... ``` -The `resolveCatalogMemberClaims` method will retrieve the `sub` and `ent` -entities from the catalog, if possible, and check for +The `resolveCatalogMembership` method will retrieve the `sub` and `ent` entities +from the catalog, if possible, and check for [memberOf](../features/software-catalog/well-known-relations.md#memberof-and-hasmember) relations to add additional entity claims. diff --git a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts index f5c3219e10..c55ae17919 100644 --- a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts +++ b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts @@ -67,7 +67,7 @@ describe('CatalogIdentityClient', () => { }); }); - it('resolveCatalogMemberClaims resolves membership', async () => { + it('resolveCatalogMembership resolves membership', async () => { const mockUsers: Array = [ { apiVersion: 'backstage.io/v1beta1', @@ -118,7 +118,7 @@ describe('CatalogIdentityClient', () => { tokenIssuer, }); - const claims = await client.resolveCatalogMemberClaims({ + const claims = await client.resolveCatalogMembership({ sub: 'inigom', ent: ['User:default/imontoya', 'User:reality/mpatinkin'], }); diff --git a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts index 7b29ed859b..179843839c 100644 --- a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts +++ b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts @@ -86,7 +86,7 @@ export class CatalogIdentityClient { * * Returns a superset of the `ent` argument that can be passed directly to `issueToken` as `ent`. */ - async resolveCatalogMemberClaims({ + async resolveCatalogMembership({ sub, ent, logger, From 4f11e67cc47ebb5830f21a9aa8335c7672b73eb2 Mon Sep 17 00:00:00 2001 From: Tim Hansen Date: Tue, 3 Aug 2021 08:45:07 -0600 Subject: [PATCH 4/5] Simplify signature Signed-off-by: Tim Hansen --- docs/auth/identity-resolver.md | 7 +- .../lib/catalog/CatalogIdentityClient.test.ts | 4 +- .../src/lib/catalog/CatalogIdentityClient.ts | 65 ++++++++----------- 3 files changed, 32 insertions(+), 44 deletions(-) diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md index 482d4d0314..e772832c1e 100644 --- a/docs/auth/identity-resolver.md +++ b/docs/auth/identity-resolver.md @@ -135,8 +135,7 @@ export default async function createPlugin({ // Resolve group membership from the Backstage catalog const fullEnt = await ctx.catalogIdentityClient.resolveCatalogMembership({ - sub, - ent, + entityRefs: [sub].concat(ent), logger: ctx.logger, }); const token = await ctx.tokenIssuer.issueToken({ @@ -149,8 +148,8 @@ export default async function createPlugin({ ... ``` -The `resolveCatalogMembership` method will retrieve the `sub` and `ent` entities -from the catalog, if possible, and check for +The `resolveCatalogMembership` method will retrieve the referenced entities from +the catalog, if possible, and check for [memberOf](../features/software-catalog/well-known-relations.md#memberof-and-hasmember) relations to add additional entity claims. diff --git a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts index c55ae17919..6ffcfd6f46 100644 --- a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts +++ b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.test.ts @@ -119,8 +119,7 @@ describe('CatalogIdentityClient', () => { }); const claims = await client.resolveCatalogMembership({ - sub: 'inigom', - ent: ['User:default/imontoya', 'User:reality/mpatinkin'], + entityRefs: ['inigom', 'User:default/imontoya', 'User:reality/mpatinkin'], }); expect(catalogApi.getEntities).toHaveBeenCalledWith({ @@ -144,6 +143,7 @@ describe('CatalogIdentityClient', () => { }); expect(claims).toMatchObject([ + 'user:default/inigom', 'user:default/imontoya', 'user:reality/mpatinkin', 'group:default/team-a', diff --git a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts index 179843839c..6e8494f805 100644 --- a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts +++ b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts @@ -31,8 +31,7 @@ type UserQuery = { }; type MemberClaimQuery = { - sub: string; - ent: string[]; + entityRefs: string[]; logger?: Logger; }; @@ -79,41 +78,33 @@ export class CatalogIdentityClient { } /** - * Resolve additional entity claims from the catalog, using the passed-in subject and entity - * claims. Designed to be used within a `signInResolver` where additional entity claims might be - * provided, but group membership and transient group membership lean on imported catalog - * relations. + * Resolve additional entity claims from the catalog, using the passed-in entity names. Designed + * to be used within a `signInResolver` where additional entity claims might be provided, but + * group membership and transient group membership lean on imported catalog relations. * - * Returns a superset of the `ent` argument that can be passed directly to `issueToken` as `ent`. + * Returns a superset of the entity names that can be passed directly to `issueToken` as `ent`. */ async resolveCatalogMembership({ - sub, - ent, + entityRefs, logger, }: MemberClaimQuery): Promise { - const subRef: EntityName = parseEntityRef(sub, { - defaultKind: 'user', - defaultNamespace: 'default', - }); + let resolvedEntityRefs: Array = []; + resolvedEntityRefs = entityRefs + .map((ref: string) => { + try { + const parsedRef = parseEntityRef(ref.toLocaleLowerCase('en-US'), { + defaultKind: 'user', + defaultNamespace: 'default', + }); + return parsedRef; + } catch { + logger?.debug(`Failed to parse entityRef from ${ref}, ignoring`); + return null; + } + }) + .filter((ref): ref is EntityName => ref !== null); - let entityRefs: Array = []; - if (ent) { - entityRefs = ent - .map((ref: string) => { - try { - const parsedRef = parseEntityRef(ref.toLocaleLowerCase('en-US')); - return parsedRef; - } catch { - logger?.debug( - `Failed to parse entityRef from '${sub}' ent claim: ${ref}, ignoring`, - ); - return null; - } - }) - .filter((ref): ref is EntityName => ref !== null); - } - - const filter = [subRef].concat(entityRefs).map(ref => ({ + const filter = resolvedEntityRefs.map(ref => ({ kind: ref.kind, 'metadata.namespace': ref.namespace, 'metadata.name': ref.name, @@ -124,12 +115,10 @@ export class CatalogIdentityClient { if (entityRefs.length !== entities.length) { const foundEntityNames = entities.map(stringifyEntityRef); - const missingEntityNames = entityRefs + const missingEntityNames = resolvedEntityRefs .map(stringifyEntityRef) .filter(s => !foundEntityNames.includes(s)); - logger?.debug( - `Entities not found for '${sub}' claims: ${missingEntityNames.join()}`, - ); + logger?.debug(`Entities not found for refs ${missingEntityNames.join()}`); } const memberOf = entities.flatMap( @@ -139,11 +128,11 @@ export class CatalogIdentityClient { .map(r => r.target) ?? [], ); - const newEnt = [...new Set(entityRefs.concat(memberOf))].map( + const newEntityRefs = [...new Set(resolvedEntityRefs.concat(memberOf))].map( stringifyEntityRef, ); - logger?.debug(`Found claims for ${sub} in the catalog: ${newEnt.join()}`); - return newEnt; + logger?.debug(`Found catalog membership: ${newEntityRefs.join()}`); + return newEntityRefs; } } From d051bc2fdaa40e2e531fb11c60e5667a63cb7e38 Mon Sep 17 00:00:00 2001 From: Tim Hansen Date: Wed, 11 Aug 2021 12:16:59 -0600 Subject: [PATCH 5/5] Minor cleanup Signed-off-by: Tim Hansen --- docs/auth/identity-resolver.md | 2 +- .../src/lib/catalog/CatalogIdentityClient.ts | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md index e772832c1e..7ec6ec7117 100644 --- a/docs/auth/identity-resolver.md +++ b/docs/auth/identity-resolver.md @@ -139,7 +139,7 @@ export default async function createPlugin({ logger: ctx.logger, }); const token = await ctx.tokenIssuer.issueToken({ - claims: { sub: id, fullEnt }, + claims: { sub, ent: fullEnt }, }); return { sub, token }; }, diff --git a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts index 6e8494f805..02fe9818cb 100644 --- a/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts +++ b/plugins/auth-backend/src/lib/catalog/CatalogIdentityClient.ts @@ -88,8 +88,7 @@ export class CatalogIdentityClient { entityRefs, logger, }: MemberClaimQuery): Promise { - let resolvedEntityRefs: Array = []; - resolvedEntityRefs = entityRefs + const resolvedEntityRefs = entityRefs .map((ref: string) => { try { const parsedRef = parseEntityRef(ref.toLocaleLowerCase('en-US'), { @@ -98,7 +97,7 @@ export class CatalogIdentityClient { }); return parsedRef; } catch { - logger?.debug(`Failed to parse entityRef from ${ref}, ignoring`); + logger?.warn(`Failed to parse entityRef from ${ref}, ignoring`); return null; } }) @@ -128,9 +127,9 @@ export class CatalogIdentityClient { .map(r => r.target) ?? [], ); - const newEntityRefs = [...new Set(resolvedEntityRefs.concat(memberOf))].map( - stringifyEntityRef, - ); + const newEntityRefs = [ + ...new Set(resolvedEntityRefs.concat(memberOf).map(stringifyEntityRef)), + ]; logger?.debug(`Found catalog membership: ${newEntityRefs.join()}`); return newEntityRefs;