Skip to content

Commit

Permalink
ATO-1291: Update controller to support request objects
Browse files Browse the repository at this point in the history
Uses new validation in controller, which enables support for request objects.
Also throws MethodNotAllowedError for non GET requests
  • Loading branch information
cearl1 authored and Ryan-Andrews99 committed Jan 8, 2025
1 parent e30763f commit d28bb17
Show file tree
Hide file tree
Showing 4 changed files with 1,256 additions and 466 deletions.
4 changes: 2 additions & 2 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import express, { Application, Express, Request, Response } from "express";
import { configController } from "./components/config/config-controller";
import { tokenController } from "./components/token/token-controller";
import { authoriseGetController } from "./components/authorise/authorise-get-controller";
import { authoriseController } from "./components/authorise/authorise-get-controller";
import { dedupeQueryParams } from "./middleware/dedupe-query-params";
import { userInfoController } from "./components/user-info/user-info-controller";
import { generateJWKS } from "./components/token/helper/key-helpers";
Expand All @@ -23,7 +23,7 @@ const createApp = (): Application => {
app.get("/", (req: Request, res: Response) => {
res.send("Express + TypeScript Server");
});
app.get("/authorize", authoriseGetController);
app.use("/authorize", authoriseController);

app.post(
"/config",
Expand Down
75 changes: 58 additions & 17 deletions src/components/authorise/authorise-get-controller.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,61 @@
import { Request, Response } from "express";
import { logger } from "../../logger";
import { parseAuthQueryParams } from "../../parse/parse-auth-request-query-params";
import { parseAuthRequest } from "../../parse/parse-auth-request";
import { AuthoriseRequestError } from "../../errors/authorise-request-error";
import { BadRequestError } from "../../errors/bad-request-error";
import { ParseAuthRequestError } from "../../errors/parse-auth-request-error";
import { Config } from "../../config";
import { MissingParameterError } from "../../errors/missing-parameter-error";
import { base64url } from "jose";
import { randomBytes } from "crypto";
import { validateAuthRequestQueryParams } from "../../validators/validate-auth-request-query-params";
import { MethodNotAllowedError } from "../../errors/method-not-allowed-error";
import { VectorOfTrust } from "../../types/vector-of-trust";
import { validateAuthRequestObject } from "../../validators/validate-auth-request-object";
import { transformRequestObject } from "../../utils/utils";
import { TrustChainValidationError } from "../../errors/trust-chain-validation-error";

export const authoriseGetController = (req: Request, res: Response): void => {
export const authoriseController = async (
req: Request,
res: Response
): Promise<void> => {
const config = Config.getInstance();

try {
const parsedAuthRequestParams = parseAuthQueryParams(
//We can safely cast this type as our middleware will handle
//any duplicate query params
req.query as Record<string, string | undefined>,
config
);
let parsedAuthRequest;

switch (req.method) {
case "GET":
parsedAuthRequest = parseAuthRequest(
//We can safely cast this type as our middleware will handle
//any duplicate query params
req.query as Record<string, string>
);
break;
default:
throw new MethodNotAllowedError(req.method);
}

if (!parsedAuthRequest.requestObject) {
logger.info("Validating request query params");
validateAuthRequestQueryParams(parsedAuthRequest, config);
} else {
logger.info("Validating request object");
await validateAuthRequestObject(parsedAuthRequest, config);
parsedAuthRequest = transformRequestObject(
parsedAuthRequest.requestObject
);
}

if (parsedAuthRequest.prompt.includes("select_account")) {
throw new AuthoriseRequestError({
errorCode: "unmet_authentication_requirements",
errorDescription: "Unmet authentication requirements",
httpStatusCode: 302,
state: parsedAuthRequest.state,
redirectUri: parsedAuthRequest.redirect_uri,
});
}

if (config.getAuthoriseErrors().includes("ACCESS_DENIED")) {
logger.warn("Client configured to return access_denied error response");
Expand All @@ -27,23 +64,22 @@ export const authoriseGetController = (req: Request, res: Response): void => {
errorDescription:
"Access denied by resource owner or authorization server",
httpStatusCode: 302,
redirectUri: parsedAuthRequestParams.redirect_uri,
state: parsedAuthRequestParams.state,
redirectUri: parsedAuthRequest.redirect_uri,
state: parsedAuthRequest.state,
});
}

const authCode = generateAuthCode();

config.addToAuthCodeRequestParamsStore(authCode, {
claims: parsedAuthRequestParams.claims,
nonce: parsedAuthRequestParams.nonce,
redirectUri: parsedAuthRequestParams.redirect_uri,
scopes: parsedAuthRequestParams.scope,
vtr: parsedAuthRequestParams.vtr[0],
claims: parsedAuthRequest.claims,
nonce: parsedAuthRequest.nonce,
redirectUri: parsedAuthRequest.redirect_uri,
scopes: parsedAuthRequest.scope,
vtr: (parsedAuthRequest.vtr as VectorOfTrust[])[0],
});

res.redirect(
`${parsedAuthRequestParams.redirect_uri}?code=${authCode}&state=${parsedAuthRequestParams.state}`
`${parsedAuthRequest.redirect_uri}?code=${authCode}&state=${parsedAuthRequest.state}`
);
return;
} catch (error) {
Expand Down Expand Up @@ -82,8 +118,13 @@ const handleRequestError = (
}
} else if (error instanceof BadRequestError) {
res.status(400).send("Invalid Request");
} else if (error instanceof MethodNotAllowedError) {
res.status(405).send(error.message);
} else if (error instanceof TrustChainValidationError) {
res.status(400).send(error.message);
} else {
logger.error("Unknown error occurred: " + (error as Error).message);
logger.error(error);
res.status(500).json({
message: "Internal Server Error",
});
Expand Down
5 changes: 5 additions & 0 deletions src/errors/method-not-allowed-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export class MethodNotAllowedError extends Error {
constructor(httpMethod: string) {
super(`Method "${httpMethod} not allowed"`);
}
}
Loading

0 comments on commit d28bb17

Please sign in to comment.