@liflig/cdk 3.3.0 → 3.5.0
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/{authorizer-lambdas → authorizers}/basic-auth-authorizer.d.ts +3 -4
- 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/{authorizer-lambdas → authorizers}/cognito-user-pool-or-basic-auth-authorizer.d.ts +3 -4
- package/lib/api-gateway/authorizers/cognito-user-pool-or-basic-auth-authorizer.js +238 -0
- package/lib/api-gateway/http-api-gateway.d.ts +67 -45
- package/lib/api-gateway/http-api-gateway.js +17 -7
- package/package.json +1 -1
- package/lib/api-gateway/authorizer-lambdas/basic-auth-authorizer.js +0 -144
- 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 -222
- /package/lib/api-gateway/{authorizer-lambdas → authorizers}/cognito-user-pool-authorizer.d.ts +0 -0
|
@@ -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=
|
|
@@ -7,6 +7,7 @@ import type * as sqs from "aws-cdk-lib/aws-sqs";
|
|
|
7
7
|
import * as apigw from "aws-cdk-lib/aws-apigatewayv2";
|
|
8
8
|
import * as logs from "aws-cdk-lib/aws-logs";
|
|
9
9
|
import * as iam from "aws-cdk-lib/aws-iam";
|
|
10
|
+
import * as authorizers from "aws-cdk-lib/aws-apigatewayv2-authorizers";
|
|
10
11
|
import type { IUserPool } from "aws-cdk-lib/aws-cognito";
|
|
11
12
|
import * as route53 from "aws-cdk-lib/aws-route53";
|
|
12
13
|
/**
|
|
@@ -280,21 +281,21 @@ export type AuthorizationProps<AuthScopesT extends string = string> =
|
|
|
280
281
|
type: "IAM";
|
|
281
282
|
}
|
|
282
283
|
/**
|
|
283
|
-
* Creates a custom authorizer
|
|
284
|
+
* Creates a custom Lambda authorizer which reads `Authorization: Bearer <access token>` header
|
|
284
285
|
* and verifies the token against a Cognito user pool.
|
|
285
286
|
*/
|
|
286
287
|
| ({
|
|
287
288
|
type: "COGNITO_USER_POOL";
|
|
288
289
|
} & CognitoUserPoolAuthorizerProps<AuthScopesT>)
|
|
289
290
|
/**
|
|
290
|
-
* Creates a custom authorizer
|
|
291
|
+
* Creates a custom Lambda authorizer which reads `Authorization: Basic <base64-encoded credentials>`
|
|
291
292
|
* header and verifies the credentials against a given secret.
|
|
292
293
|
*/
|
|
293
294
|
| ({
|
|
294
295
|
type: "BASIC_AUTH";
|
|
295
296
|
} & BasicAuthAuthorizerProps)
|
|
296
297
|
/**
|
|
297
|
-
* Creates a custom authorizer
|
|
298
|
+
* Creates a custom Lambda authorizer which allows both:
|
|
298
299
|
* - `Authorization: Bearer <access token>` header, for which the token is checked against the
|
|
299
300
|
* given Cognito user pool
|
|
300
301
|
* - `Authorization: Basic <base64-encoded credentials>` header, for which the credentials are
|
|
@@ -304,7 +305,16 @@ export type AuthorizationProps<AuthScopesT extends string = string> =
|
|
|
304
305
|
*/
|
|
305
306
|
| ({
|
|
306
307
|
type: "COGNITO_USER_POOL_OR_BASIC_AUTH";
|
|
307
|
-
} & CognitoUserPoolOrBasicAuthAuthorizerProps<AuthScopesT>)
|
|
308
|
+
} & CognitoUserPoolOrBasicAuthAuthorizerProps<AuthScopesT>)
|
|
309
|
+
/**
|
|
310
|
+
* Creates a custom authorizer with the given Lambda function. Use this if you have custom
|
|
311
|
+
* authorization logic, and the other authorizers from this construct don't meet your needs.
|
|
312
|
+
*
|
|
313
|
+
* https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html
|
|
314
|
+
*/
|
|
315
|
+
| ({
|
|
316
|
+
type: "CUSTOM_LAMBDA_AUTHORIZER";
|
|
317
|
+
} & CustomLambdaAuthorizerProps);
|
|
308
318
|
export type CognitoUserPoolAuthorizerProps<AuthScopesT extends string = string> = {
|
|
309
319
|
userPool: IUserPool;
|
|
310
320
|
/**
|
|
@@ -349,54 +359,39 @@ export type CognitoUserPoolAuthorizerProps<AuthScopesT extends string = string>
|
|
|
349
359
|
};
|
|
350
360
|
export type BasicAuthAuthorizerProps = {
|
|
351
361
|
/**
|
|
352
|
-
* Name of secret in AWS Secrets Manager that stores basic auth credentials.
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
* -
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
*
|
|
362
|
+
* Name of secret in AWS Secrets Manager that stores basic auth credentials.
|
|
363
|
+
*
|
|
364
|
+
* The following formats are supported for the secret value:
|
|
365
|
+
* - Single username and password:
|
|
366
|
+
* ```json
|
|
367
|
+
* { "username": "<username>", "password": "<password>" }
|
|
368
|
+
* ```
|
|
369
|
+
* - Array of username + password objects:
|
|
370
|
+
* ```json
|
|
371
|
+
* { "credentials": "[{\"username\":\"<user-1>\",\"password\":\"password-1\"},{\"username\":\"<user-2>\",\"password\":\"<password-2>\"}]" }
|
|
372
|
+
* ```
|
|
373
|
+
* - The value of the `credentials` field is a string, with a stringified, escaped JSON array of
|
|
374
|
+
* objects with `username` and `password` fields.
|
|
375
|
+
* - The reason that this second format stores stringified JSON _inside_ JSON, is due to a
|
|
376
|
+
* limitation in Liflig's `load-secrets` library, which only allows storing string values.
|
|
377
|
+
* - Array of base64-encoded credentials:
|
|
378
|
+
* ```json
|
|
379
|
+
* { "credentials": "[\"<encoded-credential-1>\",\"<encoded-credential-2>\"]" }
|
|
380
|
+
* ```
|
|
381
|
+
* - Each element is encoded from `<username>:<password>`.
|
|
382
|
+
* - The array is stringified for the same reason as above.
|
|
383
|
+
*
|
|
384
|
+
* If the secret uses one of the array formats, the authorizer will match the request's
|
|
385
|
+
* Authorization header against any one of the credentials.
|
|
373
386
|
*/
|
|
374
387
|
credentialsSecretName: string;
|
|
375
388
|
};
|
|
376
389
|
export type CognitoUserPoolOrBasicAuthAuthorizerProps<AuthScopesT extends string = string> = {
|
|
377
390
|
userPool: IUserPool;
|
|
378
391
|
/**
|
|
379
|
-
* Name of secret in AWS Secrets Manager that stores basic auth credentials.
|
|
380
|
-
* should follow this format:
|
|
381
|
-
* ```json
|
|
382
|
-
* { "username": "<username>", "password": "<password>" }
|
|
383
|
-
* ```
|
|
384
|
-
*
|
|
385
|
-
* The following format is also supported:
|
|
386
|
-
* ```json
|
|
387
|
-
* { "credentials": "[\"<encoded-credential-1>\",\"<encoded-credential-2>\"]" }
|
|
388
|
-
* ```
|
|
389
|
-
* ...consisting of:
|
|
390
|
-
* - A single key, `credentials`
|
|
391
|
-
* - With a _string_ value
|
|
392
|
-
* - Which is a stringified, escaped JSON array of base64-encoded credentials
|
|
393
|
-
* - In which each element is encoded from `<username>:<password>`
|
|
392
|
+
* Name of secret in AWS Secrets Manager that stores basic auth credentials.
|
|
394
393
|
*
|
|
395
|
-
*
|
|
396
|
-
* against any one of these encoded credentials.
|
|
397
|
-
*
|
|
398
|
-
* The reason that this second format stores stringified JSON _inside_ JSON, is due to a
|
|
399
|
-
* limitation in Liflig's `load-secrets` library, which only allows storing strings values.
|
|
394
|
+
* See {@link BasicAuthAuthorizerProps.credentialsSecretName} for the supported formats.
|
|
400
395
|
*/
|
|
401
396
|
basicAuthCredentialsSecretName?: string;
|
|
402
397
|
/**
|
|
@@ -411,6 +406,32 @@ export type CognitoUserPoolOrBasicAuthAuthorizerProps<AuthScopesT extends string
|
|
|
411
406
|
*/
|
|
412
407
|
requiredScope?: AuthScopesT;
|
|
413
408
|
};
|
|
409
|
+
type CustomLambdaAuthorizerProps = {
|
|
410
|
+
/**
|
|
411
|
+
* The Lambda function that will be run whenever the API Gateway route is invoked, to authenticate
|
|
412
|
+
* the request. See AWS docs for more on how to write the Lambda:
|
|
413
|
+
* https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html
|
|
414
|
+
*
|
|
415
|
+
* The default response format used is `HttpLambdaResponseType.SIMPLE` (format 2.0). If you write
|
|
416
|
+
* your Lambda in TypeScript, this means that your handler must return
|
|
417
|
+
* `APIGatewaySimpleAuthorizerResult` (from the `aws-lambda` package). The request event will also
|
|
418
|
+
* use format 2.0 (`APIGatewayRequestAuthorizerEventV2` in TypeScript). See the AWS docs linked
|
|
419
|
+
* above for more details on these formats.
|
|
420
|
+
*
|
|
421
|
+
* You can override the response format type in
|
|
422
|
+
* {@link CustomLambdaAuthorizerProps.authorizerProps}.
|
|
423
|
+
*
|
|
424
|
+
* See the Lambdas under the `authorizers` folder next to the `ApiGateway` construct in
|
|
425
|
+
* `liflig-cdk` for examples.
|
|
426
|
+
*/
|
|
427
|
+
lambdaAuthorizer: lambda.IFunction;
|
|
428
|
+
/**
|
|
429
|
+
* Props for the `HttpLambdaAuthorizer` construct. We provide some different defaults:
|
|
430
|
+
* - `responseTypes` defaults to `[HttpLambdaResponseType.SIMPLE]`
|
|
431
|
+
* - `resultsCacheTtl` defaults to `Duration.hours(1)`
|
|
432
|
+
*/
|
|
433
|
+
authorizerProps?: Partial<authorizers.HttpLambdaAuthorizerProps>;
|
|
434
|
+
};
|
|
414
435
|
export type ApiGatewayAccessLogsProps = {
|
|
415
436
|
/**
|
|
416
437
|
* Delete the access logs if this construct is deleted?
|
|
@@ -530,3 +551,4 @@ export declare class ApiGateway<AuthScopesT extends string = string> extends con
|
|
|
530
551
|
*/
|
|
531
552
|
grantInvoke(target: iam.IGrantable): void;
|
|
532
553
|
}
|
|
554
|
+
export {};
|