Working oidc authenticator with passing unit and module tests

Signed-off-by: Ruben Vallejo <rvallejo@vmware.com>
This commit is contained in:
Ruben Vallejo
2023-09-28 10:59:18 -04:00
committed by Jamie Klassen
parent a3c911e636
commit 1964cb7d88
8 changed files with 84 additions and 261 deletions
@@ -15,4 +15,3 @@
*/
export { oidc } from './provider';
export type { OidcAuthResult } from './provider';
@@ -22,255 +22,13 @@ import {
adaptLegacyOAuthHandler,
adaptLegacyOAuthSignInResolver,
} from '../../lib/legacy';
import { oidcAuthenticator } from '@backstage/plugin-auth-backend-module-oidc-provider';
// type PrivateInfo = {
// refreshToken?: string;
// };
// type OidcImpl = {
// strategy: OidcStrategy<UserinfoResponse, Client>;
// client: Client;
// };
// /**
// * authentication result for the OIDC which includes the token set and user information (a profile response sent by OIDC server)
// * @public
// */
// export type OidcAuthResult = {
// tokenset: TokenSet;
// userinfo: UserinfoResponse;
// };
// export type Options = OAuthProviderOptions & {
// metadataUrl: string;
// scope?: string;
// prompt?: string;
// tokenEndpointAuthMethod?: ClientAuthMethod;
// tokenSignedResponseAlg?: string;
// signInResolver?: SignInResolver<OidcAuthResult>;
// authHandler: AuthHandler<OidcAuthResult>;
// resolverContext: AuthResolverContext;
// };
// export class OidcAuthProvider implements OAuthHandlers {
// private readonly implementation: Promise<OidcImpl>;
// private readonly scope?: string;
// private readonly prompt?: string;
// private readonly signInResolver?: SignInResolver<OidcAuthResult>;
// private readonly authHandler: AuthHandler<OidcAuthResult>;
// private readonly resolverContext: AuthResolverContext;
// constructor(options: Options) {
// this.implementation = this.setupStrategy(options);
// this.scope = options.scope;
// this.prompt = options.prompt;
// this.signInResolver = options.signInResolver;
// this.authHandler = options.authHandler;
// this.resolverContext = options.resolverContext;
// }
// async start(req: OAuthStartRequest): Promise<OAuthStartResponse> {
// const { strategy } = await this.implementation;
// const options: Record<string, string> = {
// scope: req.scope || this.scope || 'openid profile email',
// state: encodeState(req.state),
// };
// const prompt = this.prompt || 'none';
// if (prompt !== 'auto') {
// options.prompt = prompt;
// }
// return await executeRedirectStrategy(req, strategy, options);
// }
// async handler(req: express.Request) {
// const { strategy } = await this.implementation;
// const { result, privateInfo } = await executeFrameHandlerStrategy<
// OidcAuthResult,
// PrivateInfo
// >(req, strategy);
// async refresh(req: OAuthRefreshRequest) {
// const { client } = await this.implementation;
// const tokenset = await client.refresh(req.refreshToken);
// if (!tokenset.access_token) {
// throw new Error('Refresh failed');
// }
// if (!tokenset.scope) {
// tokenset.scope = req.scope;
// }
// const userinfo = await client.userinfo(tokenset.access_token);
// return {
// response: await this.handleResult(result),
// refreshToken: privateInfo.refreshToken,
// };
// }
// async refresh(req: OAuthRefreshRequest) {
// const { client } = await this.implementation;
// const tokenset = await client.refresh(req.refreshToken);
// if (!tokenset.access_token) {
// throw new Error('Refresh failed');
// }
// const userinfo = await client.userinfo(tokenset.access_token);
// return {
// response: await this.handleResult({ tokenset, userinfo }),
// refreshToken: tokenset.refresh_token,
// };
// }
// private async setupStrategy(options: Options): Promise<OidcImpl> {
// const issuer = await Issuer.discover(options.metadataUrl);
// const client = new issuer.Client({
// access_type: 'offline', // this option must be passed to provider to receive a refresh token
// client_id: options.clientId,
// client_secret: options.clientSecret,
// redirect_uris: [options.callbackUrl],
// response_types: ['code'],
// token_endpoint_auth_method:
// options.tokenEndpointAuthMethod || 'client_secret_basic',
// id_token_signed_response_alg: options.tokenSignedResponseAlg || 'RS256',
// scope: options.scope || '',
// });
// const strategy = new OidcStrategy(
// {
// client,
// passReqToCallback: false,
// },
// (
// tokenset: TokenSet,
// userinfo: UserinfoResponse,
// done: PassportDoneCallback<OidcAuthResult, PrivateInfo>,
// ) => {
// if (typeof done !== 'function') {
// throw new Error(
// 'OIDC IdP must provide a userinfo_endpoint in the metadata response',
// );
// }
// done(
// undefined,
// { tokenset, userinfo },
// {
// refreshToken: tokenset.refresh_token,
// },
// );
// },
// );
// strategy.error = console.error;
// return { strategy, client };
// }
// Use this function to grab the user profile info from the token
// Then populate the profile with it
// private async handleResult(result: OidcAuthResult): Promise<OAuthResponse> {
// const { profile } = await this.authHandler(result, this.resolverContext);
// const expiresInSeconds =
// result.tokenset.expires_in === undefined
// ? BACKSTAGE_SESSION_EXPIRATION
// : Math.min(result.tokenset.expires_in, BACKSTAGE_SESSION_EXPIRATION);
// let backstageIdentity = undefined;
// if (this.signInResolver) {
// backstageIdentity = await this.signInResolver(
// {
// result,
// profile,
// },
// this.resolverContext,
// );
// }
// return {
// backstageIdentity,
// providerInfo: {
// idToken: result.tokenset.id_token,
// accessToken: result.tokenset.access_token!,
// scope: result.tokenset.scope!,
// expiresInSeconds,
// },
// profile,
// };
// }
// }
/**
* Auth provider integration for generic OpenID Connect auth
*
* @public
*/
// export const oidc = createAuthProviderIntegration({
// create(options?: {
// authHandler?: AuthHandler<OidcAuthResult>;
// signIn?: {
// resolver: SignInResolver<OidcAuthResult>;
// };
// }) {
// return ({ providerId, globalConfig, config, resolverContext }) =>
// OAuthEnvironmentHandler.mapConfig(config, envConfig => {
// const clientId = envConfig.getString('clientId');
// const clientSecret = envConfig.getString('clientSecret');
// const customCallbackUrl = envConfig.getOptionalString('callbackUrl');
// const callbackUrl =
// customCallbackUrl ||
// `${globalConfig.baseUrl}/${providerId}/handler/frame`;
// const metadataUrl = envConfig.getString('metadataUrl');
// const tokenEndpointAuthMethod = envConfig.getOptionalString(
// 'tokenEndpointAuthMethod',
// ) as ClientAuthMethod;
// const tokenSignedResponseAlg = envConfig.getOptionalString(
// 'tokenSignedResponseAlg',
// );
// const scope = envConfig.getOptionalString('scope');
// const prompt = envConfig.getOptionalString('prompt');
// const authHandler: AuthHandler<OidcAuthResult> = options?.authHandler
// ? options.authHandler
// : async ({ userinfo }) => ({
// profile: {
// displayName: userinfo.name,
// email: userinfo.email,
// picture: userinfo.picture,
// },
// });
// const provider = new OidcAuthProvider({
// clientId,
// clientSecret,
// callbackUrl,
// tokenEndpointAuthMethod,
// tokenSignedResponseAlg,
// metadataUrl,
// scope,
// prompt,
// signInResolver: options?.signIn?.resolver,
// authHandler,
// resolverContext,
// });
// return OAuthAdapter.fromConfig(globalConfig, provider, {
// providerId,
// callbackUrl,
// });
// });
// },
// resolvers: {
// /**
// * 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.
// */
// emailMatchingUserEntityProfileEmail: () => commonByEmailResolver,
// },
// });
export const oidc = createAuthProviderIntegration({
create(options?: {
/**