From 085ddf4084f67d008d7c9d05d4bd597e8c7d389f Mon Sep 17 00:00:00 2001 From: Aramis Date: Sat, 27 Jan 2024 16:31:08 -0500 Subject: [PATCH] add comments Signed-off-by: Aramis Signed-off-by: aramissennyeydd --- packages/app/src/identityProviders.ts | 12 ++-- .../implementations/auth/guest/GuestAuth.ts | 2 +- .../RefreshingDirectAuthConnector.ts | 6 ++ .../src/createGuestAuthFactory.ts | 21 +++--- .../src/createGuestAuthRouteHandlers.ts | 71 +++++++------------ .../src/index.ts | 1 - .../src/resolvers.ts | 6 ++ .../src/types.ts | 6 +- 8 files changed, 60 insertions(+), 65 deletions(-) diff --git a/packages/app/src/identityProviders.ts b/packages/app/src/identityProviders.ts index 9f2ed58e8d..c59a55b9d1 100644 --- a/packages/app/src/identityProviders.ts +++ b/packages/app/src/identityProviders.ts @@ -27,6 +27,12 @@ import { } from '@backstage/core-plugin-api'; export const providers = [ + { + id: 'guest-auth-provider', + title: 'Guest', + message: 'Sign in as a guest', + apiRef: guestAuthApiRef, + }, { id: 'google-auth-provider', title: 'Google', @@ -75,10 +81,4 @@ export const providers = [ message: 'Sign In using Bitbucket Server', apiRef: bitbucketServerAuthApiRef, }, - { - id: 'guest-auth-provider', - title: 'Guest', - message: 'Sign in as a guest', - apiRef: guestAuthApiRef, - }, ]; diff --git a/packages/core-app-api/src/apis/implementations/auth/guest/GuestAuth.ts b/packages/core-app-api/src/apis/implementations/auth/guest/GuestAuth.ts index 880aa0f675..b054187373 100644 --- a/packages/core-app-api/src/apis/implementations/auth/guest/GuestAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/guest/GuestAuth.ts @@ -41,7 +41,7 @@ const DEFAULT_PROVIDER = { }; /** - * Implements a guest auth flow. + * Implements a guest auth flow. Heavily based on SAML flow with added support for refreshing the token. * * @public */ diff --git a/packages/core-app-api/src/lib/AuthConnector/RefreshingDirectAuthConnector.ts b/packages/core-app-api/src/lib/AuthConnector/RefreshingDirectAuthConnector.ts index 34969bf356..94f7486210 100644 --- a/packages/core-app-api/src/lib/AuthConnector/RefreshingDirectAuthConnector.ts +++ b/packages/core-app-api/src/lib/AuthConnector/RefreshingDirectAuthConnector.ts @@ -16,9 +16,15 @@ import { DirectAuthConnector } from './DirectAuthConnector'; +/** + * Add support for refreshing direct tokens. Used for guest authentication. + */ export class RefreshingDirectAuthConnector< DirectAuthResponse, > extends DirectAuthConnector { + /** + * Pulled from DefaultAuthConnector and adapted for use with DirectAuthConnector. + */ async refreshSession(): Promise { const res = await fetch( `${await this.buildUrl('/refresh')}&optional=true`, diff --git a/plugins/auth-backend-module-guest-provider/src/createGuestAuthFactory.ts b/plugins/auth-backend-module-guest-provider/src/createGuestAuthFactory.ts index 8331870528..acd08940a3 100644 --- a/plugins/auth-backend-module-guest-provider/src/createGuestAuthFactory.ts +++ b/plugins/auth-backend-module-guest-provider/src/createGuestAuthFactory.ts @@ -21,17 +21,21 @@ import type { SignInResolver, } from '@backstage/plugin-auth-node'; import { createGuestAuthRouteHandlers } from './createGuestAuthRouteHandlers'; -import { GuestInfo } from './types'; import { guestResolver } from './resolvers'; +const defaultTransform: ProfileTransform<{}> = async () => { + return { + profile: { + displayName: 'Guest', + }, + }; +}; + /** @public */ export function createGuestAuthProviderFactory(options?: { - profileTransform?: ProfileTransform; - signInResolver?: SignInResolver; - signInResolverFactories?: Record< - string, - SignInResolverFactory - >; + profileTransform?: ProfileTransform<{}>; + signInResolver?: SignInResolver<{}>; + signInResolverFactories?: Record>; }): AuthProviderFactory { return ctx => { const signInResolver = options?.signInResolver ?? guestResolver(); @@ -41,6 +45,7 @@ export function createGuestAuthProviderFactory(options?: { `No sign-in resolver configured for guest auth provider '${ctx.providerId}'`, ); } + const profileTransform = options?.profileTransform ?? defaultTransform; return createGuestAuthRouteHandlers({ signInResolver, @@ -48,7 +53,7 @@ export function createGuestAuthProviderFactory(options?: { appUrl: ctx.appUrl, config: ctx.config, resolverContext: ctx.resolverContext, - profileTransform: options?.profileTransform, + profileTransform, }); }; } diff --git a/plugins/auth-backend-module-guest-provider/src/createGuestAuthRouteHandlers.ts b/plugins/auth-backend-module-guest-provider/src/createGuestAuthRouteHandlers.ts index 8d1cfe78b4..ab4f9922cd 100644 --- a/plugins/auth-backend-module-guest-provider/src/createGuestAuthRouteHandlers.ts +++ b/plugins/auth-backend-module-guest-provider/src/createGuestAuthRouteHandlers.ts @@ -25,7 +25,6 @@ import { prepareBackstageIdentityResponse, sendWebMessageResponse, } from '@backstage/plugin-auth-node'; -import { GuestInfo } from './types'; /** @public */ export interface GuestAuthRouteHandlersOptions { @@ -33,77 +32,61 @@ export interface GuestAuthRouteHandlersOptions { baseUrl: string; appUrl: string; resolverContext: AuthResolverContext; - signInResolver: SignInResolver; - profileTransform?: ProfileTransform; + signInResolver: SignInResolver<{}>; + profileTransform: ProfileTransform<{}>; } -const DEFAULT_RESULT: GuestInfo = { name: 'Guest' }; - /** @public */ export function createGuestAuthRouteHandlers( options: GuestAuthRouteHandlersOptions, ): AuthProviderRouteHandlers { - const { resolverContext, signInResolver, appUrl } = options; + const { resolverContext, signInResolver, appUrl, profileTransform } = options; + + const createGuestSession = async (): Promise> => { + const { profile } = await profileTransform({}, resolverContext); + + const identity = await signInResolver( + { profile, result: {} }, + resolverContext, + ); - const defaultTransform: ProfileTransform = async result => { return { - profile: { - displayName: result.name, - }, + profile, + providerInfo: {}, + backstageIdentity: prepareBackstageIdentityResponse(identity), }; }; - const profileTransform = options.profileTransform ?? defaultTransform; return { async start(_, res): Promise { // We are the auth provider for guests, skip this step. res.redirect('handler/frame'); }, + /** + * This is where we create the token for the guest user. You can override the + * entityRef for the guest user with `signInResolver`. + */ async frameHandler(_, res): Promise { - const { profile } = await profileTransform( - DEFAULT_RESULT, - resolverContext, - ); - const response: ClientAuthResponse = { - profile, - providerInfo: DEFAULT_RESULT, - }; - if (signInResolver) { - const identity = await signInResolver( - { profile, result: DEFAULT_RESULT }, - resolverContext, - ); - response.backstageIdentity = prepareBackstageIdentityResponse(identity); - } + const session = await createGuestSession(); // post message back to popup if successful sendWebMessageResponse(res, appUrl, { type: 'authorization_response', - response, + response: session, }); }, + /** + * Support refreshing the guest user's token. This should just improve the experience of + * browsing while in guest mode. + */ async refresh(this: never, _: Request, res: Response): Promise { - const { profile } = await profileTransform( - DEFAULT_RESULT, - resolverContext, - ); - - const identity = await signInResolver( - { profile, result: DEFAULT_RESULT }, - resolverContext, - ); - - const response: ClientAuthResponse<{}> = { - profile, - providerInfo: DEFAULT_RESULT, - backstageIdentity: prepareBackstageIdentityResponse(identity), - }; - - res.status(200).json(response); + const session = await createGuestSession(); + res.status(200).json(session); }, async logout(_, res) { + // If we don't send a response or it gets cached into a 204, the page will hang. res.end(); }, }; diff --git a/plugins/auth-backend-module-guest-provider/src/index.ts b/plugins/auth-backend-module-guest-provider/src/index.ts index b1a89763b9..0c4a382a87 100644 --- a/plugins/auth-backend-module-guest-provider/src/index.ts +++ b/plugins/auth-backend-module-guest-provider/src/index.ts @@ -21,5 +21,4 @@ */ export { createGuestAuthProviderFactory } from './createGuestAuthFactory'; -export type { GuestInfo } from './types'; export { authModuleGuestProvider as default } from './module'; diff --git a/plugins/auth-backend-module-guest-provider/src/resolvers.ts b/plugins/auth-backend-module-guest-provider/src/resolvers.ts index 47d340f013..5922530c5c 100644 --- a/plugins/auth-backend-module-guest-provider/src/resolvers.ts +++ b/plugins/auth-backend-module-guest-provider/src/resolvers.ts @@ -17,6 +17,12 @@ import { stringifyEntityRef } from '@backstage/catalog-model'; import { createSignInResolverFactory } from '@backstage/plugin-auth-node'; +/** + * Provide a default implementation of the user to resolve to. By default, this + * is `user:default/guest`. We will attempt to get that user if they're in the + * 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 guestResolver = createSignInResolverFactory({ create() { return async (_, ctx) => { diff --git a/plugins/auth-backend-module-guest-provider/src/types.ts b/plugins/auth-backend-module-guest-provider/src/types.ts index 9d0ace0a33..c831014cb5 100644 --- a/plugins/auth-backend-module-guest-provider/src/types.ts +++ b/plugins/auth-backend-module-guest-provider/src/types.ts @@ -16,10 +16,6 @@ import { ProfileTransform } from '@backstage/plugin-auth-node'; -export type GuestInfo = { - name: string; -}; - export interface GuestAuthenticator { - defaultProfileTransform: ProfileTransform; + defaultProfileTransform: ProfileTransform<{}>; }