test: JwksHandler test

This commit is contained in:
Wouter Termont 2024-03-12 09:21:17 +01:00
parent e7f1d28c11
commit d50f2d7e94
No known key found for this signature in database
2 changed files with 72 additions and 2 deletions

View File

@ -1,8 +1,12 @@
import { REQUEST_METHOD } from '@solid/access-token-verifier/dist/constant/REQUEST_METHOD';
import { HttpHandler, type HttpHandlerInput } from '../HttpHandler';
import type { JwkGenerator } from '../../identity/configuration/JwkGenerator';
import { MethodNotAllowedHttpError } from '../../util/errors/MethodNotAllowedHttpError';
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError';
const allowedMethods = new Set<string | undefined>([ 'GET', 'HEAD' ]);
const methodsNotAllowed: string[] = [ ...REQUEST_METHOD ].filter((method): boolean => !allowedMethods.has(method));
export class JwksHandler extends HttpHandler {
public constructor(
private readonly path: string,
@ -14,9 +18,9 @@ export class JwksHandler extends HttpHandler {
public async canHandle({ request }: HttpHandlerInput): Promise<void> {
const { method, url } = request;
if (![ 'GET', 'HEAD' ].includes(method ?? '')) {
if (!allowedMethods.has(method)) {
throw new MethodNotAllowedHttpError(
method ? [ method ] : undefined,
methodsNotAllowed,
`Only GET or HEAD requests can target the storage description.`,
);
}

View File

@ -0,0 +1,66 @@
import { createRequest, createResponse, type MockResponse } from 'node-mocks-http';
import { REQUEST_METHOD } from '@solid/access-token-verifier/dist/constant/REQUEST_METHOD';
import type { Response } from 'express';
import type { HttpResponse } from '../../../../src/server/HttpResponse';
import { JwksHandler } from '../../../../src/server/middleware/JwksHandler';
import { guardStream } from '../../../../src/util/GuardedStream';
import type { AlgJwk, JwkGenerator } from '../../../../src/identity/configuration/JwkGenerator';
import { MethodNotAllowedHttpError } from '../../../../src/util/errors/MethodNotAllowedHttpError';
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
describe('a JwksHandler', (): void => {
const key: AlgJwk = { alg: 'ES256' };
const path = 'http://example.org/.well-known/jwks.json';
const generator: JwkGenerator = jest.mocked<JwkGenerator>({
alg: key.alg,
getPrivateKey: jest.fn(),
getPublicKey: jest.fn<ReturnType<JwkGenerator['getPublicKey']>, any[]>().mockResolvedValue(key),
});
let handler: JwksHandler;
let response: MockResponse<Response & HttpResponse>;
beforeEach((): void => {
handler = new JwksHandler(path, generator);
response = createResponse<Response & HttpResponse>();
jest.clearAllMocks();
});
it('does not handle requests with methods other than GET or HEAD.', async(): Promise<void> => {
for (const method of REQUEST_METHOD) {
if (method === 'GET' || method === 'HEAD') {
continue;
}
const request = guardStream(createRequest({ method, url: path }));
await expect(handler.canHandle({ request, response })).rejects.toThrow(MethodNotAllowedHttpError);
}
});
it('does not handle requests with other paths than the configured on.', async(): Promise<void> => {
const request = guardStream(createRequest({ url: 'https://example.org/other/path' }));
await expect(handler.canHandle({ request, response })).rejects.toThrow(NotImplementedHttpError);
});
it('handles a HEAD request to the configured path.', async(): Promise<void> => {
const request = guardStream(createRequest({ method: 'HEAD', url: path }));
await handler.handleSafe({ request, response });
expect(response.statusCode).toBe(200);
expect(response.getHeaders()).toEqual(expect.objectContaining({ 'content-type': 'application/json' }));
});
it('handles a GET request to the configured path.', async(): Promise<void> => {
const request = guardStream(createRequest({ method: 'GET', url: path }));
await handler.handleSafe({ request, response });
expect(generator.getPublicKey).toHaveBeenCalledTimes(1);
expect(response.statusCode).toBe(200);
expect(response.getHeaders()).toEqual(expect.objectContaining({ 'content-type': 'application/json' }));
expect(JSON.parse(response._getData())).toEqual(expect.objectContaining({ keys: expect.arrayContaining([ key ]) }));
});
});