auth-backend: migrate oauth2-proxy provider to use resolver context
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -21,18 +21,14 @@ jest.mock('jose', () => ({
|
||||
}));
|
||||
jest.mock('@backstage/catalog-client');
|
||||
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
import express from 'express';
|
||||
import { JWT } from 'jose';
|
||||
import { Logger } from 'winston';
|
||||
import { AuthHandler, SignInResolver } from '../types';
|
||||
|
||||
import { CatalogIdentityClient } from '../../lib/catalog';
|
||||
import { TokenIssuer } from '../../identity/types';
|
||||
|
||||
import { AuthHandler, AuthResolverContext, SignInResolver } from '../types';
|
||||
import {
|
||||
createOauth2ProxyProvider,
|
||||
Oauth2ProxyAuthProvider,
|
||||
Oauth2ProxyProviderOptions,
|
||||
OAuth2ProxyResult,
|
||||
OAUTH2_PROXY_JWT_HEADER,
|
||||
} from './provider';
|
||||
@@ -72,10 +68,10 @@ describe('Oauth2ProxyAuthProvider', () => {
|
||||
|
||||
provider = new Oauth2ProxyAuthProvider<any>({
|
||||
authHandler,
|
||||
logger,
|
||||
signInResolver,
|
||||
catalogIdentityClient: {} as CatalogIdentityClient,
|
||||
tokenIssuer: {} as TokenIssuer,
|
||||
resolverContext: {
|
||||
_: 'resolver-context',
|
||||
} as unknown as AuthResolverContext,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -99,17 +95,17 @@ describe('Oauth2ProxyAuthProvider', () => {
|
||||
it('should throw an error when auth header is missing', async () => {
|
||||
mockRequest.header.mockReturnValue(undefined);
|
||||
|
||||
await provider.refresh(mockRequest, mockResponse);
|
||||
|
||||
expect(mockResponse.status).toHaveBeenCalledWith(401);
|
||||
await expect(provider.refresh(mockRequest, mockResponse)).rejects.toThrow(
|
||||
AuthenticationError,
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw an error if the bearer token is invalid', async () => {
|
||||
mockRequest.header.mockReturnValue('Basic asdf=');
|
||||
|
||||
await provider.refresh(mockRequest, mockResponse);
|
||||
|
||||
expect(mockResponse.status).toHaveBeenCalledWith(401);
|
||||
await expect(provider.refresh(mockRequest, mockResponse)).rejects.toThrow(
|
||||
AuthenticationError,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return if auth header is set and valid', async () => {
|
||||
@@ -152,7 +148,7 @@ describe('Oauth2ProxyAuthProvider', () => {
|
||||
fullProfile: decodedToken,
|
||||
},
|
||||
},
|
||||
{ catalogIdentityClient: {}, logger, tokenIssuer: {} },
|
||||
{ _: 'resolver-context' },
|
||||
);
|
||||
expect(mockResponse.json).toHaveBeenCalledWith({
|
||||
backstageIdentity: {
|
||||
@@ -183,12 +179,10 @@ describe('Oauth2ProxyAuthProvider', () => {
|
||||
});
|
||||
|
||||
it('should create a valid provider', async () => {
|
||||
const providerOptions = {
|
||||
const factory = createOauth2ProxyProvider({
|
||||
authHandler,
|
||||
signIn: { resolver: signInResolver },
|
||||
} as Oauth2ProxyProviderOptions<any>;
|
||||
|
||||
const factory = createOauth2ProxyProvider(providerOptions);
|
||||
});
|
||||
const handler = factory({
|
||||
logger,
|
||||
catalogApi: {},
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
|
||||
import express from 'express';
|
||||
import { Logger } from 'winston';
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node';
|
||||
import {
|
||||
@@ -24,10 +23,9 @@ import {
|
||||
AuthProviderFactory,
|
||||
AuthProviderRouteHandlers,
|
||||
AuthResponse,
|
||||
AuthResolverContext,
|
||||
} from '../types';
|
||||
import { CatalogIdentityClient } from '../../lib/catalog';
|
||||
import { JWT } from 'jose';
|
||||
import { TokenIssuer } from '../../identity/types';
|
||||
import { prepareBackstageIdentityResponse } from '../prepareBackstageIdentityResponse';
|
||||
|
||||
export const OAUTH2_PROXY_JWT_HEADER = 'X-OAUTH2-PROXY-ID-TOKEN';
|
||||
@@ -71,28 +69,22 @@ export type Oauth2ProxyProviderOptions<JWTPayload> = {
|
||||
};
|
||||
|
||||
interface Options<JWTPayload> {
|
||||
logger: Logger;
|
||||
resolverContext: AuthResolverContext;
|
||||
signInResolver: SignInResolver<OAuth2ProxyResult<JWTPayload>>;
|
||||
authHandler: AuthHandler<OAuth2ProxyResult<JWTPayload>>;
|
||||
tokenIssuer: TokenIssuer;
|
||||
catalogIdentityClient: CatalogIdentityClient;
|
||||
}
|
||||
|
||||
export class Oauth2ProxyAuthProvider<JWTPayload>
|
||||
implements AuthProviderRouteHandlers
|
||||
{
|
||||
private readonly logger: Logger;
|
||||
private readonly catalogIdentityClient: CatalogIdentityClient;
|
||||
private readonly resolverContext: AuthResolverContext;
|
||||
private readonly signInResolver: SignInResolver<
|
||||
OAuth2ProxyResult<JWTPayload>
|
||||
>;
|
||||
private readonly authHandler: AuthHandler<OAuth2ProxyResult<JWTPayload>>;
|
||||
private readonly tokenIssuer: TokenIssuer;
|
||||
|
||||
constructor(options: Options<JWTPayload>) {
|
||||
this.catalogIdentityClient = options.catalogIdentityClient;
|
||||
this.logger = options.logger;
|
||||
this.tokenIssuer = options.tokenIssuer;
|
||||
this.resolverContext = options.resolverContext;
|
||||
this.signInResolver = options.signInResolver;
|
||||
this.authHandler = options.authHandler;
|
||||
}
|
||||
@@ -104,17 +96,10 @@ export class Oauth2ProxyAuthProvider<JWTPayload>
|
||||
async refresh(req: express.Request, res: express.Response): Promise<void> {
|
||||
try {
|
||||
const result = this.getResult(req);
|
||||
|
||||
const response = await this.handleResult(result);
|
||||
|
||||
res.json(response);
|
||||
} catch (e) {
|
||||
this.logger.error(
|
||||
`Exception occurred during ${OAUTH2_PROXY_JWT_HEADER} refresh`,
|
||||
e,
|
||||
);
|
||||
res.status(401);
|
||||
res.end();
|
||||
throw new AuthenticationError('Refresh failed', e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,20 +110,14 @@ export class Oauth2ProxyAuthProvider<JWTPayload>
|
||||
private async handleResult(
|
||||
result: OAuth2ProxyResult<JWTPayload>,
|
||||
): Promise<AuthResponse<{ accessToken: string }>> {
|
||||
const ctx = {
|
||||
logger: this.logger,
|
||||
tokenIssuer: this.tokenIssuer,
|
||||
catalogIdentityClient: this.catalogIdentityClient,
|
||||
};
|
||||
|
||||
const { profile } = await this.authHandler(result, ctx);
|
||||
const { profile } = await this.authHandler(result, this.resolverContext);
|
||||
|
||||
const backstageSignInResult = await this.signInResolver(
|
||||
{
|
||||
result,
|
||||
profile,
|
||||
},
|
||||
ctx,
|
||||
this.resolverContext,
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -193,18 +172,12 @@ export const createOauth2ProxyProvider =
|
||||
resolver: SignInResolver<OAuth2ProxyResult<JWTPayload>>;
|
||||
};
|
||||
}): AuthProviderFactory =>
|
||||
({ catalogApi, logger, tokenIssuer, tokenManager }) => {
|
||||
({ resolverContext }) => {
|
||||
const signInResolver = options.signIn.resolver;
|
||||
const authHandler = options.authHandler;
|
||||
const catalogIdentityClient = new CatalogIdentityClient({
|
||||
catalogApi,
|
||||
tokenManager,
|
||||
});
|
||||
return new Oauth2ProxyAuthProvider<JWTPayload>({
|
||||
logger,
|
||||
resolverContext,
|
||||
signInResolver,
|
||||
authHandler,
|
||||
tokenIssuer,
|
||||
catalogIdentityClient,
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user