From 9c8a2e2116f139c876bfe15269ef462f8c4e617a Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 8 Apr 2022 13:07:25 +0200 Subject: [PATCH] auth-backend: migrate github provider to use resolver context Signed-off-by: Patrik Oldsberg --- .../src/providers/github/provider.test.ts | 48 ++++--------- .../src/providers/github/provider.ts | 67 +++---------------- 2 files changed, 22 insertions(+), 93 deletions(-) diff --git a/plugins/auth-backend/src/providers/github/provider.test.ts b/plugins/auth-backend/src/providers/github/provider.test.ts index 37dd4115ed..e425cef0ff 100644 --- a/plugins/auth-backend/src/providers/github/provider.test.ts +++ b/plugins/auth-backend/src/providers/github/provider.test.ts @@ -15,9 +15,6 @@ */ import { Profile as PassportProfile } from 'passport'; -import { getVoidLogger } from '@backstage/backend-common'; -import { TokenIssuer } from '../../identity/types'; -import { CatalogIdentityClient } from '../../lib/catalog'; import { GithubAuthProvider, GithubOAuthResult, @@ -26,6 +23,7 @@ import { import * as helpers from '../../lib/passport/PassportStrategyHelper'; import { makeProfileInfo } from '../../lib/passport/PassportStrategyHelper'; import { OAuthStartRequest, encodeState } from '../../lib/oauth'; +import { AuthResolverContext } from '../types'; const mockFrameHandler = jest.spyOn( helpers, @@ -38,25 +36,12 @@ const mockFrameHandler = jest.spyOn( >; describe('GithubAuthProvider', () => { - const tokenIssuer: TokenIssuer = { - listPublicKeys: jest.fn(), - async issueToken(params) { - return `token-for-${params.claims.sub}`; - }, - }; - const catalogIdentityClient = { - findUser: jest.fn(), - resolveCatalogMembership: async ({ - entityRefs, - }: { - entityRefs: string[]; - }) => entityRefs, - } as unknown as CatalogIdentityClient; - const provider = new GithubAuthProvider({ - logger: getVoidLogger(), - catalogIdentityClient: catalogIdentityClient, - tokenIssuer: tokenIssuer as unknown as TokenIssuer, + resolverContext: { + signInWithCatalogUser: jest.fn(({ entityRef }) => ({ + token: `token-for-user:${entityRef.name}`, + })), + } as unknown as AuthResolverContext, signInResolver: githubUsernameEntityNameSignInResolver, authHandler: async ({ fullProfile }) => ({ profile: makeProfileInfo(fullProfile), @@ -96,8 +81,7 @@ describe('GithubAuthProvider', () => { const expected = { backstageIdentity: { - id: 'jimmymarkum', - token: 'token-for-user:default/jimmymarkum', + token: 'token-for-user:jimmymarkum', }, providerInfo: { accessToken: '19xasczxcm9n7gacn9jdgm19me', @@ -142,8 +126,7 @@ describe('GithubAuthProvider', () => { const expected = { backstageIdentity: { - id: 'jimmymarkum', - token: 'token-for-user:default/jimmymarkum', + token: 'token-for-user:jimmymarkum', }, providerInfo: { accessToken: '19xasczxcm9n7gacn9jdgm19me', @@ -186,8 +169,7 @@ describe('GithubAuthProvider', () => { }; const expected = { backstageIdentity: { - id: 'jimmymarkum', - token: 'token-for-user:default/jimmymarkum', + token: 'token-for-user:jimmymarkum', }, providerInfo: { accessToken: '19xasczxcm9n7gacn9jdgm19me', @@ -230,8 +212,7 @@ describe('GithubAuthProvider', () => { const expected = { backstageIdentity: { - id: 'daveboyle', - token: 'token-for-user:default/daveboyle', + token: 'token-for-user:daveboyle', }, providerInfo: { accessToken: @@ -276,8 +257,7 @@ describe('GithubAuthProvider', () => { expect(response).toEqual({ response: { backstageIdentity: { - id: 'daveboyle', - token: 'token-for-user:default/daveboyle', + token: 'token-for-user:daveboyle', }, providerInfo: { accessToken: 'a.b.c', @@ -352,8 +332,7 @@ describe('GithubAuthProvider', () => { expect(result).toEqual({ response: { backstageIdentity: { - id: 'mockuser', - token: 'token-for-user:default/mockuser', + token: 'token-for-user:mockuser', }, profile: { displayName: 'Mocked User', @@ -404,8 +383,7 @@ describe('GithubAuthProvider', () => { expect(result).toEqual({ response: { backstageIdentity: { - id: 'mockuser', - token: 'token-for-user:default/mockuser', + token: 'token-for-user:mockuser', }, profile: { displayName: 'Mocked User', diff --git a/plugins/auth-backend/src/providers/github/provider.ts b/plugins/auth-backend/src/providers/github/provider.ts index 44db24772b..770715d0ae 100644 --- a/plugins/auth-backend/src/providers/github/provider.ts +++ b/plugins/auth-backend/src/providers/github/provider.ts @@ -14,12 +14,7 @@ * limitations under the License. */ -import { - DEFAULT_NAMESPACE, - stringifyEntityRef, -} from '@backstage/catalog-model'; import express from 'express'; -import { Logger } from 'winston'; import { Profile as PassportProfile } from 'passport'; import { Strategy as GithubStrategy } from 'passport-github2'; import { @@ -36,6 +31,7 @@ import { AuthHandler, SignInResolver, StateEncoder, + AuthResolverContext, } from '../types'; import { OAuthAdapter, @@ -46,8 +42,6 @@ import { encodeState, OAuthRefreshRequest, } from '../../lib/oauth'; -import { CatalogIdentityClient } from '../../lib/catalog'; -import { TokenIssuer } from '../../identity'; const ACCESS_TOKEN_PREFIX = 'access-token.'; @@ -76,27 +70,21 @@ export type GithubAuthProviderOptions = OAuthProviderOptions & { signInResolver?: SignInResolver; authHandler: AuthHandler; stateEncoder: StateEncoder; - tokenIssuer: TokenIssuer; - catalogIdentityClient: CatalogIdentityClient; - logger: Logger; + resolverContext: AuthResolverContext; }; export class GithubAuthProvider implements OAuthHandlers { private readonly _strategy: GithubStrategy; private readonly signInResolver?: SignInResolver; private readonly authHandler: AuthHandler; - private readonly tokenIssuer: TokenIssuer; - private readonly catalogIdentityClient: CatalogIdentityClient; - private readonly logger: Logger; + private readonly resolverContext: AuthResolverContext; private readonly stateEncoder: StateEncoder; constructor(options: GithubAuthProviderOptions) { this.signInResolver = options.signInResolver; this.authHandler = options.authHandler; this.stateEncoder = options.stateEncoder; - this.tokenIssuer = options.tokenIssuer; - this.catalogIdentityClient = options.catalogIdentityClient; - this.logger = options.logger; + this.resolverContext = options.resolverContext; this._strategy = new GithubStrategy( { clientID: options.clientId, @@ -198,12 +186,7 @@ export class GithubAuthProvider implements OAuthHandlers { } private async handleResult(result: GithubOAuthResult) { - const context = { - logger: this.logger, - catalogIdentityClient: this.catalogIdentityClient, - tokenIssuer: this.tokenIssuer, - }; - const { profile } = await this.authHandler(result, context); + const { profile } = await this.authHandler(result, this.resolverContext); const expiresInStr = result.params.expires_in; let expiresInSeconds = @@ -217,7 +200,7 @@ export class GithubAuthProvider implements OAuthHandlers { result, profile, }, - context, + this.resolverContext, ); // GitHub sessions last longer than Backstage sessions, so if we're using @@ -254,23 +237,7 @@ export const githubUsernameEntityNameSignInResolver: SignInResolver< throw new Error(`GitHub user profile does not contain a username`); } - const entityRef = stringifyEntityRef({ - kind: 'User', - namespace: DEFAULT_NAMESPACE, - name: userId, - }); - const ownershipEntityRefs = - await ctx.catalogIdentityClient.resolveCatalogMembership({ - entityRefs: [entityRef], - }); - const token = await ctx.tokenIssuer.issueToken({ - claims: { - sub: entityRef, - ent: ownershipEntityRefs, - }, - }); - - return { id: userId, token }; + return ctx.signInWithCatalogUser({ entityRef: { name: userId } }); }; /** @@ -347,15 +314,7 @@ export const createGithubProvider = (options?: { */ stateEncoder?: StateEncoder; }): AuthProviderFactory => { - return ({ - providerId, - globalConfig, - config, - tokenIssuer, - tokenManager, - catalogApi, - logger, - }) => + return ({ providerId, globalConfig, config, resolverContext }) => OAuthEnvironmentHandler.mapConfig(config, envConfig => { const clientId = envConfig.getString('clientId'); const clientSecret = envConfig.getString('clientSecret'); @@ -376,11 +335,6 @@ export const createGithubProvider = (options?: { customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`; - const catalogIdentityClient = new CatalogIdentityClient({ - catalogApi, - tokenManager, - }); - const authHandler: AuthHandler = options?.authHandler ? options.authHandler : async ({ fullProfile }) => ({ @@ -402,16 +356,13 @@ export const createGithubProvider = (options?: { authorizationUrl, signInResolver: options?.signIn?.resolver, authHandler, - tokenIssuer, - catalogIdentityClient, stateEncoder, - logger, + resolverContext, }); return OAuthAdapter.fromConfig(globalConfig, provider, { persistScopes: true, providerId, - tokenIssuer, callbackUrl, }); });