diff --git a/.changeset/strong-mangos-sell.md b/.changeset/strong-mangos-sell.md index c70a917a4d..aca074c7f3 100644 --- a/.changeset/strong-mangos-sell.md +++ b/.changeset/strong-mangos-sell.md @@ -2,7 +2,15 @@ '@backstage/plugin-auth-backend': patch --- -Add common signIn resolver to more providers. +Add more common predefined sign-in resolvers to auth providers. + +Add the existing resolver to more providers (already available at `google`): - `providers.microsoft.resolvers.emailLocalPartMatchingUserEntityName()` - `providers.okta.resolvers.emailLocalPartMatchingUserEntityName()` + +Add a new resolver for simple email-to-email matching: + +- `providers.google.resolvers.emailMatchingUserEntityEmail()` +- `providers.microsoft.resolvers.emailMatchingUserEntityEmail()` +- `providers.okta.resolvers.emailMatchingUserEntityEmail()` diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index ae02e859a1..80866bb959 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -872,6 +872,7 @@ export const providers: Readonly<{ ) => AuthProviderFactory; resolvers: Readonly<{ emailLocalPartMatchingUserEntityName: () => SignInResolver; + emailMatchingUserEntityEmail: () => SignInResolver; emailMatchingUserEntityAnnotation(): SignInResolver; }>; }>; @@ -890,6 +891,7 @@ export const providers: Readonly<{ ) => AuthProviderFactory; resolvers: Readonly<{ emailLocalPartMatchingUserEntityName: () => SignInResolver; + emailMatchingUserEntityEmail: () => SignInResolver; emailMatchingUserEntityAnnotation(): SignInResolver; }>; }>; @@ -947,6 +949,7 @@ export const providers: Readonly<{ ) => AuthProviderFactory; resolvers: Readonly<{ emailLocalPartMatchingUserEntityName: () => SignInResolver; + emailMatchingUserEntityEmail: () => SignInResolver; emailMatchingUserEntityAnnotation(): SignInResolver; }>; }>; diff --git a/plugins/auth-backend/src/providers/google/provider.ts b/plugins/auth-backend/src/providers/google/provider.ts index 68925e7817..f468a6415a 100644 --- a/plugins/auth-backend/src/providers/google/provider.ts +++ b/plugins/auth-backend/src/providers/google/provider.ts @@ -43,7 +43,10 @@ import { SignInResolver, } from '../types'; import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; -import { commonByEmailLocalPartResolver } from '../resolvers'; +import { + commonByEmailLocalPartResolver, + commonByEmailResolver, +} from '../resolvers'; type PrivateInfo = { refreshToken: string; @@ -248,6 +251,10 @@ export const google = createAuthProviderIntegration({ * Looks up the user by matching their email local part to the entity name. */ emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver, + /** + * Looks up the user by matching their email to the entity email. + */ + emailMatchingUserEntityEmail: () => commonByEmailResolver, /** * Looks up the user by matching their email to the `google.com/email` annotation. */ diff --git a/plugins/auth-backend/src/providers/microsoft/provider.ts b/plugins/auth-backend/src/providers/microsoft/provider.ts index cc722ad4e5..05db76fb15 100644 --- a/plugins/auth-backend/src/providers/microsoft/provider.ts +++ b/plugins/auth-backend/src/providers/microsoft/provider.ts @@ -43,7 +43,10 @@ import { AuthResolverContext, } from '../types'; import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; -import { commonByEmailLocalPartResolver } from '../resolvers'; +import { + commonByEmailLocalPartResolver, + commonByEmailResolver, +} from '../resolvers'; import { Logger } from 'winston'; import fetch from 'node-fetch'; @@ -275,6 +278,10 @@ export const microsoft = createAuthProviderIntegration({ * Looks up the user by matching their email local part to the entity name. */ emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver, + /** + * Looks up the user by matching their email to the entity email. + */ + emailMatchingUserEntityEmail: () => commonByEmailResolver, /** * Looks up the user by matching their email to the `microsoft.com/email` annotation. */ diff --git a/plugins/auth-backend/src/providers/okta/provider.ts b/plugins/auth-backend/src/providers/okta/provider.ts index 0516b4415d..a28be51586 100644 --- a/plugins/auth-backend/src/providers/okta/provider.ts +++ b/plugins/auth-backend/src/providers/okta/provider.ts @@ -43,7 +43,10 @@ import { AuthResolverContext, } from '../types'; import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; -import { commonByEmailLocalPartResolver } from '../resolvers'; +import { + commonByEmailLocalPartResolver, + commonByEmailResolver, +} from '../resolvers'; import { StateStore } from 'passport-oauth2'; type PrivateInfo = { @@ -279,6 +282,10 @@ export const okta = createAuthProviderIntegration({ * Looks up the user by matching their email local part to the entity name. */ emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver, + /** + * Looks up the user by matching their email to the entity email. + */ + emailMatchingUserEntityEmail: () => commonByEmailResolver, /** * Looks up the user by matching their email to the `okta.com/email` annotation. */ diff --git a/plugins/auth-backend/src/providers/resolvers.ts b/plugins/auth-backend/src/providers/resolvers.ts index 8a2785099f..129c29c5e4 100644 --- a/plugins/auth-backend/src/providers/resolvers.ts +++ b/plugins/auth-backend/src/providers/resolvers.ts @@ -35,3 +35,24 @@ export const commonByEmailLocalPartResolver: SignInResolver = async ( entityRef: { name: localPart }, }); }; + +/** + * A common sign-in resolver that looks up the user using their email address + * as email of the entity. + */ +export const commonByEmailResolver: SignInResolver = async ( + info, + ctx, +) => { + const { profile } = info; + + if (!profile.email) { + throw new Error('Login failed, user profile does not contain an email'); + } + + return ctx.signInWithCatalogUser({ + filter: { + 'spec.profile.email': profile.email, + }, + }); +};