diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index 34a0d5c559..8a0d0a8823 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -85,10 +85,10 @@ export type BackstageIdentity = { }; // Warning: (ae-forgotten-export) The symbol "SignInResolver" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "bitbucketEmailSignInResolver" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "bitbucketDisplayNameSignInResolver" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const bitbucketEmailSignInResolver: SignInResolver; +export const bitbucketDisplayNameSignInResolver: SignInResolver; // Warning: (ae-missing-release-tag) "BitbucketOAuthResult" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -108,8 +108,11 @@ export type BitbucketOAuthResult = { // // @public (undocumented) export type BitbucketPassportProfile = Profile & { + displayName?: string; + username?: string; avatarUrl?: string; _json?: { + uuid?: string; links?: { avatar?: { href?: string; @@ -128,11 +131,21 @@ export type BitbucketProviderOptions = { }; }; +// Warning: (ae-missing-release-tag) "bitbucketUsernameSignInResolver" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const bitbucketUsernameSignInResolver: SignInResolver; + +// Warning: (ae-missing-release-tag) "bitbucketUuidSignInResolver" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const bitbucketUuidSignInResolver: SignInResolver; + // Warning: (ae-missing-release-tag) "createBitbucketProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const createBitbucketProvider: ( - options?: BitbucketProviderOptions | undefined, + options: BitbucketProviderOptions, ) => AuthProviderFactory; // Warning: (ae-missing-release-tag) "createGithubProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -519,7 +532,7 @@ export type WebMessageResponse = // // src/identity/types.d.ts:25:5 - (ae-forgotten-export) The symbol "TokenParams" needs to be exported by the entry point index.d.ts // src/identity/types.d.ts:31:9 - (ae-forgotten-export) The symbol "AnyJWK" needs to be exported by the entry point index.d.ts -// src/providers/bitbucket/provider.d.ts:57:5 - (ae-forgotten-export) The symbol "AuthHandler" needs to be exported by the entry point index.d.ts +// src/providers/bitbucket/provider.d.ts:62:5 - (ae-forgotten-export) The symbol "AuthHandler" needs to be exported by the entry point index.d.ts // src/providers/types.d.ts:109:5 - (ae-forgotten-export) The symbol "AuthProviderConfig" needs to be exported by the entry point index.d.ts // src/providers/types.d.ts:115:5 - (ae-forgotten-export) The symbol "ExperimentalIdentityResolver" needs to be exported by the entry point index.d.ts // src/providers/types.d.ts:132:8 - (tsdoc-missing-deprecation-message) The @deprecated block must include a deprecation message, e.g. describing the recommended alternative diff --git a/plugins/auth-backend/src/providers/bitbucket/index.ts b/plugins/auth-backend/src/providers/bitbucket/index.ts index f39fc5e65b..288c2e0ab1 100644 --- a/plugins/auth-backend/src/providers/bitbucket/index.ts +++ b/plugins/auth-backend/src/providers/bitbucket/index.ts @@ -16,7 +16,9 @@ export { createBitbucketProvider, - bitbucketEmailSignInResolver, + bitbucketUsernameSignInResolver, + bitbucketUuidSignInResolver, + bitbucketDisplayNameSignInResolver, } from './provider'; export type { BitbucketProviderOptions, diff --git a/plugins/auth-backend/src/providers/bitbucket/provider.ts b/plugins/auth-backend/src/providers/bitbucket/provider.ts index 1c84258273..e5b63ad3e3 100644 --- a/plugins/auth-backend/src/providers/bitbucket/provider.ts +++ b/plugins/auth-backend/src/providers/bitbucket/provider.ts @@ -70,8 +70,11 @@ export type BitbucketOAuthResult = { }; export type BitbucketPassportProfile = PassportProfile & { + displayName?: string; + username?: string; avatarUrl?: string; _json?: { + uuid?: string; links?: { avatar?: { href?: string; @@ -200,42 +203,65 @@ export class BitbucketAuthProvider implements OAuthHandlers { } } -export const bitbucketEmailSignInResolver: SignInResolver = async ( - info, - ctx, -) => { - const { profile } = info; +export const bitbucketUsernameSignInResolver: SignInResolver = + async (info, ctx) => { + const { result } = info; - if (!profile.email) { - throw new Error('Bitbucket profile contained no email'); - } + if (!result.fullProfile.username) { + throw new Error('Bitbucket profile contained no Username'); + } - const entity = await ctx.catalogIdentityClient.findUser({ - annotations: { - 'bitbucket.org/email': profile.email, - }, - }); + const entity = await ctx.catalogIdentityClient.findUser({ + annotations: { + 'bitbucket.org/username': result.fullProfile.username, + }, + }); - const claims = getEntityClaims(entity); - const token = await ctx.tokenIssuer.issueToken({ claims }); + const claims = getEntityClaims(entity); + const token = await ctx.tokenIssuer.issueToken({ claims }); - return { id: entity.metadata.name, entity, token }; -}; + return { id: entity.metadata.name, entity, token }; + }; -const bitbucketDefaultSignInResolver: SignInResolver = async ( - info, - ctx, -) => { - const { fullProfile } = info.result; +export const bitbucketDisplayNameSignInResolver: SignInResolver = + async (info, ctx) => { + const { result } = info; - const userId = fullProfile.username || fullProfile.id; + if (!result.fullProfile.displayName) { + throw new Error('Bitbucket profile contained no display name'); + } - const token = await ctx.tokenIssuer.issueToken({ - claims: { sub: userId, ent: [`user:default/${userId}`] }, - }); + const entity = await ctx.catalogIdentityClient.findUser({ + annotations: { + 'bitbucket.org/displayName': result.fullProfile.displayName, + }, + }); - return { id: userId, token }; -}; + const claims = getEntityClaims(entity); + const token = await ctx.tokenIssuer.issueToken({ claims }); + + return { id: entity.metadata.name, entity, token }; + }; + +export const bitbucketUuidSignInResolver: SignInResolver = + async (info, ctx) => { + const { result } = info; + + if (!result.fullProfile?._json?.uuid) { + throw new Error('Bitbucket profile contained no UUID'); + } + + const entity = await ctx.catalogIdentityClient.findUser({ + annotations: { + 'bitbucket.org/uuid': result.fullProfile._json?.uuid, + }, + }); + + const claims = getEntityClaims(entity); + const token = await ctx.tokenIssuer.issueToken({ claims }); + + return { id: entity.metadata.name, entity, token }; + }; export type BitbucketProviderOptions = { /** @@ -256,7 +282,7 @@ export type BitbucketProviderOptions = { }; export const createBitbucketProvider = ( - options?: BitbucketProviderOptions, + options: BitbucketProviderOptions, ): AuthProviderFactory => { return ({ providerId, @@ -276,17 +302,15 @@ export const createBitbucketProvider = ( tokenIssuer, }); - const authHandler: AuthHandler = options?.authHandler - ? options.authHandler - : async ({ fullProfile, params }) => ({ - profile: makeProfileInfo(fullProfile, params.id_token), - }); + const authHandler: AuthHandler = + options?.authHandler + ? options.authHandler + : async ({ fullProfile, params }) => ({ + profile: makeProfileInfo(fullProfile, params.id_token), + }); - const signInResolverFn = - options?.signIn?.resolver ?? bitbucketDefaultSignInResolver; - - const signInResolver: SignInResolver = info => - signInResolverFn(info, { + const signInResolver: SignInResolver = info => + options.signIn.resolver(info, { catalogIdentityClient, tokenIssuer, logger, diff --git a/plugins/auth-backend/src/providers/factories.ts b/plugins/auth-backend/src/providers/factories.ts index c4894f2757..b8e4b37d0c 100644 --- a/plugins/auth-backend/src/providers/factories.ts +++ b/plugins/auth-backend/src/providers/factories.ts @@ -26,7 +26,10 @@ import { createMicrosoftProvider } from './microsoft'; import { createOneLoginProvider } from './onelogin'; import { AuthProviderFactory } from './types'; import { createAwsAlbProvider } from './aws-alb'; -import { createBitbucketProvider } from './bitbucket'; +import { + createBitbucketProvider, + bitbucketUsernameSignInResolver, +} from './bitbucket'; export const factories: { [providerId: string]: AuthProviderFactory } = { google: createGoogleProvider(), @@ -40,5 +43,7 @@ export const factories: { [providerId: string]: AuthProviderFactory } = { oidc: createOidcProvider(), onelogin: createOneLoginProvider(), awsalb: createAwsAlbProvider(), - bitbucket: createBitbucketProvider(), + bitbucket: createBitbucketProvider({ + signIn: { resolver: bitbucketUsernameSignInResolver }, + }), };