feat: Let InteractionCompleter return redirect URL

This commit is contained in:
Joachim Van Herwegen
2021-08-06 15:26:25 +02:00
parent 7b7040a196
commit 7b42c72142
7 changed files with 72 additions and 25 deletions

View File

@@ -15,6 +15,7 @@ import type { HttpResponse } from '../../../src/server/HttpResponse';
import type { TemplateHandler } from '../../../src/server/util/TemplateHandler';
import { BadRequestHttpError } from '../../../src/util/errors/BadRequestHttpError';
import { InternalServerError } from '../../../src/util/errors/InternalServerError';
import { SOLID_HTTP } from '../../../src/util/Vocabularies';
describe('An IdentityProviderHttpHandler', (): void => {
const baseUrl = 'http://test.com/';
@@ -64,7 +65,7 @@ describe('An IdentityProviderHttpHandler', (): void => {
templateHandler = { handleSafe: jest.fn() } as any;
interactionCompleter = { handleSafe: jest.fn() } as any;
interactionCompleter = { handleSafe: jest.fn().mockResolvedValue('http://test.com/idp/auth') } as any;
errorHandler = { handleSafe: jest.fn() } as any;
@@ -147,7 +148,7 @@ describe('An IdentityProviderHttpHandler', (): void => {
expect(responseWriter.handleSafe).toHaveBeenLastCalledWith({ response, result: { statusCode: 400 }});
});
it('calls the interactionCompleter for InteractionCompleteResults.', async(): Promise<void> => {
it('calls the interactionCompleter for InteractionCompleteResults and redirects.', async(): Promise<void> => {
request.url = '/idp/routeComplete';
request.method = 'POST';
const oidcInteraction = { session: { accountId: 'account' }} as any;
@@ -157,7 +158,13 @@ describe('An IdentityProviderHttpHandler', (): void => {
expect(routes.complete.handler.handleSafe).toHaveBeenCalledTimes(1);
expect(routes.complete.handler.handleSafe).toHaveBeenLastCalledWith({ operation, oidcInteraction });
expect(interactionCompleter.handleSafe).toHaveBeenCalledTimes(1);
expect(interactionCompleter.handleSafe).toHaveBeenLastCalledWith({ request, response, webId: 'webId' });
expect(interactionCompleter.handleSafe).toHaveBeenLastCalledWith({ request, webId: 'webId' });
const location = await interactionCompleter.handleSafe.mock.results[0].value;
expect(responseWriter.handleSafe).toHaveBeenCalledTimes(1);
const args = responseWriter.handleSafe.mock.calls[0][0];
expect(args.response).toBe(response);
expect(args.result.statusCode).toBe(302);
expect(args.result.metadata?.get(SOLID_HTTP.terms.location)?.value).toBe(location);
});
it('matches paths based on prompt for requests to the root IDP.', async(): Promise<void> => {

View File

@@ -1,22 +1,20 @@
import { ServerResponse } from 'http';
import type { Provider } from 'oidc-provider';
import type { ProviderFactory } from '../../../../../src/identity/configuration/ProviderFactory';
import { InteractionCompleter } from '../../../../../src/identity/interaction/util/InteractionCompleter';
import type { HttpRequest } from '../../../../../src/server/HttpRequest';
import type { HttpResponse } from '../../../../../src/server/HttpResponse';
// Use fixed dates
jest.useFakeTimers();
describe('An InteractionCompleter', (): void => {
const request: HttpRequest = {} as any;
const response: HttpResponse = {} as any;
const webId = 'http://alice.test.com/#me';
let provider: Provider;
let provider: jest.Mocked<Provider>;
let completer: InteractionCompleter;
beforeEach(async(): Promise<void> => {
provider = {
interactionFinished: jest.fn(),
interactionResult: jest.fn(),
} as any;
const factory: ProviderFactory = {
@@ -27,10 +25,10 @@ describe('An InteractionCompleter', (): void => {
});
it('sends the correct data to the provider.', async(): Promise<void> => {
await expect(completer.handle({ request, response, webId, shouldRemember: true }))
await expect(completer.handle({ request, webId, shouldRemember: true }))
.resolves.toBeUndefined();
expect(provider.interactionFinished).toHaveBeenCalledTimes(1);
expect(provider.interactionFinished).toHaveBeenLastCalledWith(request, response, {
expect(provider.interactionResult).toHaveBeenCalledTimes(1);
expect(provider.interactionResult).toHaveBeenLastCalledWith(request, expect.any(ServerResponse), {
login: {
account: webId,
remember: true,
@@ -43,10 +41,10 @@ describe('An InteractionCompleter', (): void => {
});
it('rejects offline access if shouldRemember is false.', async(): Promise<void> => {
await expect(completer.handle({ request, response, webId, shouldRemember: false }))
await expect(completer.handle({ request, webId, shouldRemember: false }))
.resolves.toBeUndefined();
expect(provider.interactionFinished).toHaveBeenCalledTimes(1);
expect(provider.interactionFinished).toHaveBeenLastCalledWith(request, response, {
expect(provider.interactionResult).toHaveBeenCalledTimes(1);
expect(provider.interactionResult).toHaveBeenLastCalledWith(request, expect.any(ServerResponse), {
login: {
account: webId,
remember: false,

View File

@@ -0,0 +1,18 @@
import { RedirectResponseDescription } from '../../../../../src/ldp/http/response/RedirectResponseDescription';
import { SOLID_HTTP } from '../../../../../src/util/Vocabularies';
describe('A RedirectResponseDescription', (): void => {
const location = 'http://test.com/foo';
it('has status code 302 and a location.', async(): Promise<void> => {
const description = new RedirectResponseDescription(location);
expect(description.metadata?.get(SOLID_HTTP.terms.location)?.value).toBe(location);
expect(description.statusCode).toBe(302);
});
it('has status code 301 if the change is permanent.', async(): Promise<void> => {
const description = new RedirectResponseDescription(location, true);
expect(description.metadata?.get(SOLID_HTTP.terms.location)?.value).toBe(location);
expect(description.statusCode).toBe(301);
});
});