Skip to content

Commit

Permalink
feat/minimal support aws alb (#180)
Browse files Browse the repository at this point in the history
  • Loading branch information
ottokruse authored Jan 2, 2025
1 parent 46be74c commit 1fab445
Show file tree
Hide file tree
Showing 25 changed files with 6,093 additions and 11,191 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ const verifier = JwtVerifier.create([
await verifier.hydrate();
```

Note: it is only useful to call this method if your calling process has an idle time window, in which it might just as well fetch the JWKS. For example, during container start up, when the load balancer does not yet route traffic to the container. Calling this method inside API Gateway custom authorizers or Lambda@Edge has no benefit (in fact, awaiting the call as part of the Lambda handler would even hurt performance as it bypasses the existing cached JWKS).
Note: it is only useful to call this method if your calling process has a time window, in which it might just as well fetch the JWKS. For example, during container start up, when the load balancer does not yet route traffic to the container. Calling this method in AWS Lambda functions only makes sense if you do it outside the Lambda handler, i.e. with a top-level await that is part of the code that runs during "cold starts". Awaiting `verifier.hydrate()` inside the Lambda handler will hurt performance as it always bypasses the existing cached JWKS.

### Clearing the JWKS cache

Expand Down Expand Up @@ -968,7 +968,7 @@ exports.handler = async (event) => {

### HTTP API Lambda Authorizer

An example of a sample HTTP Lambda authorizer is included [here](tests/cognito/lib/lambda-authorizer/index.js) as part of the test suite for the solution ([format 2.0](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html#http-api-lambda-authorizer.payload-format-response)).
An example of a sample HTTP Lambda authorizer is included [here](tests/cognito/lib/lambda-authorizer/index.mjs) as part of the test suite for the solution ([format 2.0](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html#http-api-lambda-authorizer.payload-format-response)).

### AppSync Lambda Authorizer

Expand Down
1,678 changes: 982 additions & 696 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion src/jwt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,11 @@ export function decomposeUnverifiedJwt(jwt: unknown): DecomposedJwt {
if (typeof jwt !== "string") {
throw new JwtParseError("JWT is not a string");
}
if (!jwt.match(/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/)) {
if (
!jwt.match(
/^[A-Za-z0-9_-]+={0,2}\.[A-Za-z0-9_-]+={0,2}\.[A-Za-z0-9_-]+={0,2}$/
)
) {
throw new JwtParseError(
"JWT string does not consist of exactly 3 parts (header, payload, signature)"
);
Expand Down
4 changes: 2 additions & 2 deletions src/node-web-compat-web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ const bufferFromBase64url = (function () {
{} as { [key: number]: number }
);
return function (base64url: string) {
const paddingLength = base64url.match(/^.+?(=?=?)$/)![1].length;
base64url = base64url.replace(/={1,2}$/, ""); // ignore padding (e.g. AWS ALB)
let first: number, second: number, third: number, fourth: number;
return base64url.match(/.{1,4}/g)!.reduce(
(acc, chunk, index) => {
Expand All @@ -135,7 +135,7 @@ const bufferFromBase64url = (function () {
acc[3 * index + 2] = ((third & 0b11) << 6) | fourth;
return acc;
},
new Uint8Array((base64url.length * 3) / 4 - paddingLength)
new Uint8Array((base64url.length * 3) / 4)
);
};
})();
3 changes: 3 additions & 0 deletions tests/cognito/.env.TEMPLATE
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
HOSTED_ZONE_ID=
HOSTED_ZONE_NAME=
ALB_DOMAIN_NAME=
4 changes: 3 additions & 1 deletion tests/cognito/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ node_modules
cdk.out

# Stack outputs
outputs.json
outputs.json

.env
12 changes: 10 additions & 2 deletions tests/cognito/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@
This is a CDK project that deploys a Cognito User Pool to get JWTs from for testing.
This CDK project's automated tests check that the User Pool's JWTs can indeed be successfully verified by aws-jwt-verify

## Prereqs

You need to have an existing Route 53 public hosted zone in your account (because we will setup AWS ALB with an HTTPS certificate).

## How to run the tests

- Clone the repo: `git clone https://github.com/awslabs/aws-jwt-verify`
- Install dev dependencies and create installable dist: `cd aws-jwt-verify && npm install && npm run pack-for-tests`
- Install CDK dependencies: `cd tests/cognito && npm install`
- The stack uses a custom CDK bootstrap toolkit. Therefore, it's necessary to first deploy the bootstrap toolkit stack: `aws cloudformation create-stack --template-body file://bootstrap-template.yml --stack-name AwsJwtVerifyTest-toolkit --capabilities CAPABILITY_NAMED_IAM`
- Deploy the stack to your default AWS account/region, saving outputs to `outputs.json`: `cdk deploy -O outputs.json --toolkit-stack-name AwsJwtVerifyTest-toolkit`
- Copy `.env.TEMPLATE` to `.env` and populate with the right values:
- HOSTED_ZONE_ID: the ID of an existing Route 53 public hosted zone in your account
- HOSTED_ZONE_NAME: the domain name of the hosted zone
- ALB_DOMAIN_NAME: the domain name that you want to give to the ALB (likely a subdomain of the hosted zone)
- Bootstrap your AWS account for AWS CDK: `cdk bootstrap`
- Deploy the stack to your default AWS account/region, saving outputs to `outputs.json`: `cdk deploy -O outputs.json`
- Execute the automated tests, this uses the outputs from `outputs.json`: `npm run test`

Next time, you can just run `npm run test` from the current working directory, or `npm run test:cognito` from the workspace root.
17 changes: 13 additions & 4 deletions tests/cognito/bin/cognito.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
#!/usr/bin/env node
import "source-map-support/register";
import * as cdk from "@aws-cdk/core";
import * as cdk from "aws-cdk-lib";
import { CognitoStack } from "../lib/cognito-stack";
import "dotenv/config";

const { HOSTED_ZONE_ID, HOSTED_ZONE_NAME, ALB_DOMAIN_NAME } = process.env;

if (!HOSTED_ZONE_ID || !HOSTED_ZONE_NAME || !ALB_DOMAIN_NAME) {
throw new Error(
"Please create an .env file with values for HOSTED_ZONE_ID, HOSTED_ZONE_NAME and ALB_DOMAIN_NAME"
);
}

const app = new cdk.App();
new CognitoStack(app, "AwsJwtCognitoTestStack", {
synthesizer: new cdk.DefaultStackSynthesizer({
qualifier: "test",
}),
albDomainName: ALB_DOMAIN_NAME,
hostedZoneId: HOSTED_ZONE_ID,
hostedZoneName: HOSTED_ZONE_NAME,
});
Loading

0 comments on commit 1fab445

Please sign in to comment.