feat: Indicate to templates if this is part of an auth request

This commit is contained in:
Joachim Van Herwegen 2021-08-13 12:05:22 +02:00
parent cb227d6431
commit f71f8683fc
3 changed files with 29 additions and 17 deletions

View File

@ -167,8 +167,9 @@ export class IdentityProviderHttpHandler extends HttpHandler {
private async resolveRoute(request: HttpRequest, response: HttpResponse, route: InteractionRoute, private async resolveRoute(request: HttpRequest, response: HttpResponse, route: InteractionRoute,
oidcInteraction?: Interaction): Promise<void> { oidcInteraction?: Interaction): Promise<void> {
if (request.method === 'GET') { if (request.method === 'GET') {
// .ejs templates errors on undefined variables return await this.handleTemplateResponse(
return await this.handleTemplateResponse(response, route.viewTemplate, { errorMessage: '', prefilled: {}}); response, route.viewTemplate, { errorMessage: '', prefilled: {}}, oidcInteraction,
);
} }
if (request.method === 'POST') { if (request.method === 'POST') {
@ -179,7 +180,9 @@ export class IdentityProviderHttpHandler extends HttpHandler {
// Render error in the view // Render error in the view
const prefilled = IdpInteractionError.isInstance(error) ? error.prefilled : {}; const prefilled = IdpInteractionError.isInstance(error) ? error.prefilled : {};
const errorMessage = createErrorMessage(error); const errorMessage = createErrorMessage(error);
return await this.handleTemplateResponse(response, route.viewTemplate, { errorMessage, prefilled }); return await this.handleTemplateResponse(
response, route.viewTemplate, { errorMessage, prefilled }, oidcInteraction,
);
} }
if (result.type === 'complete') { if (result.type === 'complete') {
@ -193,15 +196,17 @@ export class IdentityProviderHttpHandler extends HttpHandler {
return await this.interactionCompleter.handleSafe({ ...result.details, request, response }); return await this.interactionCompleter.handleSafe({ ...result.details, request, response });
} }
if (result.type === 'response' && route.responseTemplate) { if (result.type === 'response' && route.responseTemplate) {
return await this.handleTemplateResponse(response, route.responseTemplate, result.details); return await this.handleTemplateResponse(response, route.responseTemplate, result.details, oidcInteraction);
} }
} }
throw new BadRequestHttpError(`Unsupported request: ${request.method} ${request.url}`); throw new BadRequestHttpError(`Unsupported request: ${request.method} ${request.url}`);
} }
private async handleTemplateResponse(response: HttpResponse, templateFile: string, contents?: NodeJS.Dict<any>): private async handleTemplateResponse(response: HttpResponse, templateFile: string, data?: NodeJS.Dict<any>,
Promise<void> { oidcInteraction?: Interaction): Promise<void> {
await this.templateHandler.handleSafe({ response, templateFile, contents: contents ?? {}}); const contents = data ?? {};
contents.authenticating = Boolean(oidcInteraction);
await this.templateHandler.handleSafe({ response, templateFile, contents });
} }
/** /**

View File

@ -26,7 +26,11 @@
<h2>Your new account</h2> <h2>Your new account</h2>
<p> <p>
Via your email address <em><%= email %></em>, Via your email address <em><%= email %></em>,
this server lets you <a href="./login">log in</a> to Solid apps <% if (authenticating) { %>
you can now <a href="./login">log in</a>
<% } else { %>
this server lets you log in to Solid apps
<% } %>
with your WebID <a href="<%= webId %>" class="link"><%= webId %></a> with your WebID <a href="<%= webId %>" class="link"><%= webId %></a>
</p> </p>
<% if (!createWebId) { %> <% if (!createWebId) { %>

View File

@ -83,9 +83,9 @@ describe('An IdentityProviderHttpHandler', (): void => {
request.url = '/idp/routeResponse'; request.url = '/idp/routeResponse';
await expect(handler.handle({ request, response })).resolves.toBeUndefined(); await expect(handler.handle({ request, response })).resolves.toBeUndefined();
expect(templateHandler.handleSafe).toHaveBeenCalledTimes(1); expect(templateHandler.handleSafe).toHaveBeenCalledTimes(1);
expect(templateHandler.handleSafe).toHaveBeenLastCalledWith( expect(templateHandler.handleSafe).toHaveBeenLastCalledWith({ response,
{ response, templateFile: routes.response.viewTemplate, contents: { errorMessage: '', prefilled: {}}}, templateFile: routes.response.viewTemplate,
); contents: { errorMessage: '', prefilled: {}, authenticating: false }});
}); });
it('calls the templateHandler for InteractionResponseResults.', async(): Promise<void> => { it('calls the templateHandler for InteractionResponseResults.', async(): Promise<void> => {
@ -96,20 +96,22 @@ describe('An IdentityProviderHttpHandler', (): void => {
expect(routes.response.handler.handleSafe).toHaveBeenLastCalledWith({ request }); expect(routes.response.handler.handleSafe).toHaveBeenLastCalledWith({ request });
expect(templateHandler.handleSafe).toHaveBeenCalledTimes(1); expect(templateHandler.handleSafe).toHaveBeenCalledTimes(1);
expect(templateHandler.handleSafe).toHaveBeenLastCalledWith( expect(templateHandler.handleSafe).toHaveBeenLastCalledWith(
{ response, templateFile: routes.response.responseTemplate, contents: { key: 'val' }}, { response, templateFile: routes.response.responseTemplate, contents: { key: 'val', authenticating: false }},
); );
}); });
it('supports InteractionResponseResults without details.', async(): Promise<void> => { it('indicates to the templates if the request is part of an auth flow.', async(): Promise<void> => {
request.url = '/idp/routeResponse'; request.url = '/idp/routeResponse';
request.method = 'POST'; request.method = 'POST';
const oidcInteraction = { session: { accountId: 'account' }} as any;
provider.interactionDetails.mockResolvedValueOnce(oidcInteraction);
(routes.response.handler as jest.Mocked<InteractionHandler>).handleSafe.mockResolvedValueOnce({ type: 'response' }); (routes.response.handler as jest.Mocked<InteractionHandler>).handleSafe.mockResolvedValueOnce({ type: 'response' });
await expect(handler.handle({ request, response })).resolves.toBeUndefined(); await expect(handler.handle({ request, response })).resolves.toBeUndefined();
expect(routes.response.handler.handleSafe).toHaveBeenCalledTimes(1); expect(routes.response.handler.handleSafe).toHaveBeenCalledTimes(1);
expect(routes.response.handler.handleSafe).toHaveBeenLastCalledWith({ request }); expect(routes.response.handler.handleSafe).toHaveBeenLastCalledWith({ request, oidcInteraction });
expect(templateHandler.handleSafe).toHaveBeenCalledTimes(1); expect(templateHandler.handleSafe).toHaveBeenCalledTimes(1);
expect(templateHandler.handleSafe).toHaveBeenLastCalledWith( expect(templateHandler.handleSafe).toHaveBeenLastCalledWith(
{ response, templateFile: routes.response.responseTemplate, contents: {}}, { response, templateFile: routes.response.responseTemplate, contents: { authenticating: true }},
); );
}); });
@ -175,7 +177,8 @@ describe('An IdentityProviderHttpHandler', (): void => {
expect(templateHandler.handleSafe).toHaveBeenLastCalledWith({ expect(templateHandler.handleSafe).toHaveBeenLastCalledWith({
response, response,
templateFile: routes.response.viewTemplate, templateFile: routes.response.viewTemplate,
contents: { errorMessage: 'handle error', prefilled: { name: 'name' }}, contents: { errorMessage: 'handle error', prefilled: { name: 'name' }, authenticating: false },
}); });
}); });
@ -188,7 +191,7 @@ describe('An IdentityProviderHttpHandler', (): void => {
expect(templateHandler.handleSafe).toHaveBeenLastCalledWith({ expect(templateHandler.handleSafe).toHaveBeenLastCalledWith({
response, response,
templateFile: routes.response.viewTemplate, templateFile: routes.response.viewTemplate,
contents: { errorMessage: 'handle error', prefilled: { }}, contents: { errorMessage: 'handle error', prefilled: {}, authenticating: false },
}); });
}); });