@liflig/cdk 3.4.0 → 3.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api-gateway/authorizers/basic-auth-authorizer.js +160 -0
- package/lib/api-gateway/authorizers/cognito-user-pool-authorizer.js +133 -0
- package/lib/api-gateway/authorizers/cognito-user-pool-or-basic-auth-authorizer.js +238 -0
- package/lib/api-gateway/http-api-gateway.d.ts +41 -4
- package/lib/api-gateway/http-api-gateway.js +17 -7
- package/package.json +3 -3
- package/lib/api-gateway/authorizer-lambdas/basic-auth-authorizer.js +0 -160
- package/lib/api-gateway/authorizer-lambdas/cognito-user-pool-authorizer.js +0 -133
- package/lib/api-gateway/authorizer-lambdas/cognito-user-pool-or-basic-auth-authorizer.js +0 -238
- /package/lib/api-gateway/{authorizer-lambdas → authorizers}/basic-auth-authorizer.d.ts +0 -0
- /package/lib/api-gateway/{authorizer-lambdas → authorizers}/cognito-user-pool-authorizer.d.ts +0 -0
- /package/lib/api-gateway/{authorizer-lambdas → authorizers}/cognito-user-pool-or-basic-auth-authorizer.d.ts +0 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This lambda verifies authorization header against static basic auth credentials saved in Secrets
|
|
3
|
+
* Manager.
|
|
4
|
+
*
|
|
5
|
+
* Expects the following environment variables:
|
|
6
|
+
* - CREDENTIALS_SECRET_NAME
|
|
7
|
+
* - Name of secret in AWS Secrets Manager that stores basic auth credentials. See
|
|
8
|
+
* `BasicAuthAuthorizerProps` on the `ApiGateway` construct for the supported formats.
|
|
9
|
+
*/
|
|
10
|
+
import { SecretsManager } from "@aws-sdk/client-secrets-manager";
|
|
11
|
+
export const handler = async (event) => {
|
|
12
|
+
const authHeader = event.headers?.authorization;
|
|
13
|
+
if (!authHeader || !authHeader.startsWith("Basic ")) {
|
|
14
|
+
return { isAuthorized: false };
|
|
15
|
+
}
|
|
16
|
+
const expectedCredentials = await getExpectedBasicAuthCredentials();
|
|
17
|
+
for (const expected of expectedCredentials) {
|
|
18
|
+
if (authHeader === expected.basicAuthHeader) {
|
|
19
|
+
return {
|
|
20
|
+
isAuthorized: true,
|
|
21
|
+
context: {
|
|
22
|
+
username: expected.username,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return { isAuthorized: false };
|
|
28
|
+
};
|
|
29
|
+
/** Cache this value, so that subsequent lambda invocations don't have to refetch. */
|
|
30
|
+
let cachedBasicAuthCredentials = undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Returns an array, to support credential secrets with multiple values (see
|
|
33
|
+
* `BasicAuthAuthorizerProps` on the `ApiGateway` construct for more on this).
|
|
34
|
+
*/
|
|
35
|
+
async function getExpectedBasicAuthCredentials() {
|
|
36
|
+
if (cachedBasicAuthCredentials === undefined) {
|
|
37
|
+
const secretName = process.env["CREDENTIALS_SECRET_NAME"];
|
|
38
|
+
if (!secretName) {
|
|
39
|
+
console.error("CREDENTIALS_SECRET_NAME env variable is not defined");
|
|
40
|
+
throw new Error();
|
|
41
|
+
}
|
|
42
|
+
cachedBasicAuthCredentials = await getBasicAuthCredentialsSecret(secretName);
|
|
43
|
+
}
|
|
44
|
+
return cachedBasicAuthCredentials;
|
|
45
|
+
}
|
|
46
|
+
async function getBasicAuthCredentialsSecret(secretName) {
|
|
47
|
+
const secret = await getSecretValue(secretName);
|
|
48
|
+
if (isUsernameAndPasswordObject(secret)) {
|
|
49
|
+
return [encodeBasicAuthCredentials(secret)];
|
|
50
|
+
}
|
|
51
|
+
// See `BasicAuthAuthorizerProps` on the `ApiGateway` construct for an explanation of the formats
|
|
52
|
+
// we parse here
|
|
53
|
+
if (hasCredentialsKeyWithStringValue(secret)) {
|
|
54
|
+
let credentialsArray;
|
|
55
|
+
try {
|
|
56
|
+
credentialsArray = JSON.parse(secret.credentials);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
console.error(`Failed to parse credentials array in secret '${secretName}' as JSON`, e);
|
|
60
|
+
throw new Error();
|
|
61
|
+
}
|
|
62
|
+
if (isArrayOfUsernameAndPasswordObjects(credentialsArray)) {
|
|
63
|
+
return credentialsArray.map(encodeBasicAuthCredentials);
|
|
64
|
+
}
|
|
65
|
+
if (isStringArray(credentialsArray)) {
|
|
66
|
+
return credentialsArray.map(parseEncodedBasicAuthCredentials);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
console.error(`Basic auth credentials secret did not follow any expected format (secret name: '${secretName}')`);
|
|
70
|
+
throw new Error();
|
|
71
|
+
}
|
|
72
|
+
/** For overriding dependency creation in tests. */
|
|
73
|
+
export const dependencies = {
|
|
74
|
+
createSecretsManager: () => new SecretsManager(),
|
|
75
|
+
};
|
|
76
|
+
async function getSecretValue(secretName) {
|
|
77
|
+
const client = dependencies.createSecretsManager();
|
|
78
|
+
const secret = await client.getSecretValue({ SecretId: secretName });
|
|
79
|
+
if (!secret.SecretString) {
|
|
80
|
+
console.error(`Secret value not found for '${secretName}'`);
|
|
81
|
+
throw new Error();
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
return JSON.parse(secret.SecretString);
|
|
85
|
+
}
|
|
86
|
+
catch (e) {
|
|
87
|
+
console.error(`Failed to parse secret '${secretName}' as JSON:`, e);
|
|
88
|
+
throw new Error();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function encodeBasicAuthCredentials(credentials) {
|
|
92
|
+
const basicAuthHeader = "Basic " +
|
|
93
|
+
Buffer.from(`${credentials.username}:${credentials.password}`).toString("base64");
|
|
94
|
+
return { basicAuthHeader, username: credentials.username };
|
|
95
|
+
}
|
|
96
|
+
function isUsernameAndPasswordObject(value) {
|
|
97
|
+
return (typeof value === "object" &&
|
|
98
|
+
value !== null &&
|
|
99
|
+
"username" in value &&
|
|
100
|
+
typeof value.username === "string" &&
|
|
101
|
+
"password" in value &&
|
|
102
|
+
typeof value.password === "string");
|
|
103
|
+
}
|
|
104
|
+
function isArrayOfUsernameAndPasswordObjects(value) {
|
|
105
|
+
if (!Array.isArray(value)) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
for (const element of value) {
|
|
109
|
+
if (!isUsernameAndPasswordObject(element)) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
function hasCredentialsKeyWithStringValue(value) {
|
|
116
|
+
return (typeof value === "object" &&
|
|
117
|
+
value !== null &&
|
|
118
|
+
"credentials" in value &&
|
|
119
|
+
typeof value.credentials === "string");
|
|
120
|
+
}
|
|
121
|
+
function isStringArray(value) {
|
|
122
|
+
if (!Array.isArray(value)) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
for (const element of value) {
|
|
126
|
+
if (typeof element !== "string") {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* We want to return the requesting username as a context variable in
|
|
134
|
+
* {@link AuthorizerResult.context}, for API Gateway access logs and parameter mapping. So if the
|
|
135
|
+
* basic auth credentials secret is stored as pre-encoded base64 strings, we need to parse them to
|
|
136
|
+
* get the username.
|
|
137
|
+
*/
|
|
138
|
+
function parseEncodedBasicAuthCredentials(encodedCredentials) {
|
|
139
|
+
let decodedCredentials;
|
|
140
|
+
try {
|
|
141
|
+
decodedCredentials = Buffer.from(encodedCredentials, "base64").toString();
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
console.error("Basic auth credentials secret could not be decoded as base64:", e);
|
|
145
|
+
throw new Error();
|
|
146
|
+
}
|
|
147
|
+
const usernameAndPassword = decodedCredentials.split(":", 2);
|
|
148
|
+
if (usernameAndPassword.length !== 2) {
|
|
149
|
+
console.error("Basic auth credentials secret could not be decoded as 'username:password'");
|
|
150
|
+
throw new Error();
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
basicAuthHeader: `Basic ${encodedCredentials}`,
|
|
154
|
+
username: usernameAndPassword[0],
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
export function clearCache() {
|
|
158
|
+
cachedBasicAuthCredentials = undefined;
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzaWMtYXV0aC1hdXRob3JpemVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwaS1nYXRld2F5L2F1dGhvcml6ZXJzL2Jhc2ljLWF1dGgtYXV0aG9yaXplci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7R0FRRztBQU1ILE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQTtBQW9CaEUsTUFBTSxDQUFDLE1BQU0sT0FBTyxHQUFHLEtBQUssRUFDMUIsS0FBeUMsRUFDZCxFQUFFO0lBQzdCLE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFBO0lBQy9DLElBQUksQ0FBQyxVQUFVLElBQUksQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFDcEQsT0FBTyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsQ0FBQTtJQUNoQyxDQUFDO0lBRUQsTUFBTSxtQkFBbUIsR0FBRyxNQUFNLCtCQUErQixFQUFFLENBQUE7SUFFbkUsS0FBSyxNQUFNLFFBQVEsSUFBSSxtQkFBbUIsRUFBRSxDQUFDO1FBQzNDLElBQUksVUFBVSxLQUFLLFFBQVEsQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUM1QyxPQUFPO2dCQUNMLFlBQVksRUFBRSxJQUFJO2dCQUNsQixPQUFPLEVBQUU7b0JBQ1AsUUFBUSxFQUFFLFFBQVEsQ0FBQyxRQUFRO2lCQUM1QjthQUNGLENBQUE7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU8sRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLENBQUE7QUFDaEMsQ0FBQyxDQUFBO0FBT0QscUZBQXFGO0FBQ3JGLElBQUksMEJBQTBCLEdBQzVCLFNBQVMsQ0FBQTtBQUVYOzs7R0FHRztBQUNILEtBQUssVUFBVSwrQkFBK0I7SUFHNUMsSUFBSSwwQkFBMEIsS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUM3QyxNQUFNLFVBQVUsR0FDZCxP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LENBQUM7UUFDNUIsSUFBSSxPQUFPLE9BQU8sS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUNoQyxPQUFPLEtBQUssQ0FBQTtRQUNkLENBQUM7SUFDSCxDQUFDO0lBRUQsT0FBTyxJQUFJLENBQUE7QUFDYixDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxTQUFTLGdDQUFnQyxDQUN2QyxrQkFBMEI7SUFFMUIsSUFBSSxrQkFBMEIsQ0FBQTtJQUM5QixJQUFJLENBQUM7UUFDSCxrQkFBa0IsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLFFBQVEsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFBO0lBQzNFLENBQUM7SUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQ1gsT0FBTyxDQUFDLEtBQUssQ0FDWCwrREFBK0QsRUFDL0QsQ0FBQyxDQUNGLENBQUE7UUFDRCxNQUFNLElBQUksS0FBSyxFQUFFLENBQUE7SUFDbkIsQ0FBQztJQUVELE1BQU0sbUJBQW1CLEdBQUcsa0JBQWtCLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQTtJQUM1RCxJQUFJLG1CQUFtQixDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUNyQyxPQUFPLENBQUMsS0FBSyxDQUNYLDJFQUEyRSxDQUM1RSxDQUFBO1FBQ0QsTUFBTSxJQUFJLEtBQUssRUFBRSxDQUFBO0lBQ25CLENBQUM7SUFFRCxPQUFPO1FBQ0wsZUFBZSxFQUFFLFNBQVMsa0JBQWtCLEVBQUU7UUFDOUMsUUFBUSxFQUFFLG1CQUFtQixDQUFDLENBQUMsQ0FBQztLQUNqQyxDQUFBO0FBQ0gsQ0FBQztBQUVELE1BQU0sVUFBVSxVQUFVO0lBQ3hCLDBCQUEwQixHQUFHLFNBQVMsQ0FBQTtBQUN4QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUaGlzIGxhbWJkYSB2ZXJpZmllcyBhdXRob3JpemF0aW9uIGhlYWRlciBhZ2FpbnN0IHN0YXRpYyBiYXNpYyBhdXRoIGNyZWRlbnRpYWxzIHNhdmVkIGluIFNlY3JldHNcbiAqIE1hbmFnZXIuXG4gKlxuICogRXhwZWN0cyB0aGUgZm9sbG93aW5nIGVudmlyb25tZW50IHZhcmlhYmxlczpcbiAqIC0gQ1JFREVOVElBTFNfU0VDUkVUX05BTUVcbiAqICAgLSBOYW1lIG9mIHNlY3JldCBpbiBBV1MgU2VjcmV0cyBNYW5hZ2VyIHRoYXQgc3RvcmVzIGJhc2ljIGF1dGggY3JlZGVudGlhbHMuIFNlZVxuICogICAgIGBCYXNpY0F1dGhBdXRob3JpemVyUHJvcHNgIG9uIHRoZSBgQXBpR2F0ZXdheWAgY29uc3RydWN0IGZvciB0aGUgc3VwcG9ydGVkIGZvcm1hdHMuXG4gKi9cblxuaW1wb3J0IHR5cGUge1xuICBBUElHYXRld2F5UmVxdWVzdEF1dGhvcml6ZXJFdmVudFYyLFxuICBBUElHYXRld2F5U2ltcGxlQXV0aG9yaXplclJlc3VsdCxcbn0gZnJvbSBcImF3cy1sYW1iZGFcIlxuaW1wb3J0IHsgU2VjcmV0c01hbmFnZXIgfSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LXNlY3JldHMtbWFuYWdlclwiXG5cbnR5cGUgQXV0aG9yaXplclJlc3VsdCA9IEFQSUdhdGV3YXlTaW1wbGVBdXRob3JpemVyUmVzdWx0ICYge1xuICAvKipcbiAgICogUmV0dXJuaW5nIGEgY29udGV4dCBvYmplY3QgZnJvbSBvdXIgYXV0aG9yaXplciBhbGxvd3Mgb3VyIEFQSSBHYXRld2F5IHRvIGFjY2VzcyB0aGVzZSB2YXJpYWJsZXNcbiAgICogdmlhIGAke2NvbnRleHQuYXV0aG9yaXplci48cHJvcGVydHk+fWAuXG4gICAqIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9hcGlnYXRld2F5L2xhdGVzdC9kZXZlbG9wZXJndWlkZS9odHRwLWFwaS1wYXJhbWV0ZXItbWFwcGluZy5odG1sXG4gICAqL1xuICBjb250ZXh0Pzoge1xuICAgIC8qKlxuICAgICAqIElmIHRoZSByZXF1ZXN0J3MgY3JlZGVudGlhbHMgYXJlIHZlcmlmaWVkLCB3ZSByZXR1cm4gdGhlIHVzZXJuYW1lIHRoYXQgd2FzIHVzZWQgaW4gdGhpc1xuICAgICAqIGNvbnRleHQgdmFyaWFibGUgKG5hbWVkIGBhdXRob3JpemVyLnVzZXJuYW1lYCkuIFdlIHVzZSB0aGlzIHRvIGluY2x1ZGUgdGhlIHJlcXVlc3RpbmcgdXNlciBpblxuICAgICAqIHRoZSBBUEkgR2F0ZXdheSBhY2Nlc3MgbG9ncyAoc2VlIGBkZWZhdWx0QWNjZXNzTG9nRm9ybWF0YCBpbiBvdXIgYEFwaUdhdGV3YXlgIGNvbnN0cnVjdCkuIFlvdVxuICAgICAqIGNhbiBhbHNvIHVzZSB0aGlzIHdoZW4gbWFwcGluZyBwYXJhbWV0ZXJzIHRvIHRoZSBiYWNrZW5kIGludGVncmF0aW9uIChzZWVcbiAgICAgKiBgQWxiSW50ZWdyYXRpb25Qcm9wcy5tYXBQYXJhbWV0ZXJzYCBvbiB0aGUgYEFwaUdhdGV3YXlgIGNvbnN0cnVjdCkuXG4gICAgICovXG4gICAgdXNlcm5hbWU6IHN0cmluZ1xuICB9XG59XG5cbmV4cG9ydCBjb25zdCBoYW5kbGVyID0gYXN5bmMgKFxuICBldmVudDogQVBJR2F0ZXdheVJlcXVlc3RBdXRob3JpemVyRXZlbnRWMixcbik6IFByb21pc2U8QXV0aG9yaXplclJlc3VsdD4gPT4ge1xuICBjb25zdCBhdXRoSGVhZGVyID0gZXZlbnQuaGVhZGVycz8uYXV0aG9yaXphdGlvblxuICBpZiAoIWF1dGhIZWFkZXIgfHwgIWF1dGhIZWFkZXIuc3RhcnRzV2l0aChcIkJhc2ljIFwiKSkge1xuICAgIHJldHVybiB7IGlzQXV0aG9yaXplZDogZmFsc2UgfVxuICB9XG5cbiAgY29uc3QgZXhwZWN0ZWRDcmVkZW50aWFscyA9IGF3YWl0IGdldEV4cGVjdGVkQmFzaWNBdXRoQ3JlZGVudGlhbHMoKVxuXG4gIGZvciAoY29uc3QgZXhwZWN0ZWQgb2YgZXhwZWN0ZWRDcmVkZW50aWFscykge1xuICAgIGlmIChhdXRoSGVhZGVyID09PSBleHBlY3RlZC5iYXNpY0F1dGhIZWFkZXIpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGlzQXV0aG9yaXplZDogdHJ1ZSxcbiAgICAgICAgY29udGV4dDoge1xuICAgICAgICAgIHVzZXJuYW1lOiBleHBlY3RlZC51c2VybmFtZSxcbiAgICAgICAgfSxcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4geyBpc0F1dGhvcml6ZWQ6IGZhbHNlIH1cbn1cblxudHlwZSBFeHBlY3RlZEJhc2ljQXV0aENyZWRlbnRpYWxzID0ge1xuICBiYXNpY0F1dGhIZWFkZXI6IHN0cmluZ1xuICB1c2VybmFtZTogc3RyaW5nXG59XG5cbi8qKiBDYWNoZSB0aGlzIHZhbHVlLCBzbyB0aGF0IHN1YnNlcXVlbnQgbGFtYmRhIGludm9jYXRpb25zIGRvbid0IGhhdmUgdG8gcmVmZXRjaC4gKi9cbmxldCBjYWNoZWRCYXNpY0F1dGhDcmVkZW50aWFsczogRXhwZWN0ZWRCYXNpY0F1dGhDcmVkZW50aWFsc1tdIHwgdW5kZWZpbmVkID1cbiAgdW5kZWZpbmVkXG5cbi8qKlxuICogUmV0dXJucyBhbiBhcnJheSwgdG8gc3VwcG9ydCBjcmVkZW50aWFsIHNlY3JldHMgd2l0aCBtdWx0aXBsZSB2YWx1ZXMgKHNlZVxuICogYEJhc2ljQXV0aEF1dGhvcml6ZXJQcm9wc2Agb24gdGhlIGBBcGlHYXRld2F5YCBjb25zdHJ1Y3QgZm9yIG1vcmUgb24gdGhpcykuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGdldEV4cGVjdGVkQmFzaWNBdXRoQ3JlZGVudGlhbHMoKTogUHJvbWlzZTxcbiAgRXhwZWN0ZWRCYXNpY0F1dGhDcmVkZW50aWFsc1tdXG4+IHtcbiAgaWYgKGNhY2hlZEJhc2ljQXV0aENyZWRlbnRpYWxzID09PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBzZWNyZXROYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQgPVxuICAgICAgcHJvY2Vzcy5lbnZbXCJDUkVERU5USUFMU19TRUNSRVRfTkFNRVwiXVxuICAgIGlmICghc2VjcmV0TmFtZSkge1xuICAgICAgY29uc29sZS5lcnJvcihcIkNSRURFTlRJQUxTX1NFQ1JFVF9OQU1FIGVudiB2YXJpYWJsZSBpcyBub3QgZGVmaW5lZFwiKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKClcbiAgICB9XG5cbiAgICBjYWNoZWRCYXNpY0F1dGhDcmVkZW50aWFscyA9IGF3YWl0IGdldEJhc2ljQXV0aENyZWRlbnRpYWxzU2VjcmV0KHNlY3JldE5hbWUpXG4gIH1cblxuICByZXR1cm4gY2FjaGVkQmFzaWNBdXRoQ3JlZGVudGlhbHNcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0QmFzaWNBdXRoQ3JlZGVudGlhbHNTZWNyZXQoXG4gIHNlY3JldE5hbWU6IHN0cmluZyxcbik6IFByb21pc2U8RXhwZWN0ZWRCYXNpY0F1dGhDcmVkZW50aWFsc1tdPiB7XG4gIGNvbnN0IHNlY3JldCA9IGF3YWl0IGdldFNlY3JldFZhbHVlKHNlY3JldE5hbWUpXG5cbiAgaWYgKGlzVXNlcm5hbWVBbmRQYXNzd29yZE9iamVjdChzZWNyZXQpKSB7XG4gICAgcmV0dXJuIFtlbmNvZGVCYXNpY0F1dGhDcmVkZW50aWFscyhzZWNyZXQpXVxuICB9XG5cbiAgLy8gU2VlIGBCYXNpY0F1dGhBdXRob3JpemVyUHJvcHNgIG9uIHRoZSBgQXBpR2F0ZXdheWAgY29uc3RydWN0IGZvciBhbiBleHBsYW5hdGlvbiBvZiB0aGUgZm9ybWF0c1xuICAvLyB3ZSBwYXJzZSBoZXJlXG4gIGlmIChoYXNDcmVkZW50aWFsc0tleVdpdGhTdHJpbmdWYWx1ZShzZWNyZXQpKSB7XG4gICAgbGV0IGNyZWRlbnRpYWxzQXJyYXk6IHVua25vd25cbiAgICB0cnkge1xuICAgICAgY3JlZGVudGlhbHNBcnJheSA9IEpTT04ucGFyc2Uoc2VjcmV0LmNyZWRlbnRpYWxzKVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgIGBGYWlsZWQgdG8gcGFyc2UgY3JlZGVudGlhbHMgYXJyYXkgaW4gc2VjcmV0ICcke3NlY3JldE5hbWV9JyBhcyBKU09OYCxcbiAgICAgICAgZSxcbiAgICAgIClcbiAgICAgIHRocm93IG5ldyBFcnJvcigpXG4gICAgfVxuXG4gICAgaWYgKGlzQXJyYXlPZlVzZXJuYW1lQW5kUGFzc3dvcmRPYmplY3RzKGNyZWRlbnRpYWxzQXJyYXkpKSB7XG4gICAgICByZXR1cm4gY3JlZGVudGlhbHNBcnJheS5tYXAoZW5jb2RlQmFzaWNBdXRoQ3JlZGVudGlhbHMpXG4gICAgfVxuXG4gICAgaWYgKGlzU3RyaW5nQXJyYXkoY3JlZGVudGlhbHNBcnJheSkpIHtcbiAgICAgIHJldHVybiBjcmVkZW50aWFsc0FycmF5Lm1hcChwYXJzZUVuY29kZWRCYXNpY0F1dGhDcmVkZW50aWFscylcbiAgICB9XG4gIH1cblxuICBjb25zb2xlLmVycm9yKFxuICAgIGBCYXNpYyBhdXRoIGNyZWRlbnRpYWxzIHNlY3JldCBkaWQgbm90IGZvbGxvdyBhbnkgZXhwZWN0ZWQgZm9ybWF0IChzZWNyZXQgbmFtZTogJyR7c2VjcmV0TmFtZX0nKWAsXG4gIClcbiAgdGhyb3cgbmV3IEVycm9yKClcbn1cblxuLyoqIEZvciBvdmVycmlkaW5nIGRlcGVuZGVuY3kgY3JlYXRpb24gaW4gdGVzdHMuICovXG5leHBvcnQgY29uc3QgZGVwZW5kZW5jaWVzID0ge1xuICBjcmVhdGVTZWNyZXRzTWFuYWdlcjogKCkgPT4gbmV3IFNlY3JldHNNYW5hZ2VyKCksXG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldFNlY3JldFZhbHVlKHNlY3JldE5hbWU6IHN0cmluZyk6IFByb21pc2U8dW5rbm93bj4ge1xuICBjb25zdCBjbGllbnQgPSBkZXBlbmRlbmNpZXMuY3JlYXRlU2VjcmV0c01hbmFnZXIoKVxuICBjb25zdCBzZWNyZXQgPSBhd2FpdCBjbGllbnQuZ2V0U2VjcmV0VmFsdWUoeyBTZWNyZXRJZDogc2VjcmV0TmFtZSB9KVxuXG4gIGlmICghc2VjcmV0LlNlY3JldFN0cmluZykge1xuICAgIGNvbnNvbGUuZXJyb3IoYFNlY3JldCB2YWx1ZSBub3QgZm91bmQgZm9yICcke3NlY3JldE5hbWV9J2ApXG4gICAgdGhyb3cgbmV3IEVycm9yKClcbiAgfVxuXG4gIHRyeSB7XG4gICAgcmV0dXJuIEpTT04ucGFyc2Uoc2VjcmV0LlNlY3JldFN0cmluZylcbiAgfSBjYXRjaCAoZSkge1xuICAgIGNvbnNvbGUuZXJyb3IoYEZhaWxlZCB0byBwYXJzZSBzZWNyZXQgJyR7c2VjcmV0TmFtZX0nIGFzIEpTT046YCwgZSlcbiAgICB0aHJvdyBuZXcgRXJyb3IoKVxuICB9XG59XG5cbmZ1bmN0aW9uIGVuY29kZUJhc2ljQXV0aENyZWRlbnRpYWxzKGNyZWRlbnRpYWxzOiB7XG4gIHVzZXJuYW1lOiBzdHJpbmdcbiAgcGFzc3dvcmQ6IHN0cmluZ1xufSk6IEV4cGVjdGVkQmFzaWNBdXRoQ3JlZGVudGlhbHMge1xuICBjb25zdCBiYXNpY0F1dGhIZWFkZXIgPVxuICAgIFwiQmFzaWMgXCIgK1xuICAgIEJ1ZmZlci5mcm9tKGAke2NyZWRlbnRpYWxzLnVzZXJuYW1lfToke2NyZWRlbnRpYWxzLnBhc3N3b3JkfWApLnRvU3RyaW5nKFxuICAgICAgXCJiYXNlNjRcIixcbiAgICApXG5cbiAgcmV0dXJuIHsgYmFzaWNBdXRoSGVhZGVyLCB1c2VybmFtZTogY3JlZGVudGlhbHMudXNlcm5hbWUgfVxufVxuXG5mdW5jdGlvbiBpc1VzZXJuYW1lQW5kUGFzc3dvcmRPYmplY3QoXG4gIHZhbHVlOiB1bmtub3duLFxuKTogdmFsdWUgaXMgeyB1c2VybmFtZTogc3RyaW5nOyBwYXNzd29yZDogc3RyaW5nIH0ge1xuICByZXR1cm4gKFxuICAgIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIiAmJlxuICAgIHZhbHVlICE9PSBudWxsICYmXG4gICAgXCJ1c2VybmFtZVwiIGluIHZhbHVlICYmXG4gICAgdHlwZW9mIHZhbHVlLnVzZXJuYW1lID09PSBcInN0cmluZ1wiICYmXG4gICAgXCJwYXNzd29yZFwiIGluIHZhbHVlICYmXG4gICAgdHlwZW9mIHZhbHVlLnBhc3N3b3JkID09PSBcInN0cmluZ1wiXG4gIClcbn1cblxuZnVuY3Rpb24gaXNBcnJheU9mVXNlcm5hbWVBbmRQYXNzd29yZE9iamVjdHMoXG4gIHZhbHVlOiB1bmtub3duLFxuKTogdmFsdWUgaXMgeyB1c2VybmFtZTogc3RyaW5nOyBwYXNzd29yZDogc3RyaW5nIH1bXSB7XG4gIGlmICghQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIGZvciAoY29uc3QgZWxlbWVudCBvZiB2YWx1ZSkge1xuICAgIGlmICghaXNVc2VybmFtZUFuZFBhc3N3b3JkT2JqZWN0KGVsZW1lbnQpKSB7XG4gICAgICByZXR1cm4gZmFsc2VcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdHJ1ZVxufVxuXG5mdW5jdGlvbiBoYXNDcmVkZW50aWFsc0tleVdpdGhTdHJpbmdWYWx1ZShcbiAgdmFsdWU6IHVua25vd24sXG4pOiB2YWx1ZSBpcyB7IGNyZWRlbnRpYWxzOiBzdHJpbmcgfSB7XG4gIHJldHVybiAoXG4gICAgdHlwZW9mIHZhbHVlID09PSBcIm9iamVjdFwiICYmXG4gICAgdmFsdWUgIT09IG51bGwgJiZcbiAgICBcImNyZWRlbnRpYWxzXCIgaW4gdmFsdWUgJiZcbiAgICB0eXBlb2YgdmFsdWUuY3JlZGVudGlhbHMgPT09IFwic3RyaW5nXCJcbiAgKVxufVxuXG5mdW5jdGlvbiBpc1N0cmluZ0FycmF5KHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgc3RyaW5nW10ge1xuICBpZiAoIUFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cblxuICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgdmFsdWUpIHtcbiAgICBpZiAodHlwZW9mIGVsZW1lbnQgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0cnVlXG59XG5cbi8qKlxuICogV2Ugd2FudCB0byByZXR1cm4gdGhlIHJlcXVlc3RpbmcgdXNlcm5hbWUgYXMgYSBjb250ZXh0IHZhcmlhYmxlIGluXG4gKiB7QGxpbmsgQXV0aG9yaXplclJlc3VsdC5jb250ZXh0fSwgZm9yIEFQSSBHYXRld2F5IGFjY2VzcyBsb2dzIGFuZCBwYXJhbWV0ZXIgbWFwcGluZy4gU28gaWYgdGhlXG4gKiBiYXNpYyBhdXRoIGNyZWRlbnRpYWxzIHNlY3JldCBpcyBzdG9yZWQgYXMgcHJlLWVuY29kZWQgYmFzZTY0IHN0cmluZ3MsIHdlIG5lZWQgdG8gcGFyc2UgdGhlbSB0b1xuICogZ2V0IHRoZSB1c2VybmFtZS5cbiAqL1xuZnVuY3Rpb24gcGFyc2VFbmNvZGVkQmFzaWNBdXRoQ3JlZGVudGlhbHMoXG4gIGVuY29kZWRDcmVkZW50aWFsczogc3RyaW5nLFxuKTogRXhwZWN0ZWRCYXNpY0F1dGhDcmVkZW50aWFscyB7XG4gIGxldCBkZWNvZGVkQ3JlZGVudGlhbHM6IHN0cmluZ1xuICB0cnkge1xuICAgIGRlY29kZWRDcmVkZW50aWFscyA9IEJ1ZmZlci5mcm9tKGVuY29kZWRDcmVkZW50aWFscywgXCJiYXNlNjRcIikudG9TdHJpbmcoKVxuICB9IGNhdGNoIChlKSB7XG4gICAgY29uc29sZS5lcnJvcihcbiAgICAgIFwiQmFzaWMgYXV0aCBjcmVkZW50aWFscyBzZWNyZXQgY291bGQgbm90IGJlIGRlY29kZWQgYXMgYmFzZTY0OlwiLFxuICAgICAgZSxcbiAgICApXG4gICAgdGhyb3cgbmV3IEVycm9yKClcbiAgfVxuXG4gIGNvbnN0IHVzZXJuYW1lQW5kUGFzc3dvcmQgPSBkZWNvZGVkQ3JlZGVudGlhbHMuc3BsaXQoXCI6XCIsIDIpXG4gIGlmICh1c2VybmFtZUFuZFBhc3N3b3JkLmxlbmd0aCAhPT0gMikge1xuICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICBcIkJhc2ljIGF1dGggY3JlZGVudGlhbHMgc2VjcmV0IGNvdWxkIG5vdCBiZSBkZWNvZGVkIGFzICd1c2VybmFtZTpwYXNzd29yZCdcIixcbiAgICApXG4gICAgdGhyb3cgbmV3IEVycm9yKClcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgYmFzaWNBdXRoSGVhZGVyOiBgQmFzaWMgJHtlbmNvZGVkQ3JlZGVudGlhbHN9YCxcbiAgICB1c2VybmFtZTogdXNlcm5hbWVBbmRQYXNzd29yZFswXSxcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gY2xlYXJDYWNoZSgpIHtcbiAgY2FjaGVkQmFzaWNBdXRoQ3JlZGVudGlhbHMgPSB1bmRlZmluZWRcbn1cbiJdfQ==
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This lambda verifies access token in Bearer authorization header using Cognito.
|
|
3
|
+
*
|
|
4
|
+
* Expects the following environment variables:
|
|
5
|
+
* - USER_POOL_ID
|
|
6
|
+
* - REQUIRED_SCOPE (optional)
|
|
7
|
+
* - Set this to require that the access token payload contains the given scope
|
|
8
|
+
* - CREDENTIALS_FOR_INTERNAL_AUTHORIZATION (optional)
|
|
9
|
+
* - Secret name from which to get basic auth credentials that should be forwarded to backend
|
|
10
|
+
* integration if authentication succeeds
|
|
11
|
+
* - Secret value should follow this format: `{"username":"<username>","password":"<password>"}`
|
|
12
|
+
*/
|
|
13
|
+
import { SecretsManager } from "@aws-sdk/client-secrets-manager";
|
|
14
|
+
import { CognitoJwtVerifier } from "aws-jwt-verify";
|
|
15
|
+
export const handler = async (event) => {
|
|
16
|
+
const authHeader = event.headers?.authorization;
|
|
17
|
+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
18
|
+
return { isAuthorized: false };
|
|
19
|
+
}
|
|
20
|
+
const result = await verifyAccessToken(authHeader.substring(7)); // substring(7) == after 'Bearer '
|
|
21
|
+
switch (result) {
|
|
22
|
+
case "INVALID":
|
|
23
|
+
return { isAuthorized: false };
|
|
24
|
+
case "EXPIRED":
|
|
25
|
+
// We want to return 401 Unauthorized for expired tokens, so the client knows to refresh
|
|
26
|
+
// their token when receiving this status code. API Gateway Lambda authorizers return
|
|
27
|
+
// 403 Forbidden for {isAuthorized: false}, but there is a way to return 401: throwing an
|
|
28
|
+
// error with this exact string. https://stackoverflow.com/a/71965890
|
|
29
|
+
throw new Error("Unauthorized");
|
|
30
|
+
default: {
|
|
31
|
+
return {
|
|
32
|
+
isAuthorized: true,
|
|
33
|
+
context: {
|
|
34
|
+
clientId: result.client_id,
|
|
35
|
+
internalAuthorizationHeader: await getInternalAuthorizationHeader(),
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
/** Decodes and verifies the given token against Cognito. */
|
|
42
|
+
async function verifyAccessToken(token) {
|
|
43
|
+
try {
|
|
44
|
+
const tokenVerifier = getTokenVerifier();
|
|
45
|
+
// Must await here instead of returning the promise directly, so that errors can be caught in
|
|
46
|
+
// this function
|
|
47
|
+
return await tokenVerifier.verify(token);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
// If the JWT has expired, aws-jwt-verify throws this error:
|
|
51
|
+
// https://github.com/awslabs/aws-jwt-verify/blob/8d8f714d7281913ecd660147f5c30311479601c1/src/jwt.ts#L197
|
|
52
|
+
// We can't check instanceof on that error class, since it's not exported, so this is the next
|
|
53
|
+
// best thing.
|
|
54
|
+
if (e instanceof Error && e.message?.includes("Token expired")) {
|
|
55
|
+
return "EXPIRED";
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
return "INVALID";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* We cache the verifier in this global variable, so that subsequent invocations of a hot lambda
|
|
64
|
+
* will re-use this.
|
|
65
|
+
*/
|
|
66
|
+
let cachedTokenVerifier = undefined;
|
|
67
|
+
function getTokenVerifier() {
|
|
68
|
+
if (cachedTokenVerifier === undefined) {
|
|
69
|
+
cachedTokenVerifier = dependencies.createTokenVerifier();
|
|
70
|
+
}
|
|
71
|
+
return cachedTokenVerifier;
|
|
72
|
+
}
|
|
73
|
+
/** For overriding dependency creation in tests. */
|
|
74
|
+
export const dependencies = {
|
|
75
|
+
createTokenVerifier: () => {
|
|
76
|
+
const userPoolId = process.env["USER_POOL_ID"];
|
|
77
|
+
if (!userPoolId) {
|
|
78
|
+
console.error("USER_POOL_ID env variable is not defined");
|
|
79
|
+
throw new Error();
|
|
80
|
+
}
|
|
81
|
+
return CognitoJwtVerifier.create({
|
|
82
|
+
userPoolId,
|
|
83
|
+
tokenUse: "access",
|
|
84
|
+
clientId: null,
|
|
85
|
+
scope: process.env.REQUIRED_SCOPE || undefined, // `|| undefined` to discard empty string
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
createSecretsManager: () => new SecretsManager(),
|
|
89
|
+
};
|
|
90
|
+
/** Cache this value, so that subsequent lambda invocations don't have to refetch. */
|
|
91
|
+
let cachedInternalAuthorizationHeader = undefined;
|
|
92
|
+
async function getInternalAuthorizationHeader() {
|
|
93
|
+
if (cachedInternalAuthorizationHeader === undefined) {
|
|
94
|
+
const secretName = process.env["CREDENTIALS_FOR_INTERNAL_AUTHORIZATION"];
|
|
95
|
+
if (!secretName) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
cachedInternalAuthorizationHeader =
|
|
99
|
+
await getSecretAsBasicAuthHeader(secretName);
|
|
100
|
+
}
|
|
101
|
+
return cachedInternalAuthorizationHeader;
|
|
102
|
+
}
|
|
103
|
+
async function getSecretAsBasicAuthHeader(secretName) {
|
|
104
|
+
const credentials = await getSecretValue(secretName);
|
|
105
|
+
if (!secretHasExpectedFormat(credentials)) {
|
|
106
|
+
console.error(`Basic auth credentials secret did not follow expected format (secret name: '${secretName}')`);
|
|
107
|
+
throw new Error();
|
|
108
|
+
}
|
|
109
|
+
return ("Basic " +
|
|
110
|
+
Buffer.from(`${credentials.username}:${credentials.password}`).toString("base64"));
|
|
111
|
+
}
|
|
112
|
+
async function getSecretValue(secretName) {
|
|
113
|
+
const client = dependencies.createSecretsManager();
|
|
114
|
+
const secret = await client.getSecretValue({ SecretId: secretName });
|
|
115
|
+
if (!secret.SecretString) {
|
|
116
|
+
console.error(`Secret value not found for '${secretName}'`);
|
|
117
|
+
throw new Error();
|
|
118
|
+
}
|
|
119
|
+
return JSON.parse(secret.SecretString);
|
|
120
|
+
}
|
|
121
|
+
function secretHasExpectedFormat(value) {
|
|
122
|
+
return (typeof value === "object" &&
|
|
123
|
+
value !== null &&
|
|
124
|
+
"username" in value &&
|
|
125
|
+
typeof value.username === "string" &&
|
|
126
|
+
"password" in value &&
|
|
127
|
+
typeof value.password === "string");
|
|
128
|
+
}
|
|
129
|
+
export function clearCache() {
|
|
130
|
+
cachedTokenVerifier = undefined;
|
|
131
|
+
cachedInternalAuthorizationHeader = undefined;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29nbml0by11c2VyLXBvb2wtYXV0aG9yaXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hcGktZ2F0ZXdheS9hdXRob3JpemVycy9jb2duaXRvLXVzZXItcG9vbC1hdXRob3JpemVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7OztHQVdHO0FBTUgsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGlDQUFpQyxDQUFBO0FBQ2hFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBNEJuRCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsS0FBSyxFQUMxQixLQUF5QyxFQUNkLEVBQUU7SUFDN0IsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUE7SUFDL0MsSUFBSSxDQUFDLFVBQVUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztRQUNyRCxPQUFPLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxDQUFBO0lBQ2hDLENBQUM7SUFFRCxNQUFNLE1BQU0sR0FBRyxNQUFNLGlCQUFpQixDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQSxDQUFDLGtDQUFrQztJQUNsRyxRQUFRLE1BQU0sRUFBRSxDQUFDO1FBQ2YsS0FBSyxTQUFTO1lBQ1osT0FBTyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsQ0FBQTtRQUNoQyxLQUFLLFNBQVM7WUFDWix3RkFBd0Y7WUFDeEYscUZBQXFGO1lBQ3JGLHlGQUF5RjtZQUN6RixxRUFBcUU7WUFDckUsTUFBTSxJQUFJLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQTtRQUNqQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1lBQ1IsT0FBTztnQkFDTCxZQUFZLEVBQUUsSUFBSTtnQkFDbEIsT0FBTyxFQUFFO29CQUNQLFFBQVEsRUFBRSxNQUFNLENBQUMsU0FBUztv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QUksV0FBVyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsUUFBUSxDQUNyRSxRQUFRLENBQ1QsQ0FDRixDQUFBO0FBQ0gsQ0FBQztBQUVELEtBQUssVUFBVSxjQUFjLENBQUMsVUFBa0I7SUFDOUMsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLG9CQUFvQixFQUFFLENBQUE7SUFDbEQsTUFBTSxNQUFNLEdBQUcsTUFBTSxNQUFNLENBQUMsY0FBYyxDQUFDLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUE7SUFFcEUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUN6QixPQUFPLENBQUMsS0FBSyxDQUFDLCtCQUErQixVQUFVLEdBQUcsQ0FBQyxDQUFBO1FBQzNELE1BQU0sSUFBSSxLQUFLLEVBQUUsQ0FBQTtJQUNuQixDQUFDO0lBRUQsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQTtBQUN4QyxDQUFDO0FBRUQsU0FBUyx1QkFBdUIsQ0FDOUIsS0FBYztJQUVkLE9BQU8sQ0FDTCxPQUFPLEtBQUssS0FBSyxRQUFRO1FBQ3pCLEtBQUssS0FBSyxJQUFJO1FBQ2QsVUFBVSxJQUFJLEtBQUs7UUFDbkIsT0FBTyxLQUFLLENBQUMsUUFBUSxLQUFLLFFBQVE7UUFDbEMsVUFBVSxJQUFJLEtBQUs7UUFDbkIsT0FBTyxLQUFLLENBQUMsUUFBUSxLQUFLLFFBQVEsQ0FDbkMsQ0FBQTtBQUNILENBQUM7QUFFRCxNQUFNLFVBQVUsVUFBVTtJQUN4QixtQkFBbUIsR0FBRyxTQUFTLENBQUE7SUFDL0IsaUNBQWlDLEdBQUcsU0FBUyxDQUFBO0FBQy9DLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRoaXMgbGFtYmRhIHZlcmlmaWVzIGFjY2VzcyB0b2tlbiBpbiBCZWFyZXIgYXV0aG9yaXphdGlvbiBoZWFkZXIgdXNpbmcgQ29nbml0by5cbiAqXG4gKiBFeHBlY3RzIHRoZSBmb2xsb3dpbmcgZW52aXJvbm1lbnQgdmFyaWFibGVzOlxuICogLSBVU0VSX1BPT0xfSURcbiAqIC0gUkVRVUlSRURfU0NPUEUgKG9wdGlvbmFsKVxuICogICAtIFNldCB0aGlzIHRvIHJlcXVpcmUgdGhhdCB0aGUgYWNjZXNzIHRva2VuIHBheWxvYWQgY29udGFpbnMgdGhlIGdpdmVuIHNjb3BlXG4gKiAtIENSRURFTlRJQUxTX0ZPUl9JTlRFUk5BTF9BVVRIT1JJWkFUSU9OIChvcHRpb25hbClcbiAqICAgLSBTZWNyZXQgbmFtZSBmcm9tIHdoaWNoIHRvIGdldCBiYXNpYyBhdXRoIGNyZWRlbnRpYWxzIHRoYXQgc2hvdWxkIGJlIGZvcndhcmRlZCB0byBiYWNrZW5kXG4gKiAgICAgaW50ZWdyYXRpb24gaWYgYXV0aGVudGljYXRpb24gc3VjY2VlZHNcbiAqICAgLSBTZWNyZXQgdmFsdWUgc2hvdWxkIGZvbGxvdyB0aGlzIGZvcm1hdDogYHtcInVzZXJuYW1lXCI6XCI8dXNlcm5hbWU+XCIsXCJwYXNzd29yZFwiOlwiPHBhc3N3b3JkPlwifWBcbiAqL1xuXG5pbXBvcnQgdHlwZSB7XG4gIEFQSUdhdGV3YXlSZXF1ZXN0QXV0aG9yaXplckV2ZW50VjIsXG4gIEFQSUdhdGV3YXlTaW1wbGVBdXRob3JpemVyUmVzdWx0LFxufSBmcm9tIFwiYXdzLWxhbWJkYVwiXG5pbXBvcnQgeyBTZWNyZXRzTWFuYWdlciB9IGZyb20gXCJAYXdzLXNkay9jbGllbnQtc2VjcmV0cy1tYW5hZ2VyXCJcbmltcG9ydCB7IENvZ25pdG9Kd3RWZXJpZmllciB9IGZyb20gXCJhd3Mtand0LXZlcmlmeVwiXG5pbXBvcnQgdHlwZSB7IENvZ25pdG9BY2Nlc3NUb2tlblBheWxvYWQgfSBmcm9tIFwiYXdzLWp3dC12ZXJpZnkvand0LW1vZGVsXCJcblxudHlwZSBBdXRob3JpemVyUmVzdWx0ID0gQVBJR2F0ZXdheVNpbXBsZUF1dGhvcml6ZXJSZXN1bHQgJiB7XG4gIC8qKlxuICAgKiBSZXR1cm5pbmcgYSBjb250ZXh0IG9iamVjdCBmcm9tIG91ciBhdXRob3JpemVyIGFsbG93cyBvdXIgQVBJIEdhdGV3YXkgdG8gYWNjZXNzIHRoZXNlIHZhcmlhYmxlc1xuICAgKiB2aWEgYCR7Y29udGV4dC5hdXRob3JpemVyLjxwcm9wZXJ0eT59YC5cbiAgICogaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2FwaWdhdGV3YXkvbGF0ZXN0L2RldmVsb3Blcmd1aWRlL2h0dHAtYXBpLXBhcmFtZXRlci1tYXBwaW5nLmh0bWxcbiAgICovXG4gIGNvbnRleHQ/OiB7XG4gICAgLyoqXG4gICAgICogSWYgdGhlIHRva2VuIGlzIHZlcmlmaWVkLCB3ZSByZXR1cm4gdGhlIGF1dGggY2xpZW50IElEIGZyb20gdGhlIHRva2VuJ3MgY2xhaW1zIGFzIGEgY29udGV4dFxuICAgICAqIHZhcmlhYmxlIChuYW1lZCBgYXV0aG9yaXplci5jbGllbnRJZGApLiBXZSB1c2UgdGhpcyB0byBpbmNsdWRlIHRoZSByZXF1ZXN0aW5nIGNsaWVudCBpbiB0aGVcbiAgICAgKiBBUEkgR2F0ZXdheSBhY2Nlc3MgbG9ncyAoc2VlIGBkZWZhdWx0QWNjZXNzTG9nRm9ybWF0YCBpbiBvdXIgYEFwaUdhdGV3YXlgIGNvbnN0cnVjdCkuIFlvdSBjYW5cbiAgICAgKiBhbHNvIHVzZSB0aGlzIHdoZW4gbWFwcGluZyBwYXJhbWV0ZXJzIHRvIHRoZSBiYWNrZW5kIGludGVncmF0aW9uIChzZWVcbiAgICAgKiBgQWxiSW50ZWdyYXRpb25Qcm9wcy5tYXBQYXJhbWV0ZXJzYCBvbiB0aGUgYEFwaUdhdGV3YXlgIGNvbnN0cnVjdCkuXG4gICAgICovXG4gICAgY2xpZW50SWQ6IHN0cmluZ1xuICAgIC8qKlxuICAgICAqIElmIGBDUkVERU5USUFMU19GT1JfSU5URVJOQUxfQVVUSE9SSVpBVElPTmAgaXMgcHJvdmlkZWQsIHdlIHdhbnQgdG8gZm9yd2FyZCBiYXNpYyBhdXRoXG4gICAgICogY3JlZGVudGlhbHMgdG8gb3VyIGJhY2tlbmQsIGFzIGFuIGFkZGl0aW9uYWwgYXV0aGVudGljYXRpb24gbGF5ZXIuIFNlZSB0aGUgZG9jc3RyaW5nIG9uXG4gICAgICogYENvZ25pdG9Vc2VyUG9vbEF1dGhvcml6ZXJQcm9wcy5iYXNpY0F1dGhGb3JJbnRlcm5hbEF1dGhvcml6YXRpb25gIGluIHRoZSBgQXBpR2F0ZXdheWBcbiAgICAgKiBjb25zdHJ1Y3QgZm9yIG1vcmUgb24gdGhpcy5cbiAgICAgKi9cbiAgICBpbnRlcm5hbEF1dGhvcml6YXRpb25IZWFkZXI/OiBzdHJpbmdcbiAgfVxufVxuXG5leHBvcnQgY29uc3QgaGFuZGxlciA9IGFzeW5jIChcbiAgZXZlbnQ6IEFQSUdhdGV3YXlSZXF1ZXN0QXV0aG9yaXplckV2ZW50VjIsXG4pOiBQcm9taXNlPEF1dGhvcml6ZXJSZXN1bHQ+ID0+IHtcbiAgY29uc3QgYXV0aEhlYWRlciA9IGV2ZW50LmhlYWRlcnM/LmF1dGhvcml6YXRpb25cbiAgaWYgKCFhdXRoSGVhZGVyIHx8ICFhdXRoSGVhZGVyLnN0YXJ0c1dpdGgoXCJCZWFyZXIgXCIpKSB7XG4gICAgcmV0dXJuIHsgaXNBdXRob3JpemVkOiBmYWxzZSB9XG4gIH1cblxuICBjb25zdCByZXN1bHQgPSBhd2FpdCB2ZXJpZnlBY2Nlc3NUb2tlbihhdXRoSGVhZGVyLnN1YnN0cmluZyg3KSkgLy8gc3Vic3RyaW5nKDcpID09IGFmdGVyICdCZWFyZXIgJ1xuICBzd2l0Y2ggKHJlc3VsdCkge1xuICAgIGNhc2UgXCJJTlZBTElEXCI6XG4gICAgICByZXR1cm4geyBpc0F1dGhvcml6ZWQ6IGZhbHNlIH1cbiAgICBjYXNlIFwiRVhQSVJFRFwiOlxuICAgICAgLy8gV2Ugd2FudCB0byByZXR1cm4gNDAxIFVuYXV0aG9yaXplZCBmb3IgZXhwaXJlZCB0b2tlbnMsIHNvIHRoZSBjbGllbnQga25vd3MgdG8gcmVmcmVzaFxuICAgICAgLy8gdGhlaXIgdG9rZW4gd2hlbiByZWNlaXZpbmcgdGhpcyBzdGF0dXMgY29kZS4gQVBJIEdhdGV3YXkgTGFtYmRhIGF1dGhvcml6ZXJzIHJldHVyblxuICAgICAgLy8gNDAzIEZvcmJpZGRlbiBmb3Ige2lzQXV0aG9yaXplZDogZmFsc2V9LCBidXQgdGhlcmUgaXMgYSB3YXkgdG8gcmV0dXJuIDQwMTogdGhyb3dpbmcgYW5cbiAgICAgIC8vIGVycm9yIHdpdGggdGhpcyBleGFjdCBzdHJpbmcuIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS83MTk2NTg5MFxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVW5hdXRob3JpemVkXCIpXG4gICAgZGVmYXVsdDoge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgaXNBdXRob3JpemVkOiB0cnVlLFxuICAgICAgICBjb250ZXh0OiB7XG4gICAgICAgICAgY2xpZW50SWQ6IHJlc3VsdC5jbGllbnRfaWQsXG4gICAgICAgICAgaW50ZXJuYWxBdXRob3JpemF0aW9uSGVhZGVyOiBhd2FpdCBnZXRJbnRlcm5hbEF1dGhvcml6YXRpb25IZWFkZXIoKSxcbiAgICAgICAgfSxcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuLyoqIERlY29kZXMgYW5kIHZlcmlmaWVzIHRoZSBnaXZlbiB0b2tlbiBhZ2FpbnN0IENvZ25pdG8uICovXG5hc3luYyBmdW5jdGlvbiB2ZXJpZnlBY2Nlc3NUb2tlbihcbiAgdG9rZW46IHN0cmluZyxcbik6IFByb21pc2U8Q29nbml0b0FjY2Vzc1Rva2VuUGF5bG9hZCB8IFwiRVhQSVJFRFwiIHwgXCJJTlZBTElEXCI+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCB0b2tlblZlcmlmaWVyID0gZ2V0VG9rZW5WZXJpZmllcigpXG4gICAgLy8gTXVzdCBhd2FpdCBoZXJlIGluc3RlYWQgb2YgcmV0dXJuaW5nIHRoZSBwcm9taXNlIGRpcmVjdGx5LCBzbyB0aGF0IGVycm9ycyBjYW4gYmUgY2F1Z2h0IGluXG4gICAgLy8gdGhpcyBmdW5jdGlvblxuICAgIHJldHVybiBhd2FpdCB0b2tlblZlcmlmaWVyLnZlcmlmeSh0b2tlbilcbiAgfSBjYXRjaCAoZSkge1xuICAgIC8vIElmIHRoZSBKV1QgaGFzIGV4cGlyZWQsIGF3cy1qd3QtdmVyaWZ5IHRocm93cyB0aGlzIGVycm9yOlxuICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9hd3NsYWJzL2F3cy1qd3QtdmVyaWZ5L2Jsb2IvOGQ4ZjcxNGQ3MjgxOTEzZWNkNjYwMTQ3ZjVjMzAzMTE0Nzk2MDFjMS9zcmMvand0LnRzI0wxOTdcbiAgICAvLyBXZSBjYW4ndCBjaGVjayBpbnN0YW5jZW9mIG9uIHRoYXQgZXJyb3IgY2xhc3MsIHNpbmNlIGl0J3Mgbm90IGV4cG9ydGVkLCBzbyB0aGlzIGlzIHRoZSBuZXh0XG4gICAgLy8gYmVzdCB0aGluZy5cbiAgICBpZiAoZSBpbnN0YW5jZW9mIEVycm9yICYmIGUubWVzc2FnZT8uaW5jbHVkZXMoXCJUb2tlbiBleHBpcmVkXCIpKSB7XG4gICAgICByZXR1cm4gXCJFWFBJUkVEXCJcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIFwiSU5WQUxJRFwiXG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCB0eXBlIFRva2VuVmVyaWZpZXIgPSB7XG4gIHZlcmlmeTogKGFjY2Vzc1Rva2VuOiBzdHJpbmcpID0+IFByb21pc2U8Q29nbml0b0FjY2Vzc1Rva2VuUGF5bG9hZD5cbn1cblxuLyoqXG4gKiBXZSBjYWNoZSB0aGUgdmVyaWZpZXIgaW4gdGhpcyBnbG9iYWwgdmFyaWFibGUsIHNvIHRoYXQgc3Vic2VxdWVudCBpbnZvY2F0aW9ucyBvZiBhIGhvdCBsYW1iZGFcbiAqIHdpbGwgcmUtdXNlIHRoaXMuXG4gKi9cbmxldCBjYWNoZWRUb2tlblZlcmlmaWVyOiBUb2tlblZlcmlmaWVyIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkXG5cbmZ1bmN0aW9uIGdldFRva2VuVmVyaWZpZXIoKTogVG9rZW5WZXJpZmllciB7XG4gIGlmIChjYWNoZWRUb2tlblZlcmlmaWVyID09PSB1bmRlZmluZWQpIHtcbiAgICBjYWNoZWRUb2tlblZlcmlmaWVyID0gZGVwZW5kZW5jaWVzLmNyZWF0ZVRva2VuVmVyaWZpZXIoKVxuICB9XG4gIHJldHVybiBjYWNoZWRUb2tlblZlcmlmaWVyXG59XG5cbi8qKiBGb3Igb3ZlcnJpZGluZyBkZXBlbmRlbmN5IGNyZWF0aW9uIGluIHRlc3RzLiAqL1xuZXhwb3J0IGNvbnN0IGRlcGVuZGVuY2llcyA9IHtcbiAgY3JlYXRlVG9rZW5WZXJpZmllcjogKCk6IFRva2VuVmVyaWZpZXIgPT4ge1xuICAgIGNvbnN0IHVzZXJQb29sSWQgPSBwcm9jZXNzLmVudltcIlVTRVJfUE9PTF9JRFwiXVxuICAgIGlmICghdXNlclBvb2xJZCkge1xuICAgICAgY29uc29sZS5lcnJvcihcIlVTRVJfUE9PTF9JRCBlbnYgdmFyaWFibGUgaXMgbm90IGRlZmluZWRcIilcbiAgICAgIHRocm93IG5ldyBFcnJvcigpXG4gICAgfVxuXG4gICAgcmV0dXJuIENvZ25pdG9Kd3RWZXJpZmllci5jcmVhdGUoe1xuICAgICAgdXNlclBvb2xJZCxcbiAgICAgIHRva2VuVXNlOiBcImFjY2Vzc1wiLFxuICAgICAgY2xpZW50SWQ6IG51bGwsXG4gICAgICBzY29wZTogcHJvY2Vzcy5lbnYuUkVRVUlSRURfU0NPUEUgfHwgdW5kZWZpbmVkLCAvLyBgfHwgdW5kZWZpbmVkYCB0byBkaXNjYXJkIGVtcHR5IHN0cmluZ1xuICAgIH0pXG4gIH0sXG4gIGNyZWF0ZVNlY3JldHNNYW5hZ2VyOiAoKSA9PiBuZXcgU2VjcmV0c01hbmFnZXIoKSxcbn1cblxuLyoqIENhY2hlIHRoaXMgdmFsdWUsIHNvIHRoYXQgc3Vic2VxdWVudCBsYW1iZGEgaW52b2NhdGlvbnMgZG9uJ3QgaGF2ZSB0byByZWZldGNoLiAqL1xubGV0IGNhY2hlZEludGVybmFsQXV0aG9yaXphdGlvbkhlYWRlcjogc3RyaW5nIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkXG5cbmFzeW5jIGZ1bmN0aW9uIGdldEludGVybmFsQXV0aG9yaXphdGlvbkhlYWRlcigpOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICBpZiAoY2FjaGVkSW50ZXJuYWxBdXRob3JpemF0aW9uSGVhZGVyID09PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBzZWNyZXROYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQgPVxuICAgICAgcHJvY2Vzcy5lbnZbXCJDUkVERU5USUFMU19GT1JfSU5URVJOQUxfQVVUSE9SSVpBVElPTlwiXVxuICAgIGlmICghc2VjcmV0TmFtZSkge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgIH1cblxuICAgIGNhY2hlZEludGVybmFsQXV0aG9yaXphdGlvbkhlYWRlciA9XG4gICAgICBhd2FpdCBnZXRTZWNyZXRBc0Jhc2ljQXV0aEhlYWRlcihzZWNyZXROYW1lKVxuICB9XG5cbiAgcmV0dXJuIGNhY2hlZEludGVybmFsQXV0aG9yaXphdGlvbkhlYWRlclxufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRTZWNyZXRBc0Jhc2ljQXV0aEhlYWRlcihzZWNyZXROYW1lOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCBjcmVkZW50aWFscyA9IGF3YWl0IGdldFNlY3JldFZhbHVlKHNlY3JldE5hbWUpXG4gIGlmICghc2VjcmV0SGFzRXhwZWN0ZWRGb3JtYXQoY3JlZGVudGlhbHMpKSB7XG4gICAgY29uc29sZS5lcnJvcihcbiAgICAgIGBCYXNpYyBhdXRoIGNyZWRlbnRpYWxzIHNlY3JldCBkaWQgbm90IGZvbGxvdyBleHBlY3RlZCBmb3JtYXQgKHNlY3JldCBuYW1lOiAnJHtzZWNyZXROYW1lfScpYCxcbiAgICApXG4gICAgdGhyb3cgbmV3IEVycm9yKClcbiAgfVxuXG4gIHJldHVybiAoXG4gICAgXCJCYXNpYyBcIiArXG4gICAgQnVmZmVyLmZyb20oYCR7Y3JlZGVudGlhbHMudXNlcm5hbWV9OiR7Y3JlZGVudGlhbHMucGFzc3dvcmR9YCkudG9TdHJpbmcoXG4gICAgICBcImJhc2U2NFwiLFxuICAgIClcbiAgKVxufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRTZWNyZXRWYWx1ZShzZWNyZXROYW1lOiBzdHJpbmcpOiBQcm9taXNlPHVua25vd24+IHtcbiAgY29uc3QgY2xpZW50ID0gZGVwZW5kZW5jaWVzLmNyZWF0ZVNlY3JldHNNYW5hZ2VyKClcbiAgY29uc3Qgc2VjcmV0ID0gYXdhaXQgY2xpZW50LmdldFNlY3JldFZhbHVlKHsgU2VjcmV0SWQ6IHNlY3JldE5hbWUgfSlcblxuICBpZiAoIXNlY3JldC5TZWNyZXRTdHJpbmcpIHtcbiAgICBjb25zb2xlLmVycm9yKGBTZWNyZXQgdmFsdWUgbm90IGZvdW5kIGZvciAnJHtzZWNyZXROYW1lfSdgKVxuICAgIHRocm93IG5ldyBFcnJvcigpXG4gIH1cblxuICByZXR1cm4gSlNPTi5wYXJzZShzZWNyZXQuU2VjcmV0U3RyaW5nKVxufVxuXG5mdW5jdGlvbiBzZWNyZXRIYXNFeHBlY3RlZEZvcm1hdChcbiAgdmFsdWU6IHVua25vd24sXG4pOiB2YWx1ZSBpcyB7IHVzZXJuYW1lOiBzdHJpbmc7IHBhc3N3b3JkOiBzdHJpbmcgfSB7XG4gIHJldHVybiAoXG4gICAgdHlwZW9mIHZhbHVlID09PSBcIm9iamVjdFwiICYmXG4gICAgdmFsdWUgIT09IG51bGwgJiZcbiAgICBcInVzZXJuYW1lXCIgaW4gdmFsdWUgJiZcbiAgICB0eXBlb2YgdmFsdWUudXNlcm5hbWUgPT09IFwic3RyaW5nXCIgJiZcbiAgICBcInBhc3N3b3JkXCIgaW4gdmFsdWUgJiZcbiAgICB0eXBlb2YgdmFsdWUucGFzc3dvcmQgPT09IFwic3RyaW5nXCJcbiAgKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gY2xlYXJDYWNoZSgpIHtcbiAgY2FjaGVkVG9rZW5WZXJpZmllciA9IHVuZGVmaW5lZFxuICBjYWNoZWRJbnRlcm5hbEF1dGhvcml6YXRpb25IZWFkZXIgPSB1bmRlZmluZWRcbn1cbiJdfQ==
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This lambda verifies credentials:
|
|
3
|
+
* - Against Cognito user pool if request uses access token in Bearer authorization header
|
|
4
|
+
* - Against credentials saved in Secret Manager if request uses basic auth (and if secret exists)
|
|
5
|
+
*
|
|
6
|
+
* Expects the following environment variables:
|
|
7
|
+
* - USER_POOL_ID
|
|
8
|
+
* - BASIC_AUTH_CREDENTIALS_SECRET_NAME (optional)
|
|
9
|
+
* - Name of secret in AWS Secrets Manager that stores basic auth credentials. See
|
|
10
|
+
* `BasicAuthAuthorizerProps` on the `ApiGateway` construct for the supported formats.
|
|
11
|
+
* - REQUIRED_SCOPE (optional)
|
|
12
|
+
* - Set this to require that the access token payload contains the given scope
|
|
13
|
+
*/
|
|
14
|
+
import { SecretsManager } from "@aws-sdk/client-secrets-manager";
|
|
15
|
+
import { CognitoJwtVerifier } from "aws-jwt-verify";
|
|
16
|
+
export const handler = async (event) => {
|
|
17
|
+
const authHeader = event.headers?.authorization;
|
|
18
|
+
if (!authHeader) {
|
|
19
|
+
return { isAuthorized: false };
|
|
20
|
+
}
|
|
21
|
+
const expectedBasicAuthCredentials = await getExpectedBasicAuthCredentials();
|
|
22
|
+
if (authHeader.startsWith("Bearer ")) {
|
|
23
|
+
const result = await verifyAccessToken(authHeader.substring(7)); // substring(7) == after 'Bearer '
|
|
24
|
+
switch (result) {
|
|
25
|
+
case "INVALID":
|
|
26
|
+
return { isAuthorized: false };
|
|
27
|
+
case "EXPIRED":
|
|
28
|
+
// We want to return 401 Unauthorized for expired tokens, so the client knows to refresh
|
|
29
|
+
// their token when receiving this status code. API Gateway Lambda Authorizers return
|
|
30
|
+
// 403 Forbidden for {isAuthorized: false}, but there is a way to return 401: throwing an
|
|
31
|
+
// error with this exact string. https://stackoverflow.com/a/71965890
|
|
32
|
+
throw new Error("Unauthorized");
|
|
33
|
+
default:
|
|
34
|
+
return {
|
|
35
|
+
isAuthorized: true,
|
|
36
|
+
context: {
|
|
37
|
+
clientId: result.client_id,
|
|
38
|
+
internalAuthorizationHeader: expectedBasicAuthCredentials?.[0]?.basicAuthHeader,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else if (authHeader.startsWith("Basic ") &&
|
|
44
|
+
expectedBasicAuthCredentials !== undefined) {
|
|
45
|
+
for (const expected of expectedBasicAuthCredentials) {
|
|
46
|
+
if (authHeader === expected.basicAuthHeader) {
|
|
47
|
+
return {
|
|
48
|
+
isAuthorized: true,
|
|
49
|
+
context: {
|
|
50
|
+
username: expected.username,
|
|
51
|
+
internalAuthorizationHeader: expected.basicAuthHeader,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { isAuthorized: false };
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
return { isAuthorized: false };
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
/** Decodes and verifies the given token against Cognito. */
|
|
63
|
+
async function verifyAccessToken(token) {
|
|
64
|
+
try {
|
|
65
|
+
const tokenVerifier = getTokenVerifier();
|
|
66
|
+
// Must await here instead of returning the promise directly, so that errors can be caught in
|
|
67
|
+
// this function
|
|
68
|
+
return await tokenVerifier.verify(token);
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
// If the JWT has expired, aws-jwt-verify throws this error:
|
|
72
|
+
// https://github.com/awslabs/aws-jwt-verify/blob/8d8f714d7281913ecd660147f5c30311479601c1/src/jwt.ts#L197
|
|
73
|
+
// We can't check instanceof on that error class, since it's not exported, so this is the next
|
|
74
|
+
// best thing.
|
|
75
|
+
if (e instanceof Error && e.message?.includes("Token expired")) {
|
|
76
|
+
return "EXPIRED";
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
return "INVALID";
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* We cache the verifier in this global variable, so that subsequent invocations of a hot lambda
|
|
85
|
+
* will re-use this.
|
|
86
|
+
*/
|
|
87
|
+
let cachedTokenVerifier = undefined;
|
|
88
|
+
function getTokenVerifier() {
|
|
89
|
+
if (cachedTokenVerifier === undefined) {
|
|
90
|
+
cachedTokenVerifier = dependencies.createTokenVerifier();
|
|
91
|
+
}
|
|
92
|
+
return cachedTokenVerifier;
|
|
93
|
+
}
|
|
94
|
+
/** For overriding dependency creation in tests. */
|
|
95
|
+
export const dependencies = {
|
|
96
|
+
createTokenVerifier: () => {
|
|
97
|
+
const userPoolId = process.env["USER_POOL_ID"];
|
|
98
|
+
if (!userPoolId) {
|
|
99
|
+
console.error("USER_POOL_ID env variable is not defined");
|
|
100
|
+
throw new Error();
|
|
101
|
+
}
|
|
102
|
+
return CognitoJwtVerifier.create({
|
|
103
|
+
userPoolId,
|
|
104
|
+
tokenUse: "access",
|
|
105
|
+
clientId: null,
|
|
106
|
+
scope: process.env.REQUIRED_SCOPE || undefined, // `|| undefined` to discard empty string
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
createSecretsManager: () => new SecretsManager(),
|
|
110
|
+
};
|
|
111
|
+
/** Cache this value, so that subsequent lambda invocations don't have to refetch. */
|
|
112
|
+
let cachedBasicAuthCredentials = undefined;
|
|
113
|
+
/**
|
|
114
|
+
* Returns an array, to support credential secrets with multiple values (see
|
|
115
|
+
* `BasicAuthAuthorizerProps` on the `ApiGateway` construct for more on this).
|
|
116
|
+
*/
|
|
117
|
+
async function getExpectedBasicAuthCredentials() {
|
|
118
|
+
if (cachedBasicAuthCredentials === undefined) {
|
|
119
|
+
const secretName = process.env["BASIC_AUTH_CREDENTIALS_SECRET_NAME"];
|
|
120
|
+
if (!secretName) {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
cachedBasicAuthCredentials = await getBasicAuthCredentialsSecret(secretName);
|
|
124
|
+
}
|
|
125
|
+
return cachedBasicAuthCredentials;
|
|
126
|
+
}
|
|
127
|
+
async function getBasicAuthCredentialsSecret(secretName) {
|
|
128
|
+
const secret = await getSecretValue(secretName);
|
|
129
|
+
if (isUsernameAndPasswordObject(secret)) {
|
|
130
|
+
return [encodeBasicAuthCredentials(secret)];
|
|
131
|
+
}
|
|
132
|
+
// See `BasicAuthAuthorizerProps` on the `ApiGateway` construct for an explanation of the formats
|
|
133
|
+
// we parse here
|
|
134
|
+
if (hasCredentialsKeyWithStringValue(secret)) {
|
|
135
|
+
let credentialsArray;
|
|
136
|
+
try {
|
|
137
|
+
credentialsArray = JSON.parse(secret.credentials);
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
console.error(`Failed to parse credentials array in secret '${secretName}' as JSON`, e);
|
|
141
|
+
throw new Error();
|
|
142
|
+
}
|
|
143
|
+
if (isArrayOfUsernameAndPasswordObjects(credentialsArray)) {
|
|
144
|
+
return credentialsArray.map(encodeBasicAuthCredentials);
|
|
145
|
+
}
|
|
146
|
+
if (isStringArray(credentialsArray)) {
|
|
147
|
+
return credentialsArray.map(parseEncodedBasicAuthCredentials);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
console.error(`Basic auth credentials secret did not follow any expected format (secret name: '${secretName}')`);
|
|
151
|
+
throw new Error();
|
|
152
|
+
}
|
|
153
|
+
async function getSecretValue(secretName) {
|
|
154
|
+
const client = dependencies.createSecretsManager();
|
|
155
|
+
const secret = await client.getSecretValue({ SecretId: secretName });
|
|
156
|
+
if (!secret.SecretString) {
|
|
157
|
+
console.error(`Secret value not found for '${secretName}'`);
|
|
158
|
+
throw new Error();
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
return JSON.parse(secret.SecretString);
|
|
162
|
+
}
|
|
163
|
+
catch (e) {
|
|
164
|
+
console.error(`Failed to parse secret '${secretName}' as JSON:`, e);
|
|
165
|
+
throw new Error();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function encodeBasicAuthCredentials(credentials) {
|
|
169
|
+
const basicAuthHeader = "Basic " +
|
|
170
|
+
Buffer.from(`${credentials.username}:${credentials.password}`).toString("base64");
|
|
171
|
+
return { basicAuthHeader, username: credentials.username };
|
|
172
|
+
}
|
|
173
|
+
function isUsernameAndPasswordObject(value) {
|
|
174
|
+
return (typeof value === "object" &&
|
|
175
|
+
value !== null &&
|
|
176
|
+
"username" in value &&
|
|
177
|
+
typeof value.username === "string" &&
|
|
178
|
+
"password" in value &&
|
|
179
|
+
typeof value.password === "string");
|
|
180
|
+
}
|
|
181
|
+
function isArrayOfUsernameAndPasswordObjects(value) {
|
|
182
|
+
if (!Array.isArray(value)) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
for (const element of value) {
|
|
186
|
+
if (!isUsernameAndPasswordObject(element)) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
function hasCredentialsKeyWithStringValue(value) {
|
|
193
|
+
return (typeof value === "object" &&
|
|
194
|
+
value !== null &&
|
|
195
|
+
"credentials" in value &&
|
|
196
|
+
typeof value.credentials === "string");
|
|
197
|
+
}
|
|
198
|
+
function isStringArray(value) {
|
|
199
|
+
if (!Array.isArray(value)) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
for (const element of value) {
|
|
203
|
+
if (typeof element !== "string") {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* We want to return the requesting username as a context variable in
|
|
211
|
+
* {@link AuthorizerResult.context}, for API Gateway access logs and parameter mapping. So if the
|
|
212
|
+
* basic auth credentials secret is stored as pre-encoded base64 strings, we need to parse them to
|
|
213
|
+
* get the username.
|
|
214
|
+
*/
|
|
215
|
+
function parseEncodedBasicAuthCredentials(encodedCredentials) {
|
|
216
|
+
let decodedCredentials;
|
|
217
|
+
try {
|
|
218
|
+
decodedCredentials = Buffer.from(encodedCredentials, "base64").toString();
|
|
219
|
+
}
|
|
220
|
+
catch (e) {
|
|
221
|
+
console.error("Basic auth credentials secret could not be decoded as base64:", e);
|
|
222
|
+
throw new Error();
|
|
223
|
+
}
|
|
224
|
+
const usernameAndPassword = decodedCredentials.split(":", 2);
|
|
225
|
+
if (usernameAndPassword.length !== 2) {
|
|
226
|
+
console.error("Basic auth credentials secret could not be decoded as 'username:password'");
|
|
227
|
+
throw new Error();
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
basicAuthHeader: `Basic ${encodedCredentials}`,
|
|
231
|
+
username: usernameAndPassword[0],
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
export function clearCache() {
|
|
235
|
+
cachedTokenVerifier = undefined;
|
|
236
|
+
cachedBasicAuthCredentials = undefined;
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29nbml0by11c2VyLXBvb2wtb3ItYmFzaWMtYXV0aC1hdXRob3JpemVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwaS1nYXRld2F5L2F1dGhvcml6ZXJzL2NvZ25pdG8tdXNlci1wb29sLW9yLWJhc2ljLWF1dGgtYXV0aG9yaXplci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7O0dBWUc7QUFNSCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUNBQWlDLENBQUE7QUFDaEUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFtQ25ELE1BQU0sQ0FBQyxNQUFNLE9BQU8sR0FBRyxLQUFLLEVBQzFCLEtBQXlDLEVBQ2QsRUFBRTtJQUM3QixNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsT0FBTyxFQUFFLGFBQWEsQ0FBQTtJQUMvQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDaEIsT0FBTyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsQ0FBQTtJQUNoQyxDQUFDO0lBRUQsTUFBTSw0QkFBNEIsR0FBRyxNQUFNLCtCQUErQixFQUFFLENBQUE7SUFFNUUsSUFBSSxVQUFVLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDckMsTUFBTSxNQUFNLEdBQUcsTUFBTSxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUEsQ0FBQyxrQ0FBa0M7UUFDbEcsUUFBUSxNQUFNLEVBQUUsQ0FBQztZQUNmLEtBQUssU0FBUztnQkFDWixPQUFPLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxDQUFBO1lBQ2hDLEtBQUssU0FBUztnQkFDWix3RkFBd0Y7Z0JBQ3hGLHFGQUFxRjtnQkFDckYseUZBQXlGO2dCQUN6RixxRUFBcUU7Z0JBQ3JFLE1BQU0sSUFBSSxLQUFLLENBQUMsY0FBYyxDQUFDLENBQUE7WUFDakM7Z0JBQ0UsT0FB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Q2IsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBUyxnQ0FBZ0MsQ0FDdkMsa0JBQTBCO0lBRTFCLElBQUksa0JBQTBCLENBQUE7SUFDOUIsSUFBSSxDQUFDO1FBQ0gsa0JBQWtCLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxRQUFRLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQTtJQUMzRSxDQUFDO0lBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUNYLE9BQU8sQ0FBQyxLQUFLLENBQ1gsK0RBQStELEVBQy9ELENBQUMsQ0FDRixDQUFBO1FBQ0QsTUFBTSxJQUFJLEtBQUssRUFBRSxDQUFBO0lBQ25CLENBQUM7SUFFRCxNQUFNLG1CQUFtQixHQUFHLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUE7SUFDNUQsSUFBSSxtQkFBbUIsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDckMsT0FBTyxDQUFDLEtBQUssQ0FDWCwyRUFBMkUsQ0FDNUUsQ0FBQTtRQUNELE1BQU0sSUFBSSxLQUFLLEVBQUUsQ0FBQTtJQUNuQixDQUFDO0lBRUQsT0FBTztRQUNMLGVBQWUsRUFBRSxTQUFTLGtCQUFrQixFQUFFO1FBQzlDLFFBQVEsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDLENBQUM7S0FDakMsQ0FBQTtBQUNILENBQUM7QUFFRCxNQUFNLFVBQVUsVUFBVTtJQUN4QixtQkFBbUIsR0FBRyxTQUFTLENBQUE7SUFDL0IsMEJBQTBCLEdBQUcsU0FBUyxDQUFBO0FBQ3hDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRoaXMgbGFtYmRhIHZlcmlmaWVzIGNyZWRlbnRpYWxzOlxuICogLSBBZ2FpbnN0IENvZ25pdG8gdXNlciBwb29sIGlmIHJlcXVlc3QgdXNlcyBhY2Nlc3MgdG9rZW4gaW4gQmVhcmVyIGF1dGhvcml6YXRpb24gaGVhZGVyXG4gKiAtIEFnYWluc3QgY3JlZGVudGlhbHMgc2F2ZWQgaW4gU2VjcmV0IE1hbmFnZXIgaWYgcmVxdWVzdCB1c2VzIGJhc2ljIGF1dGggKGFuZCBpZiBzZWNyZXQgZXhpc3RzKVxuICpcbiAqIEV4cGVjdHMgdGhlIGZvbGxvd2luZyBlbnZpcm9ubWVudCB2YXJpYWJsZXM6XG4gKiAtIFVTRVJfUE9PTF9JRFxuICogLSBCQVNJQ19BVVRIX0NSRURFTlRJQUxTX1NFQ1JFVF9OQU1FIChvcHRpb25hbClcbiAqICAgLSBOYW1lIG9mIHNlY3JldCBpbiBBV1MgU2VjcmV0cyBNYW5hZ2VyIHRoYXQgc3RvcmVzIGJhc2ljIGF1dGggY3JlZGVudGlhbHMuIFNlZVxuICogICAgIGBCYXNpY0F1dGhBdXRob3JpemVyUHJvcHNgIG9uIHRoZSBgQXBpR2F0ZXdheWAgY29uc3RydWN0IGZvciB0aGUgc3VwcG9ydGVkIGZvcm1hdHMuXG4gKiAtIFJFUVVJUkVEX1NDT1BFIChvcHRpb25hbClcbiAqICAgLSBTZXQgdGhpcyB0byByZXF1aXJlIHRoYXQgdGhlIGFjY2VzcyB0b2tlbiBwYXlsb2FkIGNvbnRhaW5zIHRoZSBnaXZlbiBzY29wZVxuICovXG5cbmltcG9ydCB0eXBlIHtcbiAgQVBJR2F0ZXdheVJlcXVlc3RBdXRob3JpemVyRXZlbnRWMixcbiAgQVBJR2F0ZXdheVNpbXBsZUF1dGhvcml6ZXJSZXN1bHQsXG59IGZyb20gXCJhd3MtbGFtYmRhXCJcbmltcG9ydCB7IFNlY3JldHNNYW5hZ2VyIH0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1zZWNyZXRzLW1hbmFnZXJcIlxuaW1wb3J0IHsgQ29nbml0b0p3dFZlcmlmaWVyIH0gZnJvbSBcImF3cy1qd3QtdmVyaWZ5XCJcbmltcG9ydCB0eXBlIHsgQ29nbml0b0FjY2Vzc1Rva2VuUGF5bG9hZCB9IGZyb20gXCJhd3Mtand0LXZlcmlmeS9qd3QtbW9kZWxcIlxuXG50eXBlIEF1dGhvcml6ZXJSZXN1bHQgPSBBUElHYXRld2F5U2ltcGxlQXV0aG9yaXplclJlc3VsdCAmIHtcbiAgLyoqXG4gICAqIFJldHVybmluZyBhIGNvbnRleHQgb2JqZWN0IGZyb20gb3VyIGF1dGhvcml6ZXIgYWxsb3dzIG91ciBBUEkgR2F0ZXdheSB0byBhY2Nlc3MgdGhlc2UgdmFyaWFibGVzXG4gICAqIHZpYSBgJHtjb250ZXh0LmF1dGhvcml6ZXIuPHByb3BlcnR5Pn1gLlxuICAgKiBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vYXBpZ2F0ZXdheS9sYXRlc3QvZGV2ZWxvcGVyZ3VpZGUvaHR0cC1hcGktcGFyYW1ldGVyLW1hcHBpbmcuaHRtbFxuICAgKi9cbiAgY29udGV4dD86IHtcbiAgICAvKipcbiAgICAgKiBJZiB0aGUgcmVxdWVzdCB1c2VkIGFuIGFjY2VzcyB0b2tlbiwgYW5kIHRoZSB0b2tlbiB3YXMgdmVyaWZpZWQsIHdlIHJldHVybiB0aGUgYXV0aCBjbGllbnQgSURcbiAgICAgKiBmcm9tIHRoZSB0b2tlbidzIGNsYWltcyBpbiB0aGlzIGNvbnRleHQgdmFyaWFibGUgKG5hbWVkIGBhdXRob3JpemVyLmNsaWVudElkYCkuIFdlIHVzZSB0aGlzXG4gICAgICogdG8gaW5jbHVkZSB0aGUgcmVxdWVzdGluZyBjbGllbnQgaW4gdGhlIEFQSSBHYXRld2F5IGFjY2VzcyBsb2dzIChzZWUgYGRlZmF1bHRBY2Nlc3NMb2dGb3JtYXRgXG4gICAgICogaW4gb3VyIGBBcGlHYXRld2F5YCBjb25zdHJ1Y3QpLiBZb3UgY2FuIGFsc28gdXNlIHRoaXMgd2hlbiBtYXBwaW5nIHBhcmFtZXRlcnMgdG8gdGhlIGJhY2tlbmRcbiAgICAgKiBpbnRlZ3JhdGlvbiAoc2VlIGBBbGJJbnRlZ3JhdGlvblByb3BzLm1hcFBhcmFtZXRlcnNgIG9uIHRoZSBgQXBpR2F0ZXdheWAgY29uc3RydWN0KS5cbiAgICAgKi9cbiAgICBjbGllbnRJZD86IHN0cmluZ1xuICAgIC8qKlxuICAgICAqIElmIHRoZSByZXF1ZXN0IHVzZWQgQmFzaWMgQXV0aCwgYW5kIHRoZSBjcmVkZW50aWFscyB3ZXJlIHZlcmlmaWVkLCB3ZSByZXR1cm4gdGhlIHVzZXJuYW1lXG4gICAgICogdGhhdCB3YXMgdXNlZCBpbiB0aGlzIGNvbnRleHQgdmFyaWFibGUgKG5hbWVkIGBhdXRob3JpemVyLnVzZXJuYW1lYCkuIFdlIHVzZSB0aGlzIHRvIGluY2x1ZGVcbiAgICAgKiB0aGUgcmVxdWVzdGluZyB1c2VyIGluIHRoZSBBUEkgR2F0ZXdheSBhY2Nlc3MgbG9ncyAoc2VlIGBkZWZhdWx0QWNjZXNzTG9nRm9ybWF0YCBpbiBvdXJcbiAgICAgKiBgQXBpR2F0ZXdheWAgY29uc3RydWN0KS4gWW91IGNhbiBhbHNvIHVzZSB0aGlzIHdoZW4gbWFwcGluZyBwYXJhbWV0ZXJzIHRvIHRoZSBiYWNrZW5kXG4gICAgICogaW50ZWdyYXRpb24gKHNlZSBgQWxiSW50ZWdyYXRpb25Qcm9wcy5tYXBQYXJhbWV0ZXJzYCBvbiB0aGUgYEFwaUdhdGV3YXlgIGNvbnN0cnVjdCkuXG4gICAgICovXG4gICAgdXNlcm5hbWU/OiBzdHJpbmdcbiAgICAvKipcbiAgICAgKiBTZWUgYENvZ25pdG9Vc2VyUG9vbEF1dGhvcml6ZXJQcm9wcy5iYXNpY0F1dGhGb3JJbnRlcm5hbEF1dGhvcml6YXRpb25gIG9uIHRoZSBgQXBpR2F0ZXdheWBcbiAgICAgKiBjb25zdHJ1Y3QgKHdlIHByb3ZpZGUgdGhlIHNhbWUgY29udGV4dCB2YXJpYWJsZSBoZXJlIGFzIGluIHRoZSBDb2duaXRvIFVzZXIgUG9vbCBhdXRob3JpemVyLFxuICAgICAqIHVzaW5nIHRoZSBjcmVkZW50aWFscyBmcm9tIEJBU0lDX0FVVEhfQ1JFREVOVElBTFNfU0VDUkVUX05BTUUpLlxuICAgICAqL1xuICAgIGludGVybmFsQXV0aG9yaXphdGlvbkhlYWRlcj86IHN0cmluZ1xuICB9XG59XG5cbmV4cG9ydCBjb25zdCBoYW5kbGVyID0gYXN5bmMgKFxuICBldmVudDogQVBJR2F0ZXdheVJlcXVlc3RBdXRob3JpemVyRXZlbnRWMixcbik6IFByb21pc2U8QXV0aG9yaXplclJlc3VsdD4gPT4ge1xuICBjb25zdCBhdXRoSGVhZGVyID0gZXZlbnQuaGVhZGVycz8uYXV0aG9yaXphdGlvblxuICBpZiAoIWF1dGhIZWFkZXIpIHtcbiAgICByZXR1cm4geyBpc0F1dGhvcml6ZWQ6IGZhbHNlIH1cbiAgfVxuXG4gIGNvbnN0IGV4cGVjdGVkQmFzaWNBdXRoQ3JlZGVudGlhbHMgPSBhd2FpdCBnZXRFeHBlY3RlZEJhc2ljQXV0aENyZWRlbnRpYWxzKClcblxuICBpZiAoYXV0aEhlYWRlci5zdGFydHNXaXRoKFwiQmVhcmVyIFwiKSkge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHZlcmlmeUFjY2Vzc1Rva2VuKGF1dGhIZWFkZXIuc3Vic3RyaW5nKDcpKSAvLyBzdWJzdHJpbmcoNykgPT0gYWZ0ZXIgJ0JlYXJlciAnXG4gICAgc3dpdGNoIChyZXN1bHQpIHtcbiAgICAgIGNhc2UgXCJJTlZBTElEXCI6XG4gICAgICAgIHJldHVybiB7IGlzQXV0aG9yaXplZDogZmFsc2UgfVxuICAgICAgY2FzZSBcIkVYUElSRURcIjpcbiAgICAgICAgLy8gV2Ugd2FudCB0byByZXR1cm4gNDAxIFVuYXV0aG9yaXplZCBmb3IgZXhwaXJlZCB0b2tlbnMsIHNvIHRoZSBjbGllbnQga25vd3MgdG8gcmVmcmVzaFxuICAgICAgICAvLyB0aGVpciB0b2tlbiB3aGVuIHJlY2VpdmluZyB0aGlzIHN0YXR1cyBjb2RlLiBBUEkgR2F0ZXdheSBMYW1iZGEgQXV0aG9yaXplcnMgcmV0dXJuXG4gICAgICAgIC8vIDQwMyBGb3JiaWRkZW4gZm9yIHtpc0F1dGhvcml6ZWQ6IGZhbHNlfSwgYnV0IHRoZXJlIGlzIGEgd2F5IHRvIHJldHVybiA0MDE6IHRocm93aW5nIGFuXG4gICAgICAgIC8vIGVycm9yIHdpdGggdGhpcyBleGFjdCBzdHJpbmcuIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS83MTk2NTg5MFxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJVbmF1dGhvcml6ZWRcIilcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgaXNBdXRob3JpemVkOiB0cnVlLFxuICAgICAgICAgIGNvbnRleHQ6IHtcbiAgICAgICAgICAgIGNsaWVudElkOiByZXN1bHQuY2xpZW50X2lkLFxuICAgICAgICAgICAgaW50ZXJuYWxBdXRob3JpemF0aW9uSGVhZGVyOlxuICAgICAgICAgICAgICBleHBlY3RlZEJhc2ljQXV0aENyZWRlbnRpYWxzPy5bMF0/LmJhc2ljQXV0aEhlYWRlcixcbiAgICAgICAgICB9LFxuICAgICAgICB9XG4gICAgfVxuICB9IGVsc2UgaWYgKFxuICAgIGF1dGhIZWFkZXIuc3RhcnRzV2l0aChcIkJhc2ljIFwiKSAmJlxuICAgIGV4cGVjdGVkQmFzaWNBdXRoQ3JlZGVudGlhbHMgIT09IHVuZGVmaW5lZFxuICApIHtcbiAgICBmb3IgKGNvbnN0IGV4cGVjdGVkIG9mIGV4cGVjdGVkQmFzaWNBdXRoQ3JlZGVudGlhbHMpIHtcbiAgICAgIGlmIChhdXRoSGVhZGVyID09PSBleHBlY3RlZC5iYXNpY0F1dGhIZWFkZXIpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBpc0F1dGhvcml6ZWQ6IHRydWUsXG4gICAgICAgICAgY29udGV4dDoge1xuICAgICAgICAgICAgdXNlcm5hbWU6IGV4cGVjdGVkLnVzZXJuYW1lLFxuICAgICAgICAgICAgaW50ZXJuYWxBdXRob3JpemF0aW9uSGVhZGVyOiBleHBlY3RlZC5iYXNpY0F1dGhIZWFkZXIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4geyBpc0F1dGhvcml6ZWQ6IGZhbHNlIH1cbiAgfSBlbHNlIHtcbiAgICByZXR1cm4geyBpc0F1dGhvcml6ZWQ6IGZhbHNlIH1cbiAgfVxufVxuXG4vKiogRGVjb2RlcyBhbmQgdmVyaWZpZXMgdGhlIGdpdmVuIHRva2VuIGFnYWluc3QgQ29nbml0by4gKi9cbmFzeW5jIGZ1bmN0aW9uIHZlcmlmeUFjY2Vzc1Rva2VuKFxuICB0b2tlbjogc3RyaW5nLFxuKTogUHJvbWlzZTxDb2duaXRvQWNjZXNzVG9rZW5QYXlsb2FkIHwgXCJFWFBJUkVEXCIgfCBcIklOVkFMSURcIj4ge1xuICB0cnkge1xuICAgIGNvbnN0IHRva2VuVmVyaWZpZXIgPSBnZXRUb2tlblZlcmlmaWVyKClcbiAgICAvLyBNdXN0IGF3YWl0IGhlcmUgaW5zdGVhZCBvZiByZXR1cm5pbmcgdGhlIHByb21pc2UgZGlyZWN0bHksIHNvIHRoYXQgZXJyb3JzIGNhbiBiZSBjYXVnaHQgaW5cbiAgICAvLyB0aGlzIGZ1bmN0aW9uXG4gICAgcmV0dXJuIGF3YWl0IHRva2VuVmVyaWZpZXIudmVyaWZ5KHRva2VuKVxuICB9IGNhdGNoIChlKSB7XG4gICAgLy8gSWYgdGhlIEpXVCBoYXMgZXhwaXJlZCwgYXdzLWp3dC12ZXJpZnkgdGhyb3dzIHRoaXMgZXJyb3I6XG4gICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2F3c2xhYnMvYXdzLWp3dC12ZXJpZnkvYmxvYi84ZDhmNzE0ZDcyODE5MTNlY2Q2NjAxNDdmNWMzMDMxMTQ3OTYwMWMxL3NyYy9qd3QudHMjTDE5N1xuICAgIC8vIFdlIGNhbid0IGNoZWNrIGluc3RhbmNlb2Ygb24gdGhhdCBlcnJvciBjbGFzcywgc2luY2UgaXQncyBub3QgZXhwb3J0ZWQsIHNvIHRoaXMgaXMgdGhlIG5leHRcbiAgICAvLyBiZXN0IHRoaW5nLlxuICAgIGlmIChlIGluc3RhbmNlb2YgRXJyb3IgJiYgZS5tZXNzYWdlPy5pbmNsdWRlcyhcIlRva2VuIGV4cGlyZWRcIikpIHtcbiAgICAgIHJldHVybiBcIkVYUElSRURcIlxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gXCJJTlZBTElEXCJcbiAgICB9XG4gIH1cbn1cblxuZXhwb3J0IHR5cGUgVG9rZW5WZXJpZmllciA9IHtcbiAgdmVyaWZ5OiAoYWNjZXNzVG9rZW46IHN0cmluZykgPT4gUHJvbWlzZTxDb2duaXRvQWNjZXNzVG9rZW5QYXlsb2FkPlxufVxuXG4vKipcbiAqIFdlIGNhY2hlIHRoZSB2ZXJpZmllciBpbiB0aGlzIGdsb2JhbCB2YXJpYWJsZSwgc28gdGhhdCBzdWJzZXF1ZW50IGludm9jYXRpb25zIG9mIGEgaG90IGxhbWJkYVxuICogd2lsbCByZS11c2UgdGhpcy5cbiAqL1xubGV0IGNhY2hlZFRva2VuVmVyaWZpZXI6IFRva2VuVmVyaWZpZXIgfCB1bmRlZmluZWQgPSB1bmRlZmluZWRcblxuZnVuY3Rpb24gZ2V0VG9rZW5WZXJpZmllcigpOiBUb2tlblZlcmlmaWVyIHtcbiAgaWYgKGNhY2hlZFRva2VuVmVyaWZpZXIgPT09IHVuZGVmaW5lZCkge1xuICAgIGNhY2hlZFRva2VuVmVyaWZpZXIgPSBkZXBlbmRlbmNpZXMuY3JlYXRlVG9rZW5WZXJpZmllcigpXG4gIH1cbiAgcmV0dXJuIGNhY2hlZFRva2VuVmVyaWZpZXJcbn1cblxuLyoqIEZvciBvdmVycmlkaW5nIGRlcGVuZGVuY3kgY3JlYXRpb24gaW4gdGVzdHMuICovXG5leHBvcnQgY29uc3QgZGVwZW5kZW5jaWVzID0ge1xuICBjcmVhdGVUb2tlblZlcmlmaWVyOiAoKTogVG9rZW5WZXJpZmllciA9PiB7XG4gICAgY29uc3QgdXNlclBvb2xJZCA9IHByb2Nlc3MuZW52W1wiVVNFUl9QT09MX0lEXCJdXG4gICAgaWYgKCF1c2VyUG9vbElkKSB7XG4gICAgICBjb25zb2xlLmVycm9yKFwiVVNFUl9QT09MX0lEIGVudiB2YXJpYWJsZSBpcyBub3QgZGVmaW5lZFwiKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKClcbiAgICB9XG5cbiAgICByZXR1cm4gQ29nbml0b0p3dFZlcmlmaWVyLmNyZWF0ZSh7XG4gICAgICB1c2VyUG9vbElkLFxuICAgICAgdG9rZW5Vc2U6IFwiYWNjZXNzXCIsXG4gICAgICBjbGllbnRJZDogbnVsbCxcbiAgICAgIHNjb3BlOiBwcm9jZXNzLmVudi5SRVFVSVJFRF9TQ09QRSB8fCB1bmRlZmluZWQsIC8vIGB8fCB1bmRlZmluZWRgIHRvIGRpc2NhcmQgZW1wdHkgc3RyaW5nXG4gICAgfSlcbiAgfSxcbiAgY3JlYXRlU2VjcmV0c01hbmFnZXI6ICgpID0+IG5ldyBTZWNyZXRzTWFuYWdlcigpLFxufVxuXG50eXBlIEV4cGVjdGVkQmFzaWNBdXRoQ3JlZGVudGlhbHMgPSB7XG4gIGJhc2ljQXV0aEhlYWRlcjogc3RyaW5nXG4gIHVzZXJuYW1lOiBzdHJpbmdcbn1cblxuLyoqIENhY2hlIHRoaXMgdmFsdWUsIHNvIHRoYXQgc3Vic2VxdWVudCBsYW1iZGEgaW52b2NhdGlvbnMgZG9uJ3QgaGF2ZSB0byByZWZldGNoLiAqL1xubGV0IGNhY2hlZEJhc2ljQXV0aENyZWRlbnRpYWxzOiBFeHBlY3RlZEJhc2ljQXV0aENyZWRlbnRpYWxzW10gfCB1bmRlZmluZWQgPVxuICB1bmRlZmluZWRcblxuLyoqXG4gKiBSZXR1cm5zIGFuIGFycmF5LCB0byBzdXBwb3J0IGNyZWRlbnRpYWwgc2VjcmV0cyB3aXRoIG11bHRpcGxlIHZhbHVlcyAoc2VlXG4gKiBgQmFzaWNBdXRoQXV0aG9yaXplclByb3BzYCBvbiB0aGUgYEFwaUdhdGV3YXlgIGNvbnN0cnVjdCBmb3IgbW9yZSBvbiB0aGlzKS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZ2V0RXhwZWN0ZWRCYXNpY0F1dGhDcmVkZW50aWFscygpOiBQcm9taXNlPFxuICBFeHBlY3RlZEJhc2ljQXV0aENyZWRlbnRpYWxzW10gfCB1bmRlZmluZWRcbj4ge1xuICBpZiAoY2FjaGVkQmFzaWNBdXRoQ3JlZGVudGlhbHMgPT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IHNlY3JldE5hbWU6IHN0cmluZyB8IHVuZGVmaW5lZCA9XG4gICAgICBwcm9jZXNzLmVudltcIkJBU0lDX0FVVEhfQ1JFREVOVElBTFNfU0VDUkVUX05BTUVcIl1cbiAgICBpZiAoIXNlY3JldE5hbWUpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWRcbiAgICB9XG5cbiAgICBjYWNoZWRCYXNpY0F1dGhDcmVkZW50aWFscyA9IGF3YWl0IGdldEJhc2ljQXV0aENyZWRlbnRpYWxzU2VjcmV0KHNlY3JldE5hbWUpXG4gIH1cblxuICByZXR1cm4gY2FjaGVkQmFzaWNBdXRoQ3JlZGVudGlhbHNcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0QmFzaWNBdXRoQ3JlZGVudGlhbHNTZWNyZXQoXG4gIHNlY3JldE5hbWU6IHN0cmluZyxcbik6IFByb21pc2U8RXhwZWN0ZWRCYXNpY0F1dGhDcmVkZW50aWFsc1tdPiB7XG4gIGNvbnN0IHNlY3JldCA9IGF3YWl0IGdldFNlY3JldFZhbHVlKHNlY3JldE5hbWUpXG5cbiAgaWYgKGlzVXNlcm5hbWVBbmRQYXNzd29yZE9iamVjdChzZWNyZXQpKSB7XG4gICAgcmV0dXJuIFtlbmNvZGVCYXNpY0F1dGhDcmVkZW50aWFscyhzZWNyZXQpXVxuICB9XG5cbiAgLy8gU2VlIGBCYXNpY0F1dGhBdXRob3JpemVyUHJvcHNgIG9uIHRoZSBgQXBpR2F0ZXdheWAgY29uc3RydWN0IGZvciBhbiBleHBsYW5hdGlvbiBvZiB0aGUgZm9ybWF0c1xuICAvLyB3ZSBwYXJzZSBoZXJlXG4gIGlmIChoYXNDcmVkZW50aWFsc0tleVdpdGhTdHJpbmdWYWx1ZShzZWNyZXQpKSB7XG4gICAgbGV0IGNyZWRlbnRpYWxzQXJyYXk6IHVua25vd25cbiAgICB0cnkge1xuICAgICAgY3JlZGVudGlhbHNBcnJheSA9IEpTT04ucGFyc2Uoc2VjcmV0LmNyZWRlbnRpYWxzKVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgIGBGYWlsZWQgdG8gcGFyc2UgY3JlZGVudGlhbHMgYXJyYXkgaW4gc2VjcmV0ICcke3NlY3JldE5hbWV9JyBhcyBKU09OYCxcbiAgICAgICAgZSxcbiAgICAgIClcbiAgICAgIHRocm93IG5ldyBFcnJvcigpXG4gICAgfVxuXG4gICAgaWYgKGlzQXJyYXlPZlVzZXJuYW1lQW5kUGFzc3dvcmRPYmplY3RzKGNyZWRlbnRpYWxzQXJyYXkpKSB7XG4gICAgICByZXR1cm4gY3JlZGVudGlhbHNBcnJheS5tYXAoZW5jb2RlQmFzaWNBdXRoQ3JlZGVudGlhbHMpXG4gICAgfVxuXG4gICAgaWYgKGlzU3RyaW5nQXJyYXkoY3JlZGVudGlhbHNBcnJheSkpIHtcbiAgICAgIHJldHVybiBjcmVkZW50aWFsc0FycmF5Lm1hcChwYXJzZUVuY29kZWRCYXNpY0F1dGhDcmVkZW50aWFscylcbiAgICB9XG4gIH1cblxuICBjb25zb2xlLmVycm9yKFxuICAgIGBCYXNpYyBhdXRoIGNyZWRlbnRpYWxzIHNlY3JldCBkaWQgbm90IGZvbGxvdyBhbnkgZXhwZWN0ZWQgZm9ybWF0IChzZWNyZXQgbmFtZTogJyR7c2VjcmV0TmFtZX0nKWAsXG4gIClcbiAgdGhyb3cgbmV3IEVycm9yKClcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0U2VjcmV0VmFsdWUoc2VjcmV0TmFtZTogc3RyaW5nKTogUHJvbWlzZTx1bmtub3duPiB7XG4gIGNvbnN0IGNsaWVudCA9IGRlcGVuZGVuY2llcy5jcmVhdGVTZWNyZXRzTWFuYWdlcigpXG4gIGNvbnN0IHNlY3JldCA9IGF3YWl0IGNsaWVudC5nZXRTZWNyZXRWYWx1ZSh7IFNlY3JldElkOiBzZWNyZXROYW1lIH0pXG5cbiAgaWYgKCFzZWNyZXQuU2VjcmV0U3RyaW5nKSB7XG4gICAgY29uc29sZS5lcnJvcihgU2VjcmV0IHZhbHVlIG5vdCBmb3VuZCBmb3IgJyR7c2VjcmV0TmFtZX0nYClcbiAgICB0aHJvdyBuZXcgRXJyb3IoKVxuICB9XG5cbiAgdHJ5IHtcbiAgICByZXR1cm4gSlNPTi5wYXJzZShzZWNyZXQuU2VjcmV0U3RyaW5nKVxuICB9IGNhdGNoIChlKSB7XG4gICAgY29uc29sZS5lcnJvcihgRmFpbGVkIHRvIHBhcnNlIHNlY3JldCAnJHtzZWNyZXROYW1lfScgYXMgSlNPTjpgLCBlKVxuICAgIHRocm93IG5ldyBFcnJvcigpXG4gIH1cbn1cblxuZnVuY3Rpb24gZW5jb2RlQmFzaWNBdXRoQ3JlZGVudGlhbHMoY3JlZGVudGlhbHM6IHtcbiAgdXNlcm5hbWU6IHN0cmluZ1xuICBwYXNzd29yZDogc3RyaW5nXG59KTogRXhwZWN0ZWRCYXNpY0F1dGhDcmVkZW50aWFscyB7XG4gIGNvbnN0IGJhc2ljQXV0aEhlYWRlciA9XG4gICAgXCJCYXNpYyBcIiArXG4gICAgQnVmZmVyLmZyb20oYCR7Y3JlZGVudGlhbHMudXNlcm5hbWV9OiR7Y3JlZGVudGlhbHMucGFzc3dvcmR9YCkudG9TdHJpbmcoXG4gICAgICBcImJhc2U2NFwiLFxuICAgIClcblxuICByZXR1cm4geyBiYXNpY0F1dGhIZWFkZXIsIHVzZXJuYW1lOiBjcmVkZW50aWFscy51c2VybmFtZSB9XG59XG5cbmZ1bmN0aW9uIGlzVXNlcm5hbWVBbmRQYXNzd29yZE9iamVjdChcbiAgdmFsdWU6IHVua25vd24sXG4pOiB2YWx1ZSBpcyB7IHVzZXJuYW1lOiBzdHJpbmc7IHBhc3N3b3JkOiBzdHJpbmcgfSB7XG4gIHJldHVybiAoXG4gICAgdHlwZW9mIHZhbHVlID09PSBcIm9iamVjdFwiICYmXG4gICAgdmFsdWUgIT09IG51bGwgJiZcbiAgICBcInVzZXJuYW1lXCIgaW4gdmFsdWUgJiZcbiAgICB0eXBlb2YgdmFsdWUudXNlcm5hbWUgPT09IFwic3RyaW5nXCIgJiZcbiAgICBcInBhc3N3b3JkXCIgaW4gdmFsdWUgJiZcbiAgICB0eXBlb2YgdmFsdWUucGFzc3dvcmQgPT09IFwic3RyaW5nXCJcbiAgKVxufVxuXG5mdW5jdGlvbiBpc0FycmF5T2ZVc2VybmFtZUFuZFBhc3N3b3JkT2JqZWN0cyhcbiAgdmFsdWU6IHVua25vd24sXG4pOiB2YWx1ZSBpcyB7IHVzZXJuYW1lOiBzdHJpbmc7IHBhc3N3b3JkOiBzdHJpbmcgfVtdIHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgIHJldHVybiBmYWxzZVxuICB9XG5cbiAgZm9yIChjb25zdCBlbGVtZW50IG9mIHZhbHVlKSB7XG4gICAgaWYgKCFpc1VzZXJuYW1lQW5kUGFzc3dvcmRPYmplY3QoZWxlbWVudCkpIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0cnVlXG59XG5cbmZ1bmN0aW9uIGhhc0NyZWRlbnRpYWxzS2V5V2l0aFN0cmluZ1ZhbHVlKFxuICB2YWx1ZTogdW5rbm93bixcbik6IHZhbHVlIGlzIHsgY3JlZGVudGlhbHM6IHN0cmluZyB9IHtcbiAgcmV0dXJuIChcbiAgICB0eXBlb2YgdmFsdWUgPT09IFwib2JqZWN0XCIgJiZcbiAgICB2YWx1ZSAhPT0gbnVsbCAmJlxuICAgIFwiY3JlZGVudGlhbHNcIiBpbiB2YWx1ZSAmJlxuICAgIHR5cGVvZiB2YWx1ZS5jcmVkZW50aWFscyA9PT0gXCJzdHJpbmdcIlxuICApXG59XG5cbmZ1bmN0aW9uIGlzU3RyaW5nQXJyYXkodmFsdWU6IHVua25vd24pOiB2YWx1ZSBpcyBzdHJpbmdbXSB7XG4gIGlmICghQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIGZvciAoY29uc3QgZWxlbWVudCBvZiB2YWx1ZSkge1xuICAgIGlmICh0eXBlb2YgZWxlbWVudCAhPT0gXCJzdHJpbmdcIikge1xuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRydWVcbn1cblxuLyoqXG4gKiBXZSB3YW50IHRvIHJldHVybiB0aGUgcmVxdWVzdGluZyB1c2VybmFtZSBhcyBhIGNvbnRleHQgdmFyaWFibGUgaW5cbiAqIHtAbGluayBBdXRob3JpemVyUmVzdWx0LmNvbnRleHR9LCBmb3IgQVBJIEdhdGV3YXkgYWNjZXNzIGxvZ3MgYW5kIHBhcmFtZXRlciBtYXBwaW5nLiBTbyBpZiB0aGVcbiAqIGJhc2ljIGF1dGggY3JlZGVudGlhbHMgc2VjcmV0IGlzIHN0b3JlZCBhcyBwcmUtZW5jb2RlZCBiYXNlNjQgc3RyaW5ncywgd2UgbmVlZCB0byBwYXJzZSB0aGVtIHRvXG4gKiBnZXQgdGhlIHVzZXJuYW1lLlxuICovXG5mdW5jdGlvbiBwYXJzZUVuY29kZWRCYXNpY0F1dGhDcmVkZW50aWFscyhcbiAgZW5jb2RlZENyZWRlbnRpYWxzOiBzdHJpbmcsXG4pOiBFeHBlY3RlZEJhc2ljQXV0aENyZWRlbnRpYWxzIHtcbiAgbGV0IGRlY29kZWRDcmVkZW50aWFsczogc3RyaW5nXG4gIHRyeSB7XG4gICAgZGVjb2RlZENyZWRlbnRpYWxzID0gQnVmZmVyLmZyb20oZW5jb2RlZENyZWRlbnRpYWxzLCBcImJhc2U2NFwiKS50b1N0cmluZygpXG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBjb25zb2xlLmVycm9yKFxuICAgICAgXCJCYXNpYyBhdXRoIGNyZWRlbnRpYWxzIHNlY3JldCBjb3VsZCBub3QgYmUgZGVjb2RlZCBhcyBiYXNlNjQ6XCIsXG4gICAgICBlLFxuICAgIClcbiAgICB0aHJvdyBuZXcgRXJyb3IoKVxuICB9XG5cbiAgY29uc3QgdXNlcm5hbWVBbmRQYXNzd29yZCA9IGRlY29kZWRDcmVkZW50aWFscy5zcGxpdChcIjpcIiwgMilcbiAgaWYgKHVzZXJuYW1lQW5kUGFzc3dvcmQubGVuZ3RoICE9PSAyKSB7XG4gICAgY29uc29sZS5lcnJvcihcbiAgICAgIFwiQmFzaWMgYXV0aCBjcmVkZW50aWFscyBzZWNyZXQgY291bGQgbm90IGJlIGRlY29kZWQgYXMgJ3VzZXJuYW1lOnBhc3N3b3JkJ1wiLFxuICAgIClcbiAgICB0aHJvdyBuZXcgRXJyb3IoKVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBiYXNpY0F1dGhIZWFkZXI6IGBCYXNpYyAke2VuY29kZWRDcmVkZW50aWFsc31gLFxuICAgIHVzZXJuYW1lOiB1c2VybmFtZUFuZFBhc3N3b3JkWzBdLFxuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjbGVhckNhY2hlKCkge1xuICBjYWNoZWRUb2tlblZlcmlmaWVyID0gdW5kZWZpbmVkXG4gIGNhY2hlZEJhc2ljQXV0aENyZWRlbnRpYWxzID0gdW5kZWZpbmVkXG59XG4iXX0=
|