From f7f20b7c3fe5986472d8c04df88f29e77b55bfef Mon Sep 17 00:00:00 2001 From: Shousan Liao Date: Fri, 3 Nov 2023 15:58:08 -0400 Subject: [PATCH] delete provider.test.ts and update auth-backend's provider Signed-off-by: Shousan Liao --- plugins/auth-backend/package.json | 1 + .../src/providers/atlassian/provider.test.ts | 145 -------------- .../src/providers/atlassian/provider.ts | 189 ++---------------- 3 files changed, 15 insertions(+), 320 deletions(-) delete mode 100644 plugins/auth-backend/src/providers/atlassian/provider.test.ts diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index b52560cbb9..edd6f5de8f 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -38,6 +38,7 @@ "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/plugin-auth-backend-module-atlassian-provider": "workspace:^", "@backstage/plugin-auth-backend-module-gcp-iap-provider": "workspace:^", "@backstage/plugin-auth-backend-module-github-provider": "workspace:^", "@backstage/plugin-auth-backend-module-gitlab-provider": "workspace:^", diff --git a/plugins/auth-backend/src/providers/atlassian/provider.test.ts b/plugins/auth-backend/src/providers/atlassian/provider.test.ts deleted file mode 100644 index 1fb987d3b0..0000000000 --- a/plugins/auth-backend/src/providers/atlassian/provider.test.ts +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { AtlassianAuthProvider } from './provider'; -import * as helpers from '../../lib/passport/PassportStrategyHelper'; -import { OAuthResult } from '../../lib/oauth'; -import { PassportProfile } from '../../lib/passport/types'; -import { AuthResolverContext } from '../types'; - -jest.mock('../../lib/passport/PassportStrategyHelper', () => { - return { - executeFrameHandlerStrategy: jest.fn(), - executeRefreshTokenStrategy: jest.fn(), - executeFetchUserProfileStrategy: jest.fn(), - }; -}); - -const mockFrameHandler = jest.spyOn( - helpers, - 'executeFrameHandlerStrategy', -) as unknown as jest.MockedFunction<() => Promise<{ result: OAuthResult }>>; - -describe('createAtlassianProvider', () => { - const provider = new AtlassianAuthProvider({ - resolverContext: {} as AuthResolverContext, - authHandler: async ({ fullProfile }) => ({ - profile: { - email: fullProfile.emails![0]!.value, - displayName: fullProfile.displayName, - picture: 'http://google.com/lols', - }, - }), - clientId: 'mock', - clientSecret: 'mock', - callbackUrl: 'mock', - scopes: 'scope', - }); - - it('should auth', async () => { - mockFrameHandler.mockResolvedValueOnce({ - result: { - fullProfile: { - photos: [ - { - value: - 'https://a1cf74336522e87f135f-2f21ace9a6cf0052456644b80fa06d4f.ssl.cf2.rackcdn.com/images/characters_opt/p-mystic-river-sean-penn.jpg', - }, - ], - emails: [{ value: 'conrad@example.com' }], - displayName: 'Conrad', - id: 'conrad', - provider: 'google', - }, - params: { - id_token: 'idToken', - scope: 'scope', - expires_in: 123, - }, - accessToken: 'accessToken', - refreshToken: 'wacka', - }, - }); - const result = await provider.handler({} as any); - expect(result).toEqual({ - response: { - providerInfo: { - accessToken: 'accessToken', - expiresInSeconds: 123, - idToken: 'idToken', - scope: 'scope', - }, - profile: { - email: 'conrad@example.com', - displayName: 'Conrad', - picture: 'http://google.com/lols', - }, - }, - refreshToken: 'wacka', - }); - }); - - it('should forward a new refresh token on refresh', async () => { - const mockRefreshToken = jest.spyOn( - helpers, - 'executeRefreshTokenStrategy', - ) as unknown as jest.MockedFunction<() => Promise<{}>>; - - mockRefreshToken.mockResolvedValueOnce({ - accessToken: 'a.b.c', - refreshToken: 'dont-forget-to-send-refresh', - params: { - id_token: 'my-id', - scope: 'read_user', - }, - }); - - const mockUserProfile = jest.spyOn( - helpers, - 'executeFetchUserProfileStrategy', - ) as unknown as jest.MockedFunction<() => Promise>; - - mockUserProfile.mockResolvedValueOnce({ - id: 'uid-my-id', - username: 'mockuser', - provider: 'atlassian', - displayName: 'Mocked User', - emails: [ - { - value: 'mockuser@gmail.com', - }, - ], - }); - - const result = await provider.refresh({} as any); - - expect(result).toEqual({ - response: { - profile: { - displayName: 'Mocked User', - email: 'mockuser@gmail.com', - picture: 'http://google.com/lols', - }, - providerInfo: { - accessToken: 'a.b.c', - idToken: 'my-id', - scope: 'read_user', - }, - }, - refreshToken: 'dont-forget-to-send-refresh', - }); - }); -}); diff --git a/plugins/auth-backend/src/providers/atlassian/provider.ts b/plugins/auth-backend/src/providers/atlassian/provider.ts index e02d899fb1..0d9bc5f42b 100644 --- a/plugins/auth-backend/src/providers/atlassian/provider.ts +++ b/plugins/auth-backend/src/providers/atlassian/provider.ts @@ -14,156 +14,18 @@ * limitations under the License. */ -import AtlassianStrategy from './strategy'; -import { - encodeState, - OAuthAdapter, - OAuthEnvironmentHandler, - OAuthHandlers, - OAuthProviderOptions, - OAuthRefreshRequest, - OAuthResponse, - OAuthResult, - OAuthStartRequest, -} from '../../lib/oauth'; -import passport from 'passport'; -import { - executeFetchUserProfileStrategy, - executeFrameHandlerStrategy, - executeRedirectStrategy, - executeRefreshTokenStrategy, - makeProfileInfo, - PassportDoneCallback, -} from '../../lib/passport'; -import { - AuthHandler, - AuthResolverContext, - OAuthStartResponse, - SignInResolver, -} from '../types'; -import express from 'express'; +import { SignInResolver, AuthHandler } from '../types'; +import { OAuthResult } from '../../lib/oauth'; import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; - -/** @public */ -export type AtlassianAuthProviderOptions = OAuthProviderOptions & { - scopes: string; - signInResolver?: SignInResolver; - authHandler: AuthHandler; - resolverContext: AuthResolverContext; -}; - -export const atlassianDefaultAuthHandler: AuthHandler = async ({ - fullProfile, - params, -}) => ({ - profile: makeProfileInfo(fullProfile, params.id_token), -}); - -export class AtlassianAuthProvider implements OAuthHandlers { - private readonly _strategy: AtlassianStrategy; - private readonly signInResolver?: SignInResolver; - private readonly authHandler: AuthHandler; - private readonly resolverContext: AuthResolverContext; - - constructor(options: AtlassianAuthProviderOptions) { - this.resolverContext = options.resolverContext; - this.authHandler = options.authHandler; - this.signInResolver = options.signInResolver; - - this._strategy = new AtlassianStrategy( - { - clientID: options.clientId, - clientSecret: options.clientSecret, - callbackURL: options.callbackUrl, - scope: options.scopes, - }, - ( - accessToken: any, - refreshToken: any, - params: any, - fullProfile: passport.Profile, - done: PassportDoneCallback, - ) => { - done(undefined, { - fullProfile, - accessToken, - refreshToken, - params, - }); - }, - ); - } - - async start(req: OAuthStartRequest): Promise { - return await executeRedirectStrategy(req, this._strategy, { - state: encodeState(req.state), - }); - } - - async handler(req: express.Request) { - const { result } = await executeFrameHandlerStrategy( - req, - this._strategy, - ); - - return { - response: await this.handleResult(result), - refreshToken: result.refreshToken, - }; - } - - private async handleResult(result: OAuthResult): Promise { - const { profile } = await this.authHandler(result, this.resolverContext); - - const response: OAuthResponse = { - providerInfo: { - idToken: result.params.id_token, - accessToken: result.accessToken, - scope: result.params.scope, - expiresInSeconds: result.params.expires_in, - }, - profile, - }; - - if (this.signInResolver) { - response.backstageIdentity = await this.signInResolver( - { - result, - profile, - }, - this.resolverContext, - ); - } - - return response; - } - - async refresh(req: OAuthRefreshRequest) { - const { accessToken, params, refreshToken } = - await executeRefreshTokenStrategy( - this._strategy, - req.refreshToken, - req.scope, - ); - - const fullProfile = await executeFetchUserProfileStrategy( - this._strategy, - accessToken, - ); - - return { - response: await this.handleResult({ - fullProfile, - params, - accessToken, - }), - refreshToken, - }; - } -} +import { createOAuthProviderFactory } from '@backstage/plugin-auth-node'; +import { + adaptLegacyOAuthHandler, + adaptLegacyOAuthSignInResolver, +} from '../../lib/legacy'; +import { atlassianAuthenticator } from '@backstage/plugin-auth-backend-module-atlassian-provider'; /** - * Auth provider integration for atlassian auth + * Auth provider integration for GitLab auth * * @public */ @@ -182,33 +44,10 @@ export const atlassian = createAuthProviderIntegration({ resolver: SignInResolver; }; }) { - return ({ providerId, globalConfig, config, resolverContext }) => - OAuthEnvironmentHandler.mapConfig(config, envConfig => { - const clientId = envConfig.getString('clientId'); - const clientSecret = envConfig.getString('clientSecret'); - const scopes = envConfig.getString('scopes'); - const customCallbackUrl = envConfig.getOptionalString('callbackUrl'); - const callbackUrl = - customCallbackUrl || - `${globalConfig.baseUrl}/${providerId}/handler/frame`; - - const authHandler: AuthHandler = - options?.authHandler ?? atlassianDefaultAuthHandler; - - const provider = new AtlassianAuthProvider({ - clientId, - clientSecret, - scopes, - callbackUrl, - authHandler, - signInResolver: options?.signIn?.resolver, - resolverContext, - }); - - return OAuthAdapter.fromConfig(globalConfig, provider, { - providerId, - callbackUrl, - }); - }); + return createOAuthProviderFactory({ + authenticator: atlassianAuthenticator, + profileTransform: adaptLegacyOAuthHandler(options?.authHandler), + signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver), + }); }, });