Add basic node-cache with 1 hour TTL for caching keys retrieved from AWS public key endpoint

This commit is contained in:
Jonah Back
2021-01-18 14:22:38 -08:00
parent 147648a2d1
commit 02140eb89a
4 changed files with 23 additions and 8 deletions
+1
View File
@@ -54,6 +54,7 @@
"knex": "^0.21.6",
"moment": "^2.26.0",
"morgan": "^1.10.0",
"node-cache": "^5.1.2",
"openid-client": "^4.2.1",
"passport": "^0.4.1",
"passport-github2": "^0.1.12",
@@ -102,7 +102,7 @@ describe('TokenFactory', () => {
iat: expect.any(Number),
exp: expect.any(Number),
});
expect(payload.exp).toBe((payload.iat as number) + keyDurationSeconds);
expect(payload.exp).toBe(Number(payload.iat) + keyDurationSeconds);
});
it('should generate new signing keys when the current one expires', async () => {
@@ -16,7 +16,7 @@
import {
AuthProviderFactoryOptions,
AuthProviderRouteHandlers,
IdentityResolver,
ExperimentalIdentityResolver,
} from '../types';
import express from 'express';
// @ts-ignore no types available for R2
@@ -24,6 +24,7 @@ import r2 from 'r2';
import * as crypto from 'crypto';
import { KeyObject } from 'crypto';
import { Logger } from 'winston';
import NodeCache from 'node-cache';
import jwtVerify from 'jose/jwt/verify';
import { CatalogApi } from '@backstage/catalog-client';
@@ -35,7 +36,7 @@ const ALB_JWT_HEADER = 'x-amzn-oidc-data';
type AwsAlbAuthProviderOptions = {
region: string;
issuer: string;
identityResolutionCallback: IdentityResolver;
identityResolutionCallback: ExperimentalIdentityResolver;
};
export const getJWTHeaders = (input: string) => {
const encoded = input.split('.')[0];
@@ -46,7 +47,7 @@ export class AwsAlbAuthProvider implements AuthProviderRouteHandlers {
private logger: Logger;
private readonly catalogClient: CatalogApi;
private options: AwsAlbAuthProviderOptions;
private readonly keyCache: { [key: string]: KeyObject };
private readonly keyCache: NodeCache;
constructor(
logger: Logger,
@@ -56,7 +57,7 @@ export class AwsAlbAuthProvider implements AuthProviderRouteHandlers {
this.logger = logger;
this.catalogClient = catalogClient;
this.options = options;
this.keyCache = {};
this.keyCache = new NodeCache({ stdTTL: 3600 });
}
frameHandler(): Promise<void> {
return Promise.resolve(undefined);
@@ -96,14 +97,15 @@ export class AwsAlbAuthProvider implements AuthProviderRouteHandlers {
}
async getKey(keyId: string): Promise<KeyObject> {
if (this.keyCache[keyId]) {
return this.keyCache[keyId];
const optionalCacheKey = this.keyCache.get<KeyObject>(keyId);
if (optionalCacheKey) {
return optionalCacheKey;
}
const keyText: string = await r2(
`https://public-keys.auth.elb.${this.options.region}.amazonaws.com/${keyId}`,
).text;
const keyValue = crypto.createPublicKey(keyText);
this.keyCache[keyId] = keyValue;
this.keyCache.set(keyId, keyValue);
return keyValue;
}
}
+12
View File
@@ -10126,6 +10126,11 @@ clone-response@^1.0.2:
dependencies:
mimic-response "^1.0.0"
clone@2.x:
version "2.1.2"
resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
clone@^1.0.2:
version "1.0.4"
resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
@@ -18806,6 +18811,13 @@ node-addon-api@2.0.0:
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.0.tgz#f9afb8d777a91525244b01775ea0ddbe1125483b"
integrity sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA==
node-cache@^5.1.2:
version "5.1.2"
resolved "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d"
integrity sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==
dependencies:
clone "2.x"
node-dir@^0.1.10:
version "0.1.17"
resolved "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5"