update to a proxied sign in identity instead of a separate guest provider
Signed-off-by: Aramis <sennyeyaramis@gmail.com> Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
This commit is contained in:
+4
-1
@@ -400,7 +400,10 @@ auth:
|
||||
myproxy:
|
||||
development: {}
|
||||
guest:
|
||||
development: {}
|
||||
development:
|
||||
signIn:
|
||||
resolvers:
|
||||
- resolver: guestUser
|
||||
|
||||
costInsights:
|
||||
engineerCost: 200000
|
||||
|
||||
@@ -35,7 +35,6 @@ import {
|
||||
createFetchApi,
|
||||
FetchMiddlewares,
|
||||
VMwareCloudAuth,
|
||||
GuestAuth,
|
||||
} from '@backstage/core-app-api';
|
||||
|
||||
import {
|
||||
@@ -59,7 +58,6 @@ import {
|
||||
bitbucketServerAuthApiRef,
|
||||
atlassianAuthApiRef,
|
||||
vmwareCloudAuthApiRef,
|
||||
guestAuthApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import {
|
||||
permissionApiRef,
|
||||
@@ -279,21 +277,6 @@ export const apis = [
|
||||
});
|
||||
},
|
||||
}),
|
||||
|
||||
createApiFactory({
|
||||
api: guestAuthApiRef,
|
||||
deps: {
|
||||
discoveryApi: discoveryApiRef,
|
||||
configApi: configApiRef,
|
||||
},
|
||||
factory: ({ discoveryApi, configApi }) => {
|
||||
return GuestAuth.create({
|
||||
configApi,
|
||||
discoveryApi,
|
||||
environment: configApi.getOptionalString('auth.environment'),
|
||||
});
|
||||
},
|
||||
}),
|
||||
createApiFactory({
|
||||
api: permissionApiRef,
|
||||
deps: {
|
||||
|
||||
@@ -128,7 +128,7 @@ const app = createApp({
|
||||
return (
|
||||
<SignInPage
|
||||
{...props}
|
||||
providers={['custom', ...providers]}
|
||||
providers={['guest', 'custom', ...providers]}
|
||||
title="Select a sign-in method"
|
||||
align="center"
|
||||
/>
|
||||
|
||||
@@ -23,16 +23,9 @@ import {
|
||||
oneloginAuthApiRef,
|
||||
bitbucketAuthApiRef,
|
||||
bitbucketServerAuthApiRef,
|
||||
guestAuthApiRef,
|
||||
} 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',
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"@backstage/plugin-app-backend": "workspace:^",
|
||||
"@backstage/plugin-auth-backend": "workspace:^",
|
||||
"@backstage/plugin-auth-backend-module-github-provider": "workspace:^",
|
||||
"@backstage/plugin-auth-backend-module-guest-provider": "workspace:^",
|
||||
"@backstage/plugin-auth-node": "workspace:^",
|
||||
"@backstage/plugin-azure-devops-backend": "workspace:^",
|
||||
"@backstage/plugin-badges-backend": "workspace:^",
|
||||
|
||||
@@ -57,4 +57,7 @@ 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();
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 {
|
||||
AuthRequestOptions,
|
||||
BackstageIdentityApi,
|
||||
ProfileInfo,
|
||||
ProfileInfoApi,
|
||||
SessionApi,
|
||||
SessionState,
|
||||
BackstageIdentityResponse,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { Observable } from '@backstage/types';
|
||||
import { RefreshingAuthSessionManager } from '../../../../lib/AuthSessionManager';
|
||||
import { SessionManager } from '../../../../lib/AuthSessionManager/types';
|
||||
import { AuthApiCreateOptions } from '../types';
|
||||
import { RefreshingDirectAuthConnector } from '../../../../lib/AuthConnector/RefreshingDirectAuthConnector';
|
||||
|
||||
type GuestSession = {
|
||||
profile: ProfileInfo;
|
||||
backstageIdentity: BackstageIdentityResponse;
|
||||
};
|
||||
|
||||
const DEFAULT_PROVIDER = {
|
||||
id: 'guest',
|
||||
title: 'Guest',
|
||||
icon: () => null,
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a guest auth flow. Heavily based on SAML flow with added support for refreshing the token.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export default class GuestAuth
|
||||
implements ProfileInfoApi, BackstageIdentityApi, SessionApi
|
||||
{
|
||||
static create(options: AuthApiCreateOptions) {
|
||||
const {
|
||||
discoveryApi,
|
||||
environment = 'development',
|
||||
provider = DEFAULT_PROVIDER,
|
||||
} = options;
|
||||
|
||||
const connector = new RefreshingDirectAuthConnector<GuestSession>({
|
||||
discoveryApi,
|
||||
environment,
|
||||
provider,
|
||||
});
|
||||
|
||||
const sessionManager = new RefreshingAuthSessionManager<GuestSession>({
|
||||
connector,
|
||||
defaultScopes: new Set([]),
|
||||
sessionScopes: (_: GuestSession) => new Set<string>(),
|
||||
sessionShouldRefresh: (session: GuestSession) => {
|
||||
let min = Infinity;
|
||||
if (session.backstageIdentity?.expiresAt) {
|
||||
min = Math.min(
|
||||
min,
|
||||
(session.backstageIdentity.expiresAt.getTime() - Date.now()) / 1000,
|
||||
);
|
||||
}
|
||||
return min < 60 * 5;
|
||||
},
|
||||
});
|
||||
|
||||
return new GuestAuth({ sessionManager });
|
||||
}
|
||||
|
||||
sessionState$(): Observable<SessionState> {
|
||||
return this.sessionManager.sessionState$();
|
||||
}
|
||||
|
||||
private readonly sessionManager: SessionManager<GuestSession>;
|
||||
|
||||
private constructor(options: {
|
||||
sessionManager: SessionManager<GuestSession>;
|
||||
}) {
|
||||
this.sessionManager = options.sessionManager;
|
||||
}
|
||||
|
||||
async signIn() {
|
||||
await this.getBackstageIdentity({});
|
||||
}
|
||||
async signOut() {
|
||||
await this.sessionManager.removeSession();
|
||||
}
|
||||
|
||||
async getBackstageIdentity(
|
||||
options: AuthRequestOptions = {},
|
||||
): Promise<BackstageIdentityResponse | undefined> {
|
||||
const session = await this.sessionManager.getSession(options);
|
||||
return session?.backstageIdentity;
|
||||
}
|
||||
|
||||
async getProfile(options: AuthRequestOptions = {}) {
|
||||
const session = await this.sessionManager.getSession(options);
|
||||
return session?.profile;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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.
|
||||
*/
|
||||
export { default as GuestAuth } from './GuestAuth';
|
||||
@@ -26,5 +26,4 @@ export * from './bitbucket';
|
||||
export * from './bitbucketServer';
|
||||
export * from './atlassian';
|
||||
export * from './vmwareCloud';
|
||||
export * from './guest';
|
||||
export type { OAuthApiCreateOptions, AuthApiCreateOptions } from './types';
|
||||
|
||||
@@ -70,7 +70,7 @@ export class DirectAuthConnector<DirectAuthResponse> {
|
||||
}
|
||||
}
|
||||
|
||||
protected async buildUrl(path: string): Promise<string> {
|
||||
private async buildUrl(path: string): Promise<string> {
|
||||
const baseUrl = await this.discoveryApi.getBaseUrl('auth');
|
||||
return `${baseUrl}/${this.provider.id}${path}?env=${this.environment}`;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ import {
|
||||
BackstageUserIdentity,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
/**
|
||||
* @deprecated Use `@backstage/plugin-auth-backend-module-guest-provider` instead.
|
||||
*/
|
||||
export class GuestUserIdentity implements IdentityApi {
|
||||
getUserId(): string {
|
||||
return 'guest';
|
||||
|
||||
@@ -20,39 +20,55 @@ import Button from '@material-ui/core/Button';
|
||||
import { InfoCard } from '../InfoCard/InfoCard';
|
||||
import { GridItem } from './styles';
|
||||
import { ProviderComponent, ProviderLoader, SignInProvider } from './types';
|
||||
import { GuestUserIdentity } from './GuestUserIdentity';
|
||||
import { ProxiedSignInIdentity } from '../ProxiedSignInPage/ProxiedSignInIdentity';
|
||||
import { discoveryApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
|
||||
const Component: ProviderComponent = ({ onSignInStarted, onSignInSuccess }) => (
|
||||
<GridItem>
|
||||
<InfoCard
|
||||
title="Guest"
|
||||
variant="fullHeight"
|
||||
actions={
|
||||
<Button
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
onSignInStarted();
|
||||
onSignInSuccess(new GuestUserIdentity());
|
||||
}}
|
||||
>
|
||||
Enter
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Typography variant="body1">
|
||||
Enter as a Guest User.
|
||||
<br />
|
||||
You will not have a verified identity,
|
||||
<br />
|
||||
meaning some features might be unavailable.
|
||||
</Typography>
|
||||
</InfoCard>
|
||||
</GridItem>
|
||||
);
|
||||
const Component: ProviderComponent = ({ onSignInStarted, onSignInSuccess }) => {
|
||||
const discoveryApi = useApi(discoveryApiRef);
|
||||
return (
|
||||
<GridItem>
|
||||
<InfoCard
|
||||
title="Guest"
|
||||
variant="fullHeight"
|
||||
actions={
|
||||
<Button
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
onSignInStarted();
|
||||
onSignInSuccess(
|
||||
new ProxiedSignInIdentity({
|
||||
provider: 'guest',
|
||||
discoveryApi,
|
||||
}),
|
||||
);
|
||||
}}
|
||||
>
|
||||
Enter
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Typography variant="body1">Sign in as a Guest.</Typography>
|
||||
</InfoCard>
|
||||
</GridItem>
|
||||
);
|
||||
};
|
||||
|
||||
const loader: ProviderLoader = async () => {
|
||||
return new GuestUserIdentity();
|
||||
const loader: ProviderLoader = async apis => {
|
||||
const identity = new ProxiedSignInIdentity({
|
||||
provider: 'guest',
|
||||
discoveryApi: apis.get(discoveryApiRef)!,
|
||||
});
|
||||
|
||||
await identity.start();
|
||||
|
||||
const identityResponse = await identity.getBackstageIdentity();
|
||||
|
||||
if (!identityResponse) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return identity;
|
||||
};
|
||||
|
||||
export const guestProvider: SignInProvider = { Component, loader };
|
||||
|
||||
@@ -43,7 +43,6 @@ export type SignInProviderType = {
|
||||
};
|
||||
|
||||
const signInProviders: { [key: string]: SignInProvider } = {
|
||||
/** @deprecated Use `@backstage/plugin-auth-backend-module-guest-provider` */
|
||||
guest: guestProvider,
|
||||
custom: customProvider,
|
||||
common: commonProvider,
|
||||
|
||||
@@ -469,15 +469,3 @@ export const vmwareCloudAuthApiRef: ApiRef<
|
||||
> = createApiRef({
|
||||
id: 'core.auth.vmware-cloud',
|
||||
});
|
||||
|
||||
/**
|
||||
* Provides guest authentication support.
|
||||
*
|
||||
* @public
|
||||
* @remarks
|
||||
*/
|
||||
export const guestAuthApiRef: ApiRef<
|
||||
ProfileInfoApi & BackstageIdentityApi & SessionApi
|
||||
> = createApiRef({
|
||||
id: 'core.auth.guest',
|
||||
});
|
||||
|
||||
@@ -292,7 +292,6 @@ describe('createApp', () => {
|
||||
<api:core.auth.bitbucket-server out=[core.api.factory] />
|
||||
<api:core.auth.atlassian out=[core.api.factory] />
|
||||
<api:core.auth.vmware-cloud out=[core.api.factory] />
|
||||
<api:core.auth.guest out=[core.api.factory] />
|
||||
<api:plugin.permission.api out=[core.api.factory] />
|
||||
]
|
||||
</app>"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This module provides a guest auth provider implementation for `@backstage/plugin-auth-backend`. This is meant to supersede the existing `'guest'` option for authentication that does not emit tokens and is completely stored as frontend state.
|
||||
|
||||
**NOTE**: This provider should only ever be enabled for `development` or `test`. Enabling this for production is strongly discouraged as it would give everyone a way to bypass your other authentication methods.
|
||||
**NOTE**: This provider should only ever be enabled for `development`. This package is explicitly disabled for non-development environments.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -20,42 +20,15 @@ const backend = createBackend();
|
||||
backend.start();
|
||||
```
|
||||
|
||||
#### Old Backend
|
||||
|
||||
This module was also backported for the old backend and can be used like so,
|
||||
|
||||
```diff
|
||||
+import {
|
||||
+ providers,
|
||||
+} from '@backstage/plugin-auth-backend';
|
||||
....
|
||||
return await createRouter({
|
||||
...
|
||||
providerFactories: {
|
||||
gitlab: providers.gitlab(),
|
||||
+ guest: providers.guest(),
|
||||
...
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
### Frontend
|
||||
|
||||
Add the following to your `SignInPage` providers,
|
||||
|
||||
```diff
|
||||
+import {
|
||||
+ guestAuthApiRef,
|
||||
+} from '@backstage/core-plugin-api';
|
||||
|
||||
const providers = [
|
||||
+ {
|
||||
+ id: 'guest-auth-provider',
|
||||
+ title: 'Guest',
|
||||
+ message: 'Sign in as a guest',
|
||||
+ apiRef: guestAuthApiRef,
|
||||
+ },
|
||||
+ 'guest',
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
### Config
|
||||
|
||||
+11
-1
@@ -1,3 +1,5 @@
|
||||
import { createProxyAuthenticator } from '@backstage/plugin-auth-node';
|
||||
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
@@ -13,4 +15,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { guest } from './provider';
|
||||
export const guestAuthenticator = createProxyAuthenticator({
|
||||
defaultProfileTransform: async () => {
|
||||
return { profile: {} };
|
||||
},
|
||||
initialize() {},
|
||||
async authenticate() {
|
||||
return { result: {} };
|
||||
},
|
||||
});
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 { SignInResolverFactory } from '@backstage/plugin-auth-node';
|
||||
import type {
|
||||
AuthProviderFactory,
|
||||
ProfileTransform,
|
||||
SignInResolver,
|
||||
} from '@backstage/plugin-auth-node';
|
||||
import { createGuestAuthRouteHandlers } from './createGuestAuthRouteHandlers';
|
||||
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<{}, unknown>>;
|
||||
}): AuthProviderFactory {
|
||||
return ctx => {
|
||||
const signInResolver = options?.signInResolver ?? guestResolver();
|
||||
|
||||
if (!signInResolver) {
|
||||
throw new Error(
|
||||
`No sign-in resolver configured for guest auth provider '${ctx.providerId}'`,
|
||||
);
|
||||
}
|
||||
const profileTransform = options?.profileTransform ?? defaultTransform;
|
||||
|
||||
return createGuestAuthRouteHandlers({
|
||||
signInResolver,
|
||||
baseUrl: ctx.baseUrl,
|
||||
appUrl: ctx.appUrl,
|
||||
config: ctx.config,
|
||||
resolverContext: ctx.resolverContext,
|
||||
profileTransform,
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -1,91 +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 type { Request, Response } from 'express';
|
||||
import type { Config } from '@backstage/config';
|
||||
import {
|
||||
AuthProviderRouteHandlers,
|
||||
AuthResolverContext,
|
||||
ClientAuthResponse,
|
||||
ProfileTransform,
|
||||
SignInResolver,
|
||||
prepareBackstageIdentityResponse,
|
||||
sendWebMessageResponse,
|
||||
} from '@backstage/plugin-auth-node';
|
||||
|
||||
export interface GuestAuthRouteHandlersOptions {
|
||||
config: Config;
|
||||
baseUrl: string;
|
||||
appUrl: string;
|
||||
resolverContext: AuthResolverContext;
|
||||
signInResolver: SignInResolver<{}>;
|
||||
profileTransform: ProfileTransform<{}>;
|
||||
}
|
||||
|
||||
export function createGuestAuthRouteHandlers(
|
||||
options: GuestAuthRouteHandlersOptions,
|
||||
): AuthProviderRouteHandlers {
|
||||
const { resolverContext, signInResolver, appUrl, profileTransform } = options;
|
||||
|
||||
const createGuestSession = async (): Promise<ClientAuthResponse<{}>> => {
|
||||
const { profile } = await profileTransform({}, resolverContext);
|
||||
|
||||
const identity = await signInResolver(
|
||||
{ profile, result: {} },
|
||||
resolverContext,
|
||||
);
|
||||
|
||||
return {
|
||||
profile,
|
||||
providerInfo: {},
|
||||
backstageIdentity: prepareBackstageIdentityResponse(identity),
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
async start(_, res): Promise<void> {
|
||||
// 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<void> {
|
||||
const session = await createGuestSession();
|
||||
// post message back to popup if successful
|
||||
sendWebMessageResponse(res, appUrl, {
|
||||
type: 'authorization_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<void> {
|
||||
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();
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -20,5 +20,4 @@
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export { createGuestAuthProviderFactory } from './createGuestAuthFactory';
|
||||
export { authModuleGuestProvider as default } from './module';
|
||||
|
||||
@@ -17,8 +17,12 @@ import {
|
||||
coreServices,
|
||||
createBackendModule,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { authProvidersExtensionPoint } from '@backstage/plugin-auth-node';
|
||||
import { createGuestAuthProviderFactory } from './createGuestAuthFactory';
|
||||
import {
|
||||
authProvidersExtensionPoint,
|
||||
createProxyAuthProviderFactory,
|
||||
} from '@backstage/plugin-auth-node';
|
||||
import { guestAuthenticator } from './authenticator';
|
||||
import { signInAsGuestUser } from './resolvers';
|
||||
|
||||
/** @public */
|
||||
export const authModuleGuestProvider = createBackendModule({
|
||||
@@ -31,14 +35,17 @@ export const authModuleGuestProvider = createBackendModule({
|
||||
providers: authProvidersExtensionPoint,
|
||||
},
|
||||
async init({ providers }) {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
throw new Error(
|
||||
'Guest provider does not support authenticating production workloads.',
|
||||
);
|
||||
}
|
||||
providers.registerProvider({
|
||||
providerId: 'guest',
|
||||
factory: createGuestAuthProviderFactory(),
|
||||
factory: createProxyAuthProviderFactory({
|
||||
authenticator: guestAuthenticator,
|
||||
signInResolver: signInAsGuestUser,
|
||||
}),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { stringifyEntityRef } from '@backstage/catalog-model';
|
||||
import { createSignInResolverFactory } from '@backstage/plugin-auth-node';
|
||||
import { SignInResolver } from '@backstage/plugin-auth-node';
|
||||
|
||||
/**
|
||||
* Provide a default implementation of the user to resolve to. By default, this
|
||||
@@ -23,24 +23,20 @@ import { createSignInResolverFactory } 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 guestResolver = createSignInResolverFactory({
|
||||
create() {
|
||||
return async (_, ctx) => {
|
||||
const userRef = stringifyEntityRef({
|
||||
kind: 'user',
|
||||
name: 'guest',
|
||||
});
|
||||
try {
|
||||
return ctx.signInWithCatalogUser({ entityRef: userRef });
|
||||
} catch (err) {
|
||||
// We can't guarantee that a guest user exists in the catalog, so we issue a token directly,
|
||||
return ctx.issueToken({
|
||||
claims: {
|
||||
sub: userRef,
|
||||
ent: [userRef],
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
export const signInAsGuestUser: SignInResolver<{}> = async (_, ctx) => {
|
||||
const userRef = stringifyEntityRef({
|
||||
kind: 'user',
|
||||
name: 'guest',
|
||||
});
|
||||
try {
|
||||
return ctx.signInWithCatalogUser({ entityRef: userRef });
|
||||
} catch (err) {
|
||||
// We can't guarantee that a guest user exists in the catalog, so we issue a token directly,
|
||||
return ctx.issueToken({
|
||||
claims: {
|
||||
sub: userRef,
|
||||
ent: [userRef],
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { createAuthProviderIntegration } from '../createAuthProviderIntegration';
|
||||
import { AuthHandler, SignInResolver } from '../types';
|
||||
import { createGuestAuthProviderFactory } from '@backstage/plugin-auth-backend-module-guest-provider';
|
||||
|
||||
/**
|
||||
* Auth provider integration for Google auth
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const guest = createAuthProviderIntegration({
|
||||
create(options?: {
|
||||
/**
|
||||
* The profile transformation function used to verify and convert the auth response
|
||||
* into the profile that will be presented to the user.
|
||||
*/
|
||||
authHandler?: AuthHandler<{}>;
|
||||
|
||||
/**
|
||||
* Configure sign-in for this provider, without it the provider can not be used to sign users in.
|
||||
*/
|
||||
signIn?: {
|
||||
/**
|
||||
* Maps an auth result to a Backstage identity for the user.
|
||||
*/
|
||||
resolver: SignInResolver<{}>;
|
||||
};
|
||||
}) {
|
||||
return createGuestAuthProviderFactory({
|
||||
profileTransform: options?.authHandler,
|
||||
signInResolver: options?.signIn?.resolver,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -30,7 +30,6 @@ import { oidc } from './oidc';
|
||||
import { okta } from './okta';
|
||||
import { onelogin } from './onelogin';
|
||||
import { saml } from './saml';
|
||||
import { guest } from './guest';
|
||||
import { bitbucketServer } from './bitbucketServer';
|
||||
import { easyAuth } from './azure-easyauth';
|
||||
import { AuthProviderFactory } from '@backstage/plugin-auth-node';
|
||||
@@ -59,7 +58,6 @@ export const providers = Object.freeze({
|
||||
onelogin,
|
||||
saml,
|
||||
easyAuth,
|
||||
guest,
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -85,5 +83,4 @@ export const defaultAuthProviderFactories: {
|
||||
bitbucket: bitbucket.create(),
|
||||
bitbucketServer: bitbucketServer.create(),
|
||||
atlassian: atlassian.create(),
|
||||
guest: guest.create(),
|
||||
};
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# This file is generated by running "yarn install" inside your project.
|
||||
# Manual changes might be lost - proceed with caution!
|
||||
|
||||
__metadata:
|
||||
version: 6
|
||||
cacheKey: 8
|
||||
@@ -27411,6 +27414,7 @@ __metadata:
|
||||
"@backstage/plugin-app-backend": "workspace:^"
|
||||
"@backstage/plugin-auth-backend": "workspace:^"
|
||||
"@backstage/plugin-auth-backend-module-github-provider": "workspace:^"
|
||||
"@backstage/plugin-auth-backend-module-guest-provider": "workspace:^"
|
||||
"@backstage/plugin-auth-node": "workspace:^"
|
||||
"@backstage/plugin-azure-devops-backend": "workspace:^"
|
||||
"@backstage/plugin-badges-backend": "workspace:^"
|
||||
@@ -37347,7 +37351,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"passport-oauth2@npm:1.x.x, passport-oauth2@npm:^1.1.2, passport-oauth2@npm:^1.4.0, passport-oauth2@npm:^1.6.0, passport-oauth2@npm:^1.6.1":
|
||||
"passport-oauth2@npm:1.x.x, passport-oauth2@npm:^1.1.2, passport-oauth2@npm:^1.4.0, passport-oauth2@npm:^1.6.0, passport-oauth2@npm:^1.6.1, passport-oauth2@npm:^1.7.0":
|
||||
version: 1.8.0
|
||||
resolution: "passport-oauth2@npm:1.8.0"
|
||||
dependencies:
|
||||
@@ -37360,19 +37364,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"passport-oauth2@npm:1.x.x, passport-oauth2@npm:^1.1.2, passport-oauth2@npm:^1.4.0, passport-oauth2@npm:^1.6.0, passport-oauth2@npm:^1.6.1, passport-oauth2@npm:^1.7.0":
|
||||
version: 1.7.0
|
||||
resolution: "passport-oauth2@npm:1.7.0"
|
||||
dependencies:
|
||||
base64url: 3.x.x
|
||||
oauth: 0.10.x
|
||||
passport-strategy: 1.x.x
|
||||
uid2: 0.0.x
|
||||
utils-merge: 1.x.x
|
||||
checksum: a9a80b968343c9c1906f74ef613b346ec2d6a6acfe17af81e673fd774779b436729252485755c3ce182f2cdba2434d75067418952d722404d65b93c0360ca02b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"passport-oauth@npm:1.0.0, passport-oauth@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "passport-oauth@npm:1.0.0"
|
||||
|
||||
Reference in New Issue
Block a user