Skip to content

Commit

Permalink
feat: redirect to e403 page when webhook rejects the request
Browse files Browse the repository at this point in the history
re #4
  • Loading branch information
vlad-tkachenko committed Sep 22, 2023
1 parent f59a5d3 commit b9b4b0c
Show file tree
Hide file tree
Showing 8 changed files with 796 additions and 15 deletions.
3 changes: 3 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ OPENID_CLIENT_SECRET='1f88bd14-7e7f-45e7-be27-d680da6e48d8'
MAPPINGS_PUBLIC='[
{
"pattern": "/public/.*"
},
{
"pattern": "/favicon.ico"
}
]'
MAPPINGS_API='[
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"mocha": "^10.2.0",
"mochawesome": "^7.1.3",
"nyc": "^15.1.0",
"open-api-mocker": "^2.0.0",
"pino-pretty": "^10.0.0",
"puppeteer": "^21.0.3",
"rimraf": "^5.0.1",
Expand Down
9 changes: 8 additions & 1 deletion src/handlers/CallbackHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const CallbackHandler: RequestHandlerConfig = {
});

if (!resp.ok) {
logger.child({status: resp.status}).error('Login webhook request failed');
throw new Error('Unable to make a login webhook request');
}

Expand All @@ -47,7 +48,13 @@ export const CallbackHandler: RequestHandlerConfig = {

// check if user access should be rejected (can be useful if webhook endpoint blocked user)
if (result.reject) {
sendErrorResponse(req, 403, result.reason || 'Access denied', res);
logger.child({originalPath}).info('Webhook rejected the request');
if (getConfig().redirect.pageRequest.e403) {
sendRedirect(res, getConfig().redirect.pageRequest.e403);
} else {
sendErrorResponse(req, 403, result.reason || 'Forbidden', res);
}

return;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/ProxyHandler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IncomingMessage, ServerResponse } from "http";
import { HttpMethod, ProxyRequest, RequestHandlerConfig } from "prxi";
import { invalidateAuthCookies, sendErrorResponse, sendJsonResponse, sendRedirect, setAuthCookies, setCookies } from "../utils/ResponseUtils";
import { invalidateAuthCookies, sendErrorResponse, sendRedirect, setAuthCookies, setCookies } from "../utils/ResponseUtils";
import { parse } from 'cookie';
import { getConfig } from "../config/getConfig";
import { Mapping } from "../config/Mapping";
Expand Down
9 changes: 9 additions & 0 deletions test/Base.suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ export class BaseSuite {
await this.prxi?.stop();
}

protected async reloadPrxiWith(config: Partial<Config>): Promise<void> {
await this.prxi.stop();
updateConfig({
...this.originalConfig,
...config,
});
this.prxi = await start();
}

/**
* Fetch
* @param url
Expand Down
59 changes: 59 additions & 0 deletions test/WebhookHandler.suite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { suite, test } from "@testdeck/mocha";
import { BaseSuite } from "./Base.suite";
import { getConfig } from "../src/config/getConfig";
import { strictEqual } from "assert";

const OpenApiMocker = require('open-api-mocker');

@suite()
class PublicMappingSuite extends BaseSuite {
private mockServer: any;

private static mockPort = 7777;
private static rejectURL = `http://localhost:${PublicMappingSuite.mockPort}/reject`;

public async before() {
await this.initMockServer();
await super.before();
}

public async after() {
this.mockServer?.shutdown();
this.mockServer = null;
await super.after();
}

/**
* Init mock server
*/
private async initMockServer(): Promise<void> {
const mocker = this.mockServer = new OpenApiMocker({
port: PublicMappingSuite.mockPort,
schema: 'test/assets/webhook/mock.yml',
});

await mocker.validate();
await mocker.mock();
}

@test()
async rejectLogin(): Promise<void> {
await this.reloadPrxiWith({
webhook: {
login: PublicMappingSuite.rejectURL,
}
});

await this.withNewPage(getConfig().hostURL + '/pages/test', async (page) => {
await this.loginOnKeycloak(page);
const text = await this.getTextFromPage(page);

const json = JSON.parse(text);
// validate query to be in place
strictEqual(
json.http.originalUrl,
new URL(getConfig().redirect.pageRequest.e403).pathname
);
});
}
}
20 changes: 20 additions & 0 deletions test/assets/webhook/mock.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
openapi: '3.0.2'

info:
title: Mock WebHook Reject
version: '1.0'

paths:
/reject:
post:
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
reject:
type: boolean
x-faker: 'boolean(1)'
Loading

0 comments on commit b9b4b0c

Please sign in to comment.