@openinc/parse-server-opendash 3.10.2 → 3.10.3
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.
|
@@ -7,6 +7,7 @@ exports.init = init;
|
|
|
7
7
|
const crypto_1 = require("crypto");
|
|
8
8
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
9
9
|
const jwks_rsa_1 = __importDefault(require("jwks-rsa"));
|
|
10
|
+
const https_1 = __importDefault(require("https"));
|
|
10
11
|
const config_1 = require("../features/config");
|
|
11
12
|
const types_1 = require("../types");
|
|
12
13
|
const tenantId = config_1.ConfigInstance.getInstance().get("MICROSOFT_TENANT_ID") ||
|
|
@@ -15,23 +16,59 @@ const tenantId = config_1.ConfigInstance.getInstance().get("MICROSOFT_TENANT_ID"
|
|
|
15
16
|
const appId = config_1.ConfigInstance.getInstance().get("MICROSOFT_APP_ID") ||
|
|
16
17
|
process.env.MICROSOFT_APP_ID ||
|
|
17
18
|
process.env.OI_MICROSOFT_APP_ID;
|
|
18
|
-
// Setup JWKS client for Microsoft -
|
|
19
|
-
const
|
|
19
|
+
// Setup JWKS client for Microsoft - use tenant-specific endpoint with common as fallback
|
|
20
|
+
const getTenantJwksUri = () => `https://login.microsoftonline.com/${tenantId}/discovery/v2.0/keys`;
|
|
21
|
+
const getCommonJwksUri = () => `https://login.microsoftonline.com/common/discovery/v2.0/keys`;
|
|
20
22
|
const client = (0, jwks_rsa_1.default)({
|
|
21
|
-
jwksUri:
|
|
22
|
-
cache:
|
|
23
|
-
cacheMaxEntries: 5,
|
|
24
|
-
cacheMaxAge: 1000 * 60 * 60 * 24, // 24 hours
|
|
23
|
+
jwksUri: getTenantJwksUri(),
|
|
24
|
+
cache: false, // Disable cache temporarily for debugging
|
|
25
25
|
timeout: 30000, // 30 seconds
|
|
26
26
|
});
|
|
27
|
-
// Fallback client for
|
|
28
|
-
const
|
|
29
|
-
jwksUri:
|
|
30
|
-
cache:
|
|
31
|
-
cacheMaxEntries: 5,
|
|
32
|
-
cacheMaxAge: 1000 * 60 * 60 * 24, // 24 hours
|
|
27
|
+
// Fallback client for common endpoint if tenant-specific fails
|
|
28
|
+
const clientCommon = (0, jwks_rsa_1.default)({
|
|
29
|
+
jwksUri: getCommonJwksUri(),
|
|
30
|
+
cache: false, // Disable cache temporarily for debugging
|
|
33
31
|
timeout: 30000, // 30 seconds
|
|
34
32
|
});
|
|
33
|
+
// Manual JWKS fetch function to bypass jwks-rsa library issues
|
|
34
|
+
function fetchJWKSManually(uri) {
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
console.log("Making manual HTTPS request to:", uri);
|
|
37
|
+
https_1.default
|
|
38
|
+
.get(uri, (res) => {
|
|
39
|
+
let data = "";
|
|
40
|
+
console.log("Response status:", res.statusCode);
|
|
41
|
+
console.log("Response headers:", res.headers);
|
|
42
|
+
res.on("data", (chunk) => {
|
|
43
|
+
data += chunk;
|
|
44
|
+
});
|
|
45
|
+
res.on("end", () => {
|
|
46
|
+
try {
|
|
47
|
+
const jwks = JSON.parse(data);
|
|
48
|
+
console.log("Successfully fetched JWKS manually, found", jwks.keys?.length, "keys");
|
|
49
|
+
resolve(jwks);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
console.error("Failed to parse JWKS JSON:", error);
|
|
53
|
+
reject(error);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
})
|
|
57
|
+
.on("error", (error) => {
|
|
58
|
+
console.error("HTTPS request failed:", error);
|
|
59
|
+
reject(error);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
// Convert JWK to PEM format
|
|
64
|
+
function jwkToPem(jwk) {
|
|
65
|
+
// For Microsoft tokens, we can use the x5c (certificate chain) directly
|
|
66
|
+
if (jwk.x5c && jwk.x5c[0]) {
|
|
67
|
+
return `-----BEGIN CERTIFICATE-----\n${jwk.x5c[0]}\n-----END CERTIFICATE-----`;
|
|
68
|
+
}
|
|
69
|
+
// If no x5c, we'd need to construct from n and e, but Microsoft usually provides x5c
|
|
70
|
+
throw new Error("No x5c certificate chain found in JWK - cannot convert to PEM");
|
|
71
|
+
}
|
|
35
72
|
function getKey(header, callback) {
|
|
36
73
|
console.log("JWT Header:", header);
|
|
37
74
|
console.log("Tenant ID:", tenantId);
|
|
@@ -41,44 +78,85 @@ function getKey(header, callback) {
|
|
|
41
78
|
return callback(new Error("No kid found in token header"));
|
|
42
79
|
}
|
|
43
80
|
console.log("Attempting to get signing key for kid:", header.kid);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (!
|
|
54
|
-
|
|
55
|
-
return callback(new Error("Key not found in v1.0 endpoint"));
|
|
56
|
-
}
|
|
57
|
-
try {
|
|
58
|
-
const signingKey = keyV1.getPublicKey();
|
|
59
|
-
console.log("Successfully retrieved signing key from v1.0 endpoint");
|
|
60
|
-
callback(null, signingKey);
|
|
61
|
-
}
|
|
62
|
-
catch (keyError) {
|
|
63
|
-
console.error("Error extracting public key from v1.0:", keyError);
|
|
64
|
-
callback(keyError instanceof Error ? keyError : new Error(String(keyError)));
|
|
81
|
+
// Try manual fetch first to bypass jwks-rsa issues
|
|
82
|
+
console.log("Trying manual JWKS fetch...");
|
|
83
|
+
fetchJWKSManually(getTenantJwksUri())
|
|
84
|
+
.then((jwks) => {
|
|
85
|
+
const key = jwks.keys.find((k) => k.kid === header.kid);
|
|
86
|
+
if (!key) {
|
|
87
|
+
console.log("Key not found in tenant-specific JWKS, trying common endpoint...");
|
|
88
|
+
return fetchJWKSManually(getCommonJwksUri()).then((commonJwks) => {
|
|
89
|
+
const commonKey = commonJwks.keys.find((k) => k.kid === header.kid);
|
|
90
|
+
if (!commonKey) {
|
|
91
|
+
throw new Error(`Key with kid ${header.kid} not found in either endpoint`);
|
|
65
92
|
}
|
|
93
|
+
return commonKey;
|
|
66
94
|
});
|
|
67
|
-
return;
|
|
68
95
|
}
|
|
96
|
+
return key; // Return the key directly, not wrapped
|
|
97
|
+
})
|
|
98
|
+
.then((key) => {
|
|
69
99
|
if (!key) {
|
|
70
|
-
|
|
71
|
-
return callback(new Error("Key not found"));
|
|
100
|
+
throw new Error("No key found");
|
|
72
101
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
102
|
+
// Convert to PEM format using x5c if available
|
|
103
|
+
if (key.x5c && key.x5c[0]) {
|
|
104
|
+
const cert = jwkToPem(key);
|
|
105
|
+
console.log("Successfully retrieved signing key using manual fetch");
|
|
106
|
+
callback(null, cert);
|
|
77
107
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
callback(keyError instanceof Error ? keyError : new Error(String(keyError)));
|
|
108
|
+
else {
|
|
109
|
+
throw new Error("No x5c certificate chain found in key");
|
|
81
110
|
}
|
|
111
|
+
})
|
|
112
|
+
.catch((manualError) => {
|
|
113
|
+
console.error("Manual JWKS fetch failed, falling back to jwks-rsa library:", manualError);
|
|
114
|
+
// Fallback to original jwks-rsa approach
|
|
115
|
+
console.log("Trying tenant-specific JWKS endpoint with jwks-rsa...");
|
|
116
|
+
console.log("Tenant JWKS URI:", getTenantJwksUri());
|
|
117
|
+
client.getSigningKey(header.kid, (err, key) => {
|
|
118
|
+
if (err) {
|
|
119
|
+
console.error("Error with tenant-specific endpoint, trying common endpoint:", err);
|
|
120
|
+
console.log("Trying common JWKS endpoint as fallback...");
|
|
121
|
+
console.log("Common JWKS URI:", getCommonJwksUri());
|
|
122
|
+
// Try common endpoint as fallback
|
|
123
|
+
clientCommon.getSigningKey(header.kid, (errCommon, keyCommon) => {
|
|
124
|
+
if (errCommon) {
|
|
125
|
+
console.error("Error with common endpoint:", errCommon);
|
|
126
|
+
return callback(errCommon);
|
|
127
|
+
}
|
|
128
|
+
if (!keyCommon) {
|
|
129
|
+
console.error("No key returned from common JWKS client");
|
|
130
|
+
return callback(new Error("Key not found in common endpoint"));
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const signingKey = keyCommon.getPublicKey();
|
|
134
|
+
console.log("Successfully retrieved signing key from common endpoint");
|
|
135
|
+
callback(null, signingKey);
|
|
136
|
+
}
|
|
137
|
+
catch (keyError) {
|
|
138
|
+
console.error("Error extracting public key from common endpoint:", keyError);
|
|
139
|
+
callback(keyError instanceof Error
|
|
140
|
+
? keyError
|
|
141
|
+
: new Error(String(keyError)));
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (!key) {
|
|
147
|
+
console.error("No key returned from tenant-specific JWKS client");
|
|
148
|
+
return callback(new Error("Key not found"));
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const signingKey = key.getPublicKey();
|
|
152
|
+
console.log("Successfully retrieved signing key from tenant-specific endpoint");
|
|
153
|
+
callback(null, signingKey);
|
|
154
|
+
}
|
|
155
|
+
catch (keyError) {
|
|
156
|
+
console.error("Error extracting public key:", keyError);
|
|
157
|
+
callback(keyError instanceof Error ? keyError : new Error(String(keyError)));
|
|
158
|
+
}
|
|
159
|
+
});
|
|
82
160
|
});
|
|
83
161
|
}
|
|
84
162
|
async function init(name) {
|
|
@@ -117,12 +195,18 @@ async function init(name) {
|
|
|
117
195
|
iss: payload.iss,
|
|
118
196
|
tid: payload.tid,
|
|
119
197
|
ver: payload.ver,
|
|
198
|
+
oid: payload.oid,
|
|
199
|
+
preferred_username: payload.preferred_username,
|
|
120
200
|
});
|
|
121
201
|
}
|
|
122
202
|
}
|
|
123
203
|
catch (decodeError) {
|
|
124
204
|
console.error("Failed to decode token for debugging:", decodeError);
|
|
125
205
|
}
|
|
206
|
+
console.log("Verifying JWT with the following settings:");
|
|
207
|
+
console.log("- Audience:", appId);
|
|
208
|
+
console.log("- Issuer:", `https://login.microsoftonline.com/${tenantId}/v2.0`);
|
|
209
|
+
console.log("- Algorithm: RS256");
|
|
126
210
|
jsonwebtoken_1.default.verify(token, getKey, {
|
|
127
211
|
audience: appId,
|
|
128
212
|
issuer: `https://login.microsoftonline.com/${tenantId}/v2.0`,
|
|
@@ -132,9 +216,19 @@ async function init(name) {
|
|
|
132
216
|
console.error("JWT verification failed:", err);
|
|
133
217
|
console.error("Error name:", err.name);
|
|
134
218
|
console.error("Error message:", err.message);
|
|
219
|
+
if (err.name === "TokenExpiredError") {
|
|
220
|
+
console.error("Token has expired");
|
|
221
|
+
}
|
|
222
|
+
else if (err.name === "JsonWebTokenError") {
|
|
223
|
+
console.error("Invalid token");
|
|
224
|
+
}
|
|
225
|
+
else if (err.name === "NotBeforeError") {
|
|
226
|
+
console.error("Token not active yet");
|
|
227
|
+
}
|
|
135
228
|
return reject(err);
|
|
136
229
|
}
|
|
137
230
|
console.log("JWT verification successful");
|
|
231
|
+
console.log("Verified payload contains oid:", decoded?.oid);
|
|
138
232
|
resolve(decoded);
|
|
139
233
|
});
|
|
140
234
|
});
|