@infoxchange/make-it-so 2.10.0-internal-testing-vdt-199-add-oidc-auth.6 → 2.10.0-internal-testing-vdt-199-add-oidc-auth.8
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/dist/cdk-constructs/CloudWatchOidcAuth/auth-check.js +20 -26
- package/dist/cdk-constructs/CloudWatchOidcAuth/auth-route.d.ts.map +1 -1
- package/dist/cdk-constructs/CloudWatchOidcAuth/auth-route.js +9 -11
- package/dist/cdk-constructs/CloudWatchOidcAuth/index.d.ts.map +1 -1
- package/dist/cdk-constructs/CloudWatchOidcAuth/index.js +7 -8
- package/package.json +1 -1
- package/src/cdk-constructs/CloudWatchOidcAuth/auth-check.ts +20 -27
- package/src/cdk-constructs/CloudWatchOidcAuth/auth-route.ts +12 -15
- package/src/cdk-constructs/CloudWatchOidcAuth/index.ts +7 -13
|
@@ -11,13 +11,9 @@ const redirectResponse = {
|
|
|
11
11
|
},
|
|
12
12
|
};
|
|
13
13
|
const kvsKey = "__placeholder-for-jwt-secret-key__";
|
|
14
|
-
//
|
|
15
|
-
const loggingEnabled =
|
|
14
|
+
// Set to true to enable console logging
|
|
15
|
+
const loggingEnabled = false;
|
|
16
16
|
function jwtDecode(token, key, noVerify) {
|
|
17
|
-
// check token
|
|
18
|
-
if (!token) {
|
|
19
|
-
throw new Error("No token supplied");
|
|
20
|
-
}
|
|
21
17
|
// check segments
|
|
22
18
|
const segments = token.split(".");
|
|
23
19
|
if (segments.length !== 3) {
|
|
@@ -49,8 +45,7 @@ function jwtDecode(token, key, noVerify) {
|
|
|
49
45
|
}
|
|
50
46
|
return payload;
|
|
51
47
|
}
|
|
52
|
-
//Function to ensure a constant time comparison to prevent
|
|
53
|
-
//timing side channels.
|
|
48
|
+
// Function to ensure a constant time comparison to prevent timing side channels.
|
|
54
49
|
function _constantTimeEquals(a, b) {
|
|
55
50
|
if (a.length != b.length) {
|
|
56
51
|
return false;
|
|
@@ -75,22 +70,14 @@ function _sign(input, key, method) {
|
|
|
75
70
|
function _base64urlDecode(str) {
|
|
76
71
|
return Buffer.from(str, "base64url").toString();
|
|
77
72
|
}
|
|
78
|
-
async function handler(event
|
|
79
|
-
console.log("🟢 Auth check event:", event);
|
|
80
|
-
console.log("🔵 Auth check context:", context);
|
|
73
|
+
async function handler(event) {
|
|
81
74
|
const request = event.request;
|
|
82
75
|
const secret_key = await getSecret();
|
|
83
76
|
if (!secret_key) {
|
|
84
|
-
|
|
77
|
+
// It's not possible for us to validate requests without the secret key so we have no choice but to block all requests.
|
|
78
|
+
throw new Error("Error retrieving JWT secret key");
|
|
85
79
|
}
|
|
86
|
-
// console.log(request);
|
|
87
|
-
// console.log(request.cookies);
|
|
88
|
-
// console.log(request.cookies["auth-token"]);
|
|
89
|
-
// console.log(Object.keys(request.cookies));
|
|
90
80
|
const jwtToken = request.cookies["auth-token"] && request.cookies["auth-token"].value;
|
|
91
|
-
console.log("jwtToken:", jwtToken);
|
|
92
|
-
// console.log(Object.keys(request.cookies));
|
|
93
|
-
// If no JWT token, then generate HTTP redirect 401 response.
|
|
94
81
|
if (!jwtToken) {
|
|
95
82
|
log("Error: No JWT in the cookies");
|
|
96
83
|
return redirectResponse;
|
|
@@ -102,8 +89,6 @@ async function handler(event, context) {
|
|
|
102
89
|
log(e);
|
|
103
90
|
return redirectResponse;
|
|
104
91
|
}
|
|
105
|
-
// //Remove the JWT from the query string if valid and return.
|
|
106
|
-
// delete request.querystring.jwt;
|
|
107
92
|
log("Valid JWT token");
|
|
108
93
|
return request;
|
|
109
94
|
}
|
|
@@ -119,11 +104,20 @@ async function getSecret() {
|
|
|
119
104
|
}
|
|
120
105
|
}
|
|
121
106
|
const log = function () {
|
|
122
|
-
if (loggingEnabled)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
107
|
+
if (!loggingEnabled)
|
|
108
|
+
return;
|
|
109
|
+
// CloudFront Function runtime only prints first argument passed to console.log so add other args to the first one if given.
|
|
110
|
+
// eslint-disable-next-line prefer-rest-params -- We can't use spread or rest parameters in CloudFront Functions
|
|
111
|
+
let message = arguments[0];
|
|
112
|
+
if (arguments.length > 1) {
|
|
113
|
+
const otherArgs = [];
|
|
114
|
+
for (let i = 1; i < arguments.length; i++) {
|
|
115
|
+
// eslint-disable-next-line prefer-rest-params
|
|
116
|
+
otherArgs[i - 1] = arguments[i];
|
|
117
|
+
}
|
|
118
|
+
message += " - additional args: " + JSON.stringify(otherArgs);
|
|
119
|
+
}
|
|
120
|
+
console.log(message);
|
|
127
121
|
};
|
|
128
122
|
// This serves no purpose other than to make TypeScript and eslint happy by showing that that handler is used. We can't
|
|
129
123
|
// export handler as an alterative because CloudFront Functions don't support exports.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-route.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudWatchOidcAuth/auth-route.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"auth-route.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudWatchOidcAuth/auth-route.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,OAAO,4CAsCnB,CAAC"}
|
|
@@ -24,28 +24,26 @@ export const handler = addRequiredContext(AuthHandler({
|
|
|
24
24
|
issuer: await Issuer.discover(oidcIssuerConfigUrl.href),
|
|
25
25
|
clientID: oidcClientId,
|
|
26
26
|
scope: oidcScope,
|
|
27
|
-
onSuccess: async (tokenset) => {
|
|
28
|
-
console.log("
|
|
29
|
-
// console.log("Config.jwtSecret:", jwtSecret);
|
|
27
|
+
onSuccess: async (tokenset, client) => {
|
|
28
|
+
console.log("🟣", client);
|
|
30
29
|
// Payload to include in the token
|
|
31
30
|
const payload = {
|
|
32
31
|
userID: tokenset.claims().sub,
|
|
33
32
|
};
|
|
34
|
-
|
|
35
|
-
const options = {
|
|
36
|
-
algorithm: "HS256",
|
|
37
|
-
expiresIn: "1h",
|
|
38
|
-
};
|
|
33
|
+
const expiresInMs = 1000 * 60 * 60;
|
|
39
34
|
// Create the token
|
|
40
|
-
const token = jwt.sign(payload, jwtSecret,
|
|
41
|
-
|
|
35
|
+
const token = jwt.sign(payload, jwtSecret, {
|
|
36
|
+
algorithm: "HS256",
|
|
37
|
+
expiresIn: expiresInMs / 1000,
|
|
38
|
+
});
|
|
39
|
+
const expiryDate = new Date(Date.now() + expiresInMs);
|
|
42
40
|
return {
|
|
43
41
|
statusCode: 302,
|
|
44
42
|
headers: {
|
|
45
43
|
location: "/",
|
|
46
44
|
},
|
|
47
45
|
cookies: [
|
|
48
|
-
`auth-token=${token}; HttpOnly; SameSite=None; Secure; Path=/; Expires=${
|
|
46
|
+
`auth-token=${token}; HttpOnly; SameSite=None; Secure; Path=/; Expires=${expiryDate}`,
|
|
49
47
|
],
|
|
50
48
|
};
|
|
51
49
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudWatchOidcAuth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AASvC,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAI1E,KAAK,cAAc,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,KAAK,WAAW,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9D,KAAK,OAAO,CAAC,CAAC,IAAI;IAChB,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAC/B,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,qBAAa,kBAAmB,SAAQ,SAAS;IAC/C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;gBAER,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;IAQhE,2BAA2B,CACzB,iBAAiB,SAAS,4BAA4B,EAEtD,KAAK,EAAE,cAAc,EACrB,EACE,sBAAsB,EACtB,MAAgB,GACjB,EAAE;QAAE,sBAAsB,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudWatchOidcAuth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AASvC,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAI1E,KAAK,cAAc,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,KAAK,WAAW,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9D,KAAK,OAAO,CAAC,CAAC,IAAI;IAChB,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAC/B,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,qBAAa,kBAAmB,SAAQ,SAAS;IAC/C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;gBAER,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;IAQhE,2BAA2B,CACzB,iBAAiB,SAAS,4BAA4B,EAEtD,KAAK,EAAE,cAAc,EACrB,EACE,sBAAsB,EACtB,MAAgB,GACjB,EAAE;QAAE,sBAAsB,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAuC5E,OAAO,CAAC,sBAAsB;IAyH9B,OAAO,CAAC,sBAAsB;CA0E/B"}
|
|
@@ -22,7 +22,6 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
22
22
|
this.id = id;
|
|
23
23
|
}
|
|
24
24
|
addToDistributionDefinition(scope, { distributionDefinition, prefix = "/auth", }) {
|
|
25
|
-
console.log("------", import.meta.dirname, import.meta.url, import.meta.filename);
|
|
26
25
|
const updatedDistributionDefinition = { ...distributionDefinition };
|
|
27
26
|
const behaviourName = `${prefix.replace(/^\//g, "")}/*`;
|
|
28
27
|
updatedDistributionDefinition.additionalBehaviors =
|
|
@@ -126,18 +125,18 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
126
125
|
throw new Error("Could not find the underlying Lambda function of the AwsCustomResource");
|
|
127
126
|
}
|
|
128
127
|
fn.addEnvironment("NODE_OPTIONS", "--require=@aws-sdk/signature-v4-crt");
|
|
129
|
-
const
|
|
128
|
+
const authCheckFunction = new CloudFront.Function(scope, `${this.id}AuthCheckFunction`, {
|
|
130
129
|
code: CloudFront.FunctionCode.fromInline(fs.readFileSync(path.join(import.meta.dirname, "auth-check.js"), "utf8").replace("__placeholder-for-jwt-secret-key__", key)),
|
|
131
130
|
runtime: CloudFront.FunctionRuntime.JS_2_0,
|
|
132
131
|
keyValueStore: cfKeyValueStore,
|
|
133
132
|
});
|
|
134
133
|
return {
|
|
135
|
-
function:
|
|
134
|
+
function: authCheckFunction,
|
|
136
135
|
eventType: CloudFront.FunctionEventType.VIEWER_REQUEST,
|
|
137
136
|
};
|
|
138
137
|
}
|
|
139
138
|
getAuthBehaviorOptions(scope, jwtSecret, prefix) {
|
|
140
|
-
const
|
|
139
|
+
const authRouteFunction = new SST.Function(scope, `${this.id}AuthRouteFunction`, {
|
|
141
140
|
runtime: "nodejs20.x",
|
|
142
141
|
handler: path.join(import.meta.dirname, "auth-route.handler"),
|
|
143
142
|
environment: {
|
|
@@ -147,7 +146,7 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
147
146
|
JWT_SECRET: jwtSecret.secretValue.toString(),
|
|
148
147
|
},
|
|
149
148
|
});
|
|
150
|
-
//
|
|
149
|
+
// authRouteFunction uses SST's AuthHandler construct which is normally run inside a lambda that's
|
|
151
150
|
// created by SST's Auth construct. AuthHandler expects certain environment variables to be set
|
|
152
151
|
// by the Auth construct so we have to set them ourselves here to keep it happy.
|
|
153
152
|
const envVarName = SSTInternalConfig.envFor({
|
|
@@ -155,8 +154,8 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
155
154
|
id: "id", // It seems like the env var will still be found no matter what this value is
|
|
156
155
|
prop: "prefix",
|
|
157
156
|
});
|
|
158
|
-
|
|
159
|
-
const
|
|
157
|
+
authRouteFunction.addEnvironment(envVarName, prefix);
|
|
158
|
+
const authRouteFunctionUrl = authRouteFunction.addFunctionUrl({
|
|
160
159
|
authType: Lambda.FunctionUrlAuthType.NONE,
|
|
161
160
|
});
|
|
162
161
|
const forwardHostHeaderCfFunction = new CloudFront.Function(scope, `${this.id}ForwardHostHeaderFunction`, {
|
|
@@ -170,7 +169,7 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
170
169
|
runtime: CloudFront.FunctionRuntime.JS_2_0,
|
|
171
170
|
});
|
|
172
171
|
return {
|
|
173
|
-
origin: new CloudFrontOrigins.HttpOrigin(CDK.Fn.parseDomainName(
|
|
172
|
+
origin: new CloudFrontOrigins.HttpOrigin(CDK.Fn.parseDomainName(authRouteFunctionUrl.url)),
|
|
174
173
|
allowedMethods: CloudFront.AllowedMethods.ALLOW_ALL,
|
|
175
174
|
cachePolicy: new CloudFront.CachePolicy(scope, `${this.id}AllowAllCookiesPolicy`, {
|
|
176
175
|
cachePolicyName: "AllowAllCookiesPolicy",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infoxchange/make-it-so",
|
|
3
|
-
"version": "2.10.0-internal-testing-vdt-199-add-oidc-auth.
|
|
3
|
+
"version": "2.10.0-internal-testing-vdt-199-add-oidc-auth.8",
|
|
4
4
|
"description": "Makes deploying services to IX infra easy",
|
|
5
5
|
"repository": "github:infoxchange/make-it-so",
|
|
6
6
|
"type": "module",
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// Based off: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/example_cloudfront_functions_kvs_jwt_verify_section.html
|
|
2
2
|
// Note that as a CloudFront Function, this code has limitations compared to a Lambda@Edge function.
|
|
3
3
|
// For example, no external libraries can be used, and the runtime is more limited.
|
|
4
|
-
|
|
5
|
-
|
|
6
4
|
import crypto from "crypto";
|
|
7
5
|
import cf from "cloudfront";
|
|
8
6
|
|
|
@@ -15,14 +13,10 @@ const redirectResponse = {
|
|
|
15
13
|
};
|
|
16
14
|
|
|
17
15
|
const kvsKey = "__placeholder-for-jwt-secret-key__";
|
|
18
|
-
//
|
|
19
|
-
const loggingEnabled =
|
|
16
|
+
// Set to true to enable console logging
|
|
17
|
+
const loggingEnabled = false;
|
|
20
18
|
|
|
21
19
|
function jwtDecode(token: string, key: string, noVerify?: boolean) {
|
|
22
|
-
// check token
|
|
23
|
-
if (!token) {
|
|
24
|
-
throw new Error("No token supplied");
|
|
25
|
-
}
|
|
26
20
|
// check segments
|
|
27
21
|
const segments = token.split(".");
|
|
28
22
|
if (segments.length !== 3) {
|
|
@@ -64,8 +58,7 @@ function jwtDecode(token: string, key: string, noVerify?: boolean) {
|
|
|
64
58
|
return payload;
|
|
65
59
|
}
|
|
66
60
|
|
|
67
|
-
//Function to ensure a constant time comparison to prevent
|
|
68
|
-
//timing side channels.
|
|
61
|
+
// Function to ensure a constant time comparison to prevent timing side channels.
|
|
69
62
|
function _constantTimeEquals(a: string, b: string) {
|
|
70
63
|
if (a.length != b.length) {
|
|
71
64
|
return false;
|
|
@@ -95,25 +88,17 @@ function _base64urlDecode(str: string) {
|
|
|
95
88
|
return Buffer.from(str, "base64url").toString();
|
|
96
89
|
}
|
|
97
90
|
|
|
98
|
-
async function handler(event: AWSCloudFrontFunction.Event
|
|
99
|
-
console.log("🟢 Auth check event:", event);
|
|
100
|
-
console.log("🔵 Auth check context:", context);
|
|
91
|
+
async function handler(event: AWSCloudFrontFunction.Event) {
|
|
101
92
|
const request = event.request;
|
|
102
93
|
const secret_key = await getSecret();
|
|
103
94
|
|
|
104
95
|
if (!secret_key) {
|
|
105
|
-
|
|
96
|
+
// It's not possible for us to validate requests without the secret key so we have no choice but to block all requests.
|
|
97
|
+
throw new Error("Error retrieving JWT secret key");
|
|
106
98
|
}
|
|
107
99
|
|
|
108
|
-
// console.log(request);
|
|
109
|
-
// console.log(request.cookies);
|
|
110
|
-
// console.log(request.cookies["auth-token"]);
|
|
111
|
-
// console.log(Object.keys(request.cookies));
|
|
112
100
|
const jwtToken = request.cookies["auth-token"] && request.cookies["auth-token"].value;
|
|
113
|
-
console.log("jwtToken:", jwtToken);
|
|
114
|
-
// console.log(Object.keys(request.cookies));
|
|
115
101
|
|
|
116
|
-
// If no JWT token, then generate HTTP redirect 401 response.
|
|
117
102
|
if (!jwtToken) {
|
|
118
103
|
log("Error: No JWT in the cookies");
|
|
119
104
|
return redirectResponse;
|
|
@@ -125,8 +110,6 @@ async function handler(event: AWSCloudFrontFunction.Event, context: AWSCloudFron
|
|
|
125
110
|
return redirectResponse;
|
|
126
111
|
}
|
|
127
112
|
|
|
128
|
-
// //Remove the JWT from the query string if valid and return.
|
|
129
|
-
// delete request.querystring.jwt;
|
|
130
113
|
log("Valid JWT token");
|
|
131
114
|
return request;
|
|
132
115
|
}
|
|
@@ -143,11 +126,21 @@ async function getSecret() {
|
|
|
143
126
|
}
|
|
144
127
|
|
|
145
128
|
const log: typeof console.log = function () {
|
|
146
|
-
if (loggingEnabled)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
129
|
+
if (!loggingEnabled) return;
|
|
130
|
+
|
|
131
|
+
// CloudFront Function runtime only prints first argument passed to console.log so add other args to the first one if given.
|
|
132
|
+
// eslint-disable-next-line prefer-rest-params -- We can't use spread or rest parameters in CloudFront Functions
|
|
133
|
+
let message = arguments[0]
|
|
134
|
+
if (arguments.length > 1) {
|
|
135
|
+
const otherArgs = [];
|
|
136
|
+
for (let i = 1; i < arguments.length; i++) {
|
|
137
|
+
// eslint-disable-next-line prefer-rest-params
|
|
138
|
+
otherArgs[i-1] = arguments[i];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
message += " - additional args: " + JSON.stringify(otherArgs);
|
|
150
142
|
}
|
|
143
|
+
console.log(message);
|
|
151
144
|
}
|
|
152
145
|
|
|
153
146
|
// This serves no purpose other than to make TypeScript and eslint happy by showing that that handler is used. We can't
|
|
@@ -30,34 +30,31 @@ export const handler = addRequiredContext(
|
|
|
30
30
|
issuer: await Issuer.discover(oidcIssuerConfigUrl.href),
|
|
31
31
|
clientID: oidcClientId,
|
|
32
32
|
scope: oidcScope,
|
|
33
|
-
onSuccess: async (tokenset) => {
|
|
34
|
-
console.log("
|
|
35
|
-
|
|
36
|
-
// console.log("Config.jwtSecret:", jwtSecret);
|
|
37
|
-
|
|
33
|
+
onSuccess: async (tokenset, client) => {
|
|
34
|
+
console.log("🟣", client);
|
|
38
35
|
// Payload to include in the token
|
|
39
36
|
const payload = {
|
|
40
37
|
userID: tokenset.claims().sub,
|
|
41
38
|
};
|
|
42
|
-
|
|
43
|
-
// Options (optional)
|
|
44
|
-
const options = {
|
|
45
|
-
algorithm: "HS256",
|
|
46
|
-
expiresIn: "1h",
|
|
47
|
-
} as const;
|
|
39
|
+
const expiresInMs = 1000 * 60 * 60;
|
|
48
40
|
|
|
49
41
|
// Create the token
|
|
50
|
-
const token = jwt.sign(
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
const token = jwt.sign(
|
|
43
|
+
payload,
|
|
44
|
+
jwtSecret,
|
|
45
|
+
{
|
|
46
|
+
algorithm: "HS256",
|
|
47
|
+
expiresIn: expiresInMs / 1000,
|
|
48
|
+
}
|
|
53
49
|
);
|
|
50
|
+
const expiryDate = new Date(Date.now() + expiresInMs);
|
|
54
51
|
return {
|
|
55
52
|
statusCode: 302,
|
|
56
53
|
headers: {
|
|
57
54
|
location: "/",
|
|
58
55
|
},
|
|
59
56
|
cookies: [
|
|
60
|
-
`auth-token=${token}; HttpOnly; SameSite=None; Secure; Path=/; Expires=${
|
|
57
|
+
`auth-token=${token}; HttpOnly; SameSite=None; Secure; Path=/; Expires=${expiryDate}`,
|
|
61
58
|
],
|
|
62
59
|
};
|
|
63
60
|
},
|
|
@@ -47,12 +47,6 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
47
47
|
prefix = "/auth",
|
|
48
48
|
}: { distributionDefinition: Mutable<DistributionProps>; prefix?: string },
|
|
49
49
|
) {
|
|
50
|
-
console.log(
|
|
51
|
-
"------",
|
|
52
|
-
import.meta.dirname,
|
|
53
|
-
import.meta.url,
|
|
54
|
-
import.meta.filename,
|
|
55
|
-
);
|
|
56
50
|
const updatedDistributionDefinition = { ...distributionDefinition };
|
|
57
51
|
const behaviourName = `${prefix.replace(/^\//g, "")}/*`;
|
|
58
52
|
updatedDistributionDefinition.additionalBehaviors =
|
|
@@ -193,7 +187,7 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
193
187
|
}
|
|
194
188
|
fn.addEnvironment("NODE_OPTIONS", "--require=@aws-sdk/signature-v4-crt");
|
|
195
189
|
|
|
196
|
-
const
|
|
190
|
+
const authCheckFunction = new CloudFront.Function(
|
|
197
191
|
scope,
|
|
198
192
|
`${this.id}AuthCheckFunction`,
|
|
199
193
|
{
|
|
@@ -206,7 +200,7 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
206
200
|
);
|
|
207
201
|
|
|
208
202
|
return {
|
|
209
|
-
function:
|
|
203
|
+
function: authCheckFunction,
|
|
210
204
|
eventType: CloudFront.FunctionEventType.VIEWER_REQUEST,
|
|
211
205
|
};
|
|
212
206
|
}
|
|
@@ -216,7 +210,7 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
216
210
|
jwtSecret: SecretsManager.Secret,
|
|
217
211
|
prefix: string,
|
|
218
212
|
): CloudFront.BehaviorOptions {
|
|
219
|
-
const
|
|
213
|
+
const authRouteFunction = new SST.Function(scope, `${this.id}AuthRouteFunction`, {
|
|
220
214
|
runtime: "nodejs20.x",
|
|
221
215
|
handler: path.join(import.meta.dirname, "auth-route.handler"),
|
|
222
216
|
environment: {
|
|
@@ -227,7 +221,7 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
227
221
|
},
|
|
228
222
|
});
|
|
229
223
|
|
|
230
|
-
//
|
|
224
|
+
// authRouteFunction uses SST's AuthHandler construct which is normally run inside a lambda that's
|
|
231
225
|
// created by SST's Auth construct. AuthHandler expects certain environment variables to be set
|
|
232
226
|
// by the Auth construct so we have to set them ourselves here to keep it happy.
|
|
233
227
|
const envVarName = SSTInternalConfig.envFor({
|
|
@@ -235,9 +229,9 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
235
229
|
id: "id", // It seems like the env var will still be found no matter what this value is
|
|
236
230
|
prop: "prefix",
|
|
237
231
|
});
|
|
238
|
-
|
|
232
|
+
authRouteFunction.addEnvironment(envVarName, prefix);
|
|
239
233
|
|
|
240
|
-
const
|
|
234
|
+
const authRouteFunctionUrl = authRouteFunction.addFunctionUrl({
|
|
241
235
|
authType: Lambda.FunctionUrlAuthType.NONE,
|
|
242
236
|
});
|
|
243
237
|
const forwardHostHeaderCfFunction = new CloudFront.Function(
|
|
@@ -257,7 +251,7 @@ export class CloudWatchOidcAuth extends Construct {
|
|
|
257
251
|
|
|
258
252
|
return {
|
|
259
253
|
origin: new CloudFrontOrigins.HttpOrigin(
|
|
260
|
-
CDK.Fn.parseDomainName(
|
|
254
|
+
CDK.Fn.parseDomainName(authRouteFunctionUrl.url),
|
|
261
255
|
),
|
|
262
256
|
allowedMethods: CloudFront.AllowedMethods.ALLOW_ALL,
|
|
263
257
|
cachePolicy: new CloudFront.CachePolicy(
|