diff --git a/packages/auth/src/app.ts b/packages/auth/src/app.ts index b40665dd82..cb3eda6925 100644 --- a/packages/auth/src/app.ts +++ b/packages/auth/src/app.ts @@ -19,7 +19,8 @@ import { createValidatorMiddleware, HttpMethod } from 'openapi' import { grantInitiationHttpsigMiddleware, grantContinueHttpsigMiddleware, - tokenHttpsigMiddleware + tokenHttpsigMiddleware, + bypassOrCallHttpsigMiddleware } from './signature/middleware' export interface AppContextData extends DefaultContext { @@ -199,9 +200,11 @@ export class App { path: '/', method: HttpMethod.POST }), - this.config.bypassSignatureValidation - ? (ctx, next) => next() - : grantInitiationHttpsigMiddleware, + bypassOrCallHttpsigMiddleware( + this.config.bypassSignatureValidation, + grantInitiationHttpsigMiddleware, + { injectClientKeyId: true } + ), grantRoutes.create ) @@ -212,9 +215,10 @@ export class App { path: '/continue/{id}', method: HttpMethod.POST }), - this.config.bypassSignatureValidation - ? (ctx, next) => next() - : grantContinueHttpsigMiddleware, + bypassOrCallHttpsigMiddleware( + this.config.bypassSignatureValidation, + grantContinueHttpsigMiddleware + ), grantRoutes.continue ) @@ -225,9 +229,10 @@ export class App { path: '/token/{id}', method: HttpMethod.POST }), - this.config.bypassSignatureValidation - ? (ctx, next) => next() - : tokenHttpsigMiddleware, + bypassOrCallHttpsigMiddleware( + this.config.bypassSignatureValidation, + tokenHttpsigMiddleware + ), accessTokenRoutes.rotate ) @@ -238,9 +243,10 @@ export class App { path: '/token/{id}', method: HttpMethod.DELETE }), - this.config.bypassSignatureValidation - ? (ctx, next) => next() - : tokenHttpsigMiddleware, + bypassOrCallHttpsigMiddleware( + this.config.bypassSignatureValidation, + tokenHttpsigMiddleware + ), accessTokenRoutes.revoke ) diff --git a/packages/auth/src/signature/middleware.ts b/packages/auth/src/signature/middleware.ts index 492a650588..3eb9458a9c 100644 --- a/packages/auth/src/signature/middleware.ts +++ b/packages/auth/src/signature/middleware.ts @@ -46,16 +46,11 @@ async function verifySigFromClient( client: string, ctx: HttpSigContext ): Promise { - const clientService = await ctx.container.use('clientService') - const clientKey = await clientService.getKey({ + const clientKey = await getClientKeyOrThrow(ctx, { client, - keyId: ctx.clientKeyId + clientKeyId: ctx.clientKeyId }) - if (!clientKey) { - ctx.throw(400, 'invalid client', { error: 'invalid_client' }) - } - return verifySigAndChallenge(clientKey, ctx) } @@ -277,3 +272,57 @@ export async function tokenHttpsigMiddleware( await verifySigFromBoundKey(grant, ctx) await next() } + +type Middleware = (ctx: AppContext, next: () => Promise) => Promise + +export async function getClientKeyOrThrow( + ctx: AppContext | HttpSigContext, + { client, clientKeyId }: { client: string; clientKeyId: string } +): Promise { + const clientService = await ctx.container.use('clientService') + const clientKey = await clientService.getKey({ + client, + keyId: clientKeyId + }) + + if (!clientKey) { + ctx.throw(400, 'invalid client', { error: 'invalid_client' }) + } + + return clientKey +} + +export function bypassOrCallHttpsigMiddleware( + bypassSignatureValidation: boolean, + middleware: Middleware, + args?: { injectClientKeyId: boolean } +): Middleware { + if (!bypassSignatureValidation) { + return middleware + } + + return async (ctx: AppContext, next) => { + ctx.logger.info('Skipping httpsig validation') + + if (args?.injectClientKeyId) { + const clientKeyId = getSigInputKeyId( + ctx.headers['signature-input'] as string + ) + + if (!clientKeyId) { + ctx.throw(400, 'invalid client', { error: 'invalid_client' }) + } + + const clientPaymentPointer = ctx.request.body?.client as string + + await getClientKeyOrThrow(ctx, { + client: clientPaymentPointer, + clientKeyId + }) + + ctx.clientKeyId = clientKeyId + } + + await next() + } +}