diff --git a/.changeset/cold-boats-sell.md b/.changeset/cold-boats-sell.md index af0dd1e295..5b0eba7301 100644 --- a/.changeset/cold-boats-sell.md +++ b/.changeset/cold-boats-sell.md @@ -2,9 +2,22 @@ '@backstage/plugin-auth-backend-module-guest-provider': minor --- -Adds a new guest provider that maps guest users to actual tokens. This also shifts the default guest login to `user:development/guest` to reduce overlap with your production/real data. To change that (or set it back to the old default, use the new `auth.guestEntityRef` config key) like so, +Adds a new guest provider that maps guest users to actual tokens. This also shifts the default guest login to `user:development/guest` to reduce overlap with your production/real data. To change that (or set it back to the old default, use the new `auth.providers.guest.userEntityRef` config key) like so, ```yaml title=app-config.yaml auth: - guestEntityRef: user:default/guest + providers: + guest: + userEntityRef: user:default/guest +``` + +This also adds a new property to control the ownership entity refs, + +```yaml title=app-config.yaml +auth: + providers: + guest: + ownershipEntityRefs: + - guests + - development/custom ``` diff --git a/docs/auth/guest/provider.md b/docs/auth/guest/provider.md index ca5bee1d09..c730877a47 100644 --- a/docs/auth/guest/provider.md +++ b/docs/auth/guest/provider.md @@ -59,9 +59,8 @@ Similar to the other authentication providers, you have to enable the provider i auth: providers: + guest: -+ development: - // new optional property to override the default value. -+ loginAs: user:default/guest ++ userEntityRef: user:default/guest ++ development: {} ``` We need to specify that the provider is enabled for the given environment, and as there are no config values for this provider yet, you can just specify an empty object. diff --git a/packages/backend-next/src/index.ts b/packages/backend-next/src/index.ts index 58fa994658..403b122ddf 100644 --- a/packages/backend-next/src/index.ts +++ b/packages/backend-next/src/index.ts @@ -20,6 +20,7 @@ const backend = createBackend(); backend.add(import('@backstage/plugin-auth-backend')); backend.add(import('./authModuleGithubProvider')); +backend.add(import('@backstage/plugin-auth-backend-module-guest-provider')); backend.add(import('@backstage/plugin-adr-backend')); backend.add(import('@backstage/plugin-app-backend/alpha')); @@ -57,7 +58,4 @@ backend.add(import('@backstage/plugin-sonarqube-backend')); backend.add(import('@backstage/plugin-signals-backend')); backend.add(import('@backstage/plugin-notifications-backend')); -backend.add(import('@backstage/plugin-auth-backend')); -backend.add(import('@backstage/plugin-auth-backend-module-guest-provider')); - backend.start(); diff --git a/packages/create-app/templates/default-app/examples/org.yaml b/packages/create-app/templates/default-app/examples/org.yaml index 1c4fb91a1e..a10e81fc7f 100644 --- a/packages/create-app/templates/default-app/examples/org.yaml +++ b/packages/create-app/templates/default-app/examples/org.yaml @@ -7,15 +7,6 @@ metadata: spec: memberOf: [guests] --- -# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-user -apiVersion: backstage.io/v1alpha1 -kind: User -metadata: - name: guest - namespace: development -spec: - memberOf: [guests] ---- # https://backstage.io/docs/features/software-catalog/descriptor-format#kind-group apiVersion: backstage.io/v1alpha1 kind: Group diff --git a/plugins/auth-backend-module-guest-provider/config.d.ts b/plugins/auth-backend-module-guest-provider/config.d.ts index d6de29bed6..eb60492393 100644 --- a/plugins/auth-backend-module-guest-provider/config.d.ts +++ b/plugins/auth-backend-module-guest-provider/config.d.ts @@ -17,11 +17,26 @@ export interface Config { /** Configuration options for the auth plugin */ auth?: { - /** - * EXPERIMENTAL value: Allow users to configure what the guest provider logs in as. - * @visibility frontend - * @default user:default/guest - */ - guestEntityRef?: string; + providers: { + guest?: { + /** + * The entity reference to use for the guest user. + * @default user:development/guest + */ + userEntityRef?: string; + + /** + * A list of entity references to user for ownership of the guest user if the user + * is not found in the catalog. + * @default [userEntityRef] + */ + ownershipEntityRefs?: string[]; + + /** + * Allow users to sign in with the guest provider outside of their development environments. + */ + dangerouslyAllowOutsideDevelopment?: boolean; + }; + }; }; } diff --git a/plugins/auth-backend-module-guest-provider/src/module.ts b/plugins/auth-backend-module-guest-provider/src/module.ts index 75eb4f849c..7eac99b0a3 100644 --- a/plugins/auth-backend-module-guest-provider/src/module.ts +++ b/plugins/auth-backend-module-guest-provider/src/module.ts @@ -46,7 +46,7 @@ export const authModuleGuestProvider = createBackendModule({ factory: createProxyAuthProviderFactory({ authenticator: guestAuthenticator, signInResolver: signInAsGuestUser( - config.getOptionalString('auth.guestEntityRef'), + config.getConfig('auth.providers.guest'), ), }), }); diff --git a/plugins/auth-backend-module-guest-provider/src/resolvers.ts b/plugins/auth-backend-module-guest-provider/src/resolvers.ts index b2c2f8cf7d..bec2ffe12c 100644 --- a/plugins/auth-backend-module-guest-provider/src/resolvers.ts +++ b/plugins/auth-backend-module-guest-provider/src/resolvers.ts @@ -15,7 +15,9 @@ */ import { stringifyEntityRef } from '@backstage/catalog-model'; +import { Config } from '@backstage/config'; import { SignInResolver } from '@backstage/plugin-auth-node'; +import { NotImplementedError } from '@backstage/errors'; /** * Provide a default implementation of the user to resolve to. By default, this @@ -23,15 +25,26 @@ import { SignInResolver } from '@backstage/plugin-auth-node'; * catalog. If that user doesn't exist in the catalog, we will still create a * token for them so they can keep viewing. */ -export const signInAsGuestUser: (entityRef?: string) => SignInResolver<{}> = - (entityRef?: string) => async (_, ctx) => { +export const signInAsGuestUser: (config: Config) => SignInResolver<{}> = + (config: Config) => async (_, ctx) => { + if ( + process.env.NODE_ENV !== 'development' && + config.getOptionalBoolean('dangerouslyAllowOutsideDevelopment') !== true + ) { + throw new NotImplementedError( + 'The guest provider is NOT recommended for use outside of a development environment. If you want to enable this, set `auth.providers.guest.dangerouslyAllowOutsideDevelopment: true` in your app config.', + ); + } const userRef = - entityRef ?? + config.getOptionalString('userEntityRef') ?? stringifyEntityRef({ kind: 'user', namespace: 'development', name: 'guest', }); + const ownershipRefs = config.getOptionalStringArray( + 'ownershipEntityRefs', + ) ?? [userRef]; try { return ctx.signInWithCatalogUser({ entityRef: userRef }); } catch (err) { @@ -39,7 +52,7 @@ export const signInAsGuestUser: (entityRef?: string) => SignInResolver<{}> = return ctx.issueToken({ claims: { sub: userRef, - ent: [userRef], + ent: ownershipRefs, }, }); }