@boxyhq/saml-jackson 1.3.5 → 1.3.7
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/controller/api.d.ts +14 -11
- package/dist/controller/api.js +14 -11
- package/dist/controller/connection/saml.js +26 -15
- package/dist/controller/logout.js +3 -1
- package/dist/controller/oauth.js +9 -24
- package/dist/controller/sp-config.d.ts +6 -5
- package/dist/controller/sp-config.js +29 -15
- package/dist/controller/utils.js +3 -2
- package/dist/db/db.js +17 -5
- package/dist/db/redis.js +17 -10
- package/dist/db/sql/mssql/entity/JacksonIndex.d.ts +7 -0
- package/dist/db/sql/mssql/entity/JacksonIndex.js +41 -0
- package/dist/db/sql/mssql/entity/JacksonStore.d.ts +8 -0
- package/dist/db/sql/mssql/entity/JacksonStore.js +55 -0
- package/dist/db/sql/mssql/entity/JacksonTTL.d.ts +4 -0
- package/dist/db/sql/mssql/entity/JacksonTTL.js +29 -0
- package/dist/db/sql/mssql.d.ts +1 -0
- package/dist/db/sql/mssql.js +46 -0
- package/dist/db/sql/sql.js +12 -6
- package/dist/index.js +19 -3
- package/dist/loadConnection.js +2 -1
- package/dist/saml/x509.d.ts +12 -6
- package/dist/saml/x509.js +46 -5
- package/dist/typings.d.ts +31 -34
- package/migration/mssql/1667949639424-mss_Initial.ts +26 -0
- package/package.json +14 -11
package/dist/controller/api.d.ts
CHANGED
@@ -31,10 +31,6 @@ export declare class ConnectionAPIController implements IConnectionAPIController
|
|
31
31
|
* "description": "SP for hoppscotch.io",
|
32
32
|
* "clientID": "Xq8AJt3yYAxmXizsCWmUBDRiVP1iTC8Y/otnvFIMitk",
|
33
33
|
* "clientSecret": "00e3e11a3426f97d8000000738300009130cd45419c5943",
|
34
|
-
* "certs": {
|
35
|
-
* "publicKey": "-----BEGIN CERTIFICATE-----.......-----END CERTIFICATE-----",
|
36
|
-
* "privateKey": "-----BEGIN PRIVATE KEY-----......-----END PRIVATE KEY-----"
|
37
|
-
* }
|
38
34
|
* }
|
39
35
|
* validationErrorsPost:
|
40
36
|
* description: Please provide rawMetadata or encodedRawMetadata | Please provide a defaultRedirectUrl | Please provide redirectUrl | redirectUrl is invalid | Exceeded maximum number of allowed redirect urls | defaultRedirectUrl is invalid | Please provide tenant | Please provide product | Please provide a friendly name | Description should not exceed 100 characters | Strategy: xxxx not supported | Please provide the clientId from OpenID Provider | Please provide the clientSecret from OpenID Provider | Please provide the discoveryUrl for the OpenID Provider
|
@@ -60,6 +56,11 @@ export declare class ConnectionAPIController implements IConnectionAPIController
|
|
60
56
|
* description: Raw XML metadata
|
61
57
|
* in: formData
|
62
58
|
* type: string
|
59
|
+
* metadataUrlParamPost:
|
60
|
+
* name: metadataUrl
|
61
|
+
* description: URL containing raw XML metadata
|
62
|
+
* in: formData
|
63
|
+
* type: string
|
63
64
|
* defaultRedirectUrlParamPost:
|
64
65
|
* name: defaultRedirectUrl
|
65
66
|
* description: The redirect URL to use in the IdP login flow
|
@@ -115,6 +116,7 @@ export declare class ConnectionAPIController implements IConnectionAPIController
|
|
115
116
|
* - $ref: '#/parameters/descriptionParamPost'
|
116
117
|
* - $ref: '#/parameters/encodedRawMetadataParamPost'
|
117
118
|
* - $ref: '#/parameters/rawMetadataParamPost'
|
119
|
+
* - $ref: '#/parameters/metadataUrlParamPost'
|
118
120
|
* - $ref: '#/parameters/defaultRedirectUrlParamPost'
|
119
121
|
* - $ref: '#/parameters/redirectUrlParamPost'
|
120
122
|
* - $ref: '#/parameters/tenantParamPost'
|
@@ -145,6 +147,7 @@ export declare class ConnectionAPIController implements IConnectionAPIController
|
|
145
147
|
* - $ref: '#/parameters/descriptionParamPost'
|
146
148
|
* - $ref: '#/parameters/encodedRawMetadataParamPost'
|
147
149
|
* - $ref: '#/parameters/rawMetadataParamPost'
|
150
|
+
* - $ref: '#/parameters/metadataUrlParamPost'
|
148
151
|
* - $ref: '#/parameters/defaultRedirectUrlParamPost'
|
149
152
|
* - $ref: '#/parameters/redirectUrlParamPost'
|
150
153
|
* - $ref: '#/parameters/tenantParamPost'
|
@@ -203,6 +206,11 @@ export declare class ConnectionAPIController implements IConnectionAPIController
|
|
203
206
|
* description: Raw XML metadata
|
204
207
|
* in: formData
|
205
208
|
* type: string
|
209
|
+
* metadataUrlParamPatch:
|
210
|
+
* name: metadataUrl
|
211
|
+
* description: URL containing raw XML metadata
|
212
|
+
* in: formData
|
213
|
+
* type: string
|
206
214
|
* oidcDiscoveryUrlPatch:
|
207
215
|
* name: oidcDiscoveryUrl
|
208
216
|
* description: well-known URL where the OpenID Provider configuration is exposed
|
@@ -256,6 +264,7 @@ export declare class ConnectionAPIController implements IConnectionAPIController
|
|
256
264
|
* - $ref: '#/parameters/descriptionParamPatch'
|
257
265
|
* - $ref: '#/parameters/encodedRawMetadataParamPatch'
|
258
266
|
* - $ref: '#/parameters/rawMetadataParamPatch'
|
267
|
+
* - $ref: '#/parameters/metadataUrlParamPatch'
|
259
268
|
* - $ref: '#/parameters/defaultRedirectUrlParamPatch'
|
260
269
|
* - $ref: '#/parameters/redirectUrlParamPatch'
|
261
270
|
* - $ref: '#/parameters/tenantParamPatch'
|
@@ -282,6 +291,7 @@ export declare class ConnectionAPIController implements IConnectionAPIController
|
|
282
291
|
* - $ref: '#/parameters/descriptionParamPatch'
|
283
292
|
* - $ref: '#/parameters/encodedRawMetadataParamPatch'
|
284
293
|
* - $ref: '#/parameters/rawMetadataParamPatch'
|
294
|
+
* - $ref: '#/parameters/metadataUrlParamPatch'
|
285
295
|
* - $ref: '#/parameters/oidcDiscoveryUrlPatch'
|
286
296
|
* - $ref: '#/parameters/oidcClientIdPatch'
|
287
297
|
* - $ref: '#/parameters/oidcClientSecretPatch'
|
@@ -362,9 +372,6 @@ export declare class ConnectionAPIController implements IConnectionAPIController
|
|
362
372
|
* idpMetadata:
|
363
373
|
* type: object
|
364
374
|
* description: SAML IdP metadata
|
365
|
-
* certs:
|
366
|
-
* type: object
|
367
|
-
* description: Certs generated for SAML connection
|
368
375
|
* oidcProvider:
|
369
376
|
* type: object
|
370
377
|
* description: OIDC IdP metadata
|
@@ -435,10 +442,6 @@ export declare class ConnectionAPIController implements IConnectionAPIController
|
|
435
442
|
* "description": "SP for hoppscotch.io",
|
436
443
|
* "clientID": "Xq8AJt3yYAxmXizsCWmUBDRiVP1iTC8Y/otnvFIMitk",
|
437
444
|
* "clientSecret": "00e3e11a3426f97d8000000738300009130cd45419c5943",
|
438
|
-
* "certs": {
|
439
|
-
* "publicKey": "-----BEGIN CERTIFICATE-----.......-----END CERTIFICATE-----",
|
440
|
-
* "privateKey": "-----BEGIN PRIVATE KEY-----......-----END PRIVATE KEY-----"
|
441
|
-
* }
|
442
445
|
* }
|
443
446
|
* '400':
|
444
447
|
* $ref: '#/responses/400Get'
|
package/dist/controller/api.js
CHANGED
@@ -72,10 +72,6 @@ class ConnectionAPIController {
|
|
72
72
|
* "description": "SP for hoppscotch.io",
|
73
73
|
* "clientID": "Xq8AJt3yYAxmXizsCWmUBDRiVP1iTC8Y/otnvFIMitk",
|
74
74
|
* "clientSecret": "00e3e11a3426f97d8000000738300009130cd45419c5943",
|
75
|
-
* "certs": {
|
76
|
-
* "publicKey": "-----BEGIN CERTIFICATE-----.......-----END CERTIFICATE-----",
|
77
|
-
* "privateKey": "-----BEGIN PRIVATE KEY-----......-----END PRIVATE KEY-----"
|
78
|
-
* }
|
79
75
|
* }
|
80
76
|
* validationErrorsPost:
|
81
77
|
* description: Please provide rawMetadata or encodedRawMetadata | Please provide a defaultRedirectUrl | Please provide redirectUrl | redirectUrl is invalid | Exceeded maximum number of allowed redirect urls | defaultRedirectUrl is invalid | Please provide tenant | Please provide product | Please provide a friendly name | Description should not exceed 100 characters | Strategy: xxxx not supported | Please provide the clientId from OpenID Provider | Please provide the clientSecret from OpenID Provider | Please provide the discoveryUrl for the OpenID Provider
|
@@ -101,6 +97,11 @@ class ConnectionAPIController {
|
|
101
97
|
* description: Raw XML metadata
|
102
98
|
* in: formData
|
103
99
|
* type: string
|
100
|
+
* metadataUrlParamPost:
|
101
|
+
* name: metadataUrl
|
102
|
+
* description: URL containing raw XML metadata
|
103
|
+
* in: formData
|
104
|
+
* type: string
|
104
105
|
* defaultRedirectUrlParamPost:
|
105
106
|
* name: defaultRedirectUrl
|
106
107
|
* description: The redirect URL to use in the IdP login flow
|
@@ -156,6 +157,7 @@ class ConnectionAPIController {
|
|
156
157
|
* - $ref: '#/parameters/descriptionParamPost'
|
157
158
|
* - $ref: '#/parameters/encodedRawMetadataParamPost'
|
158
159
|
* - $ref: '#/parameters/rawMetadataParamPost'
|
160
|
+
* - $ref: '#/parameters/metadataUrlParamPost'
|
159
161
|
* - $ref: '#/parameters/defaultRedirectUrlParamPost'
|
160
162
|
* - $ref: '#/parameters/redirectUrlParamPost'
|
161
163
|
* - $ref: '#/parameters/tenantParamPost'
|
@@ -186,6 +188,7 @@ class ConnectionAPIController {
|
|
186
188
|
* - $ref: '#/parameters/descriptionParamPost'
|
187
189
|
* - $ref: '#/parameters/encodedRawMetadataParamPost'
|
188
190
|
* - $ref: '#/parameters/rawMetadataParamPost'
|
191
|
+
* - $ref: '#/parameters/metadataUrlParamPost'
|
189
192
|
* - $ref: '#/parameters/defaultRedirectUrlParamPost'
|
190
193
|
* - $ref: '#/parameters/redirectUrlParamPost'
|
191
194
|
* - $ref: '#/parameters/tenantParamPost'
|
@@ -262,6 +265,11 @@ class ConnectionAPIController {
|
|
262
265
|
* description: Raw XML metadata
|
263
266
|
* in: formData
|
264
267
|
* type: string
|
268
|
+
* metadataUrlParamPatch:
|
269
|
+
* name: metadataUrl
|
270
|
+
* description: URL containing raw XML metadata
|
271
|
+
* in: formData
|
272
|
+
* type: string
|
265
273
|
* oidcDiscoveryUrlPatch:
|
266
274
|
* name: oidcDiscoveryUrl
|
267
275
|
* description: well-known URL where the OpenID Provider configuration is exposed
|
@@ -315,6 +323,7 @@ class ConnectionAPIController {
|
|
315
323
|
* - $ref: '#/parameters/descriptionParamPatch'
|
316
324
|
* - $ref: '#/parameters/encodedRawMetadataParamPatch'
|
317
325
|
* - $ref: '#/parameters/rawMetadataParamPatch'
|
326
|
+
* - $ref: '#/parameters/metadataUrlParamPatch'
|
318
327
|
* - $ref: '#/parameters/defaultRedirectUrlParamPatch'
|
319
328
|
* - $ref: '#/parameters/redirectUrlParamPatch'
|
320
329
|
* - $ref: '#/parameters/tenantParamPatch'
|
@@ -341,6 +350,7 @@ class ConnectionAPIController {
|
|
341
350
|
* - $ref: '#/parameters/descriptionParamPatch'
|
342
351
|
* - $ref: '#/parameters/encodedRawMetadataParamPatch'
|
343
352
|
* - $ref: '#/parameters/rawMetadataParamPatch'
|
353
|
+
* - $ref: '#/parameters/metadataUrlParamPatch'
|
344
354
|
* - $ref: '#/parameters/oidcDiscoveryUrlPatch'
|
345
355
|
* - $ref: '#/parameters/oidcClientIdPatch'
|
346
356
|
* - $ref: '#/parameters/oidcClientSecretPatch'
|
@@ -431,9 +441,6 @@ class ConnectionAPIController {
|
|
431
441
|
* idpMetadata:
|
432
442
|
* type: object
|
433
443
|
* description: SAML IdP metadata
|
434
|
-
* certs:
|
435
|
-
* type: object
|
436
|
-
* description: Certs generated for SAML connection
|
437
444
|
* oidcProvider:
|
438
445
|
* type: object
|
439
446
|
* description: OIDC IdP metadata
|
@@ -549,10 +556,6 @@ class ConnectionAPIController {
|
|
549
556
|
* "description": "SP for hoppscotch.io",
|
550
557
|
* "clientID": "Xq8AJt3yYAxmXizsCWmUBDRiVP1iTC8Y/otnvFIMitk",
|
551
558
|
* "clientSecret": "00e3e11a3426f97d8000000738300009130cd45419c5943",
|
552
|
-
* "certs": {
|
553
|
-
* "publicKey": "-----BEGIN CERTIFICATE-----.......-----END CERTIFICATE-----",
|
554
|
-
* "privateKey": "-----BEGIN PRIVATE KEY-----......-----END PRIVATE KEY-----"
|
555
|
-
* }
|
556
559
|
* }
|
557
560
|
* '400':
|
558
561
|
* $ref: '#/responses/400Get'
|
@@ -50,11 +50,24 @@ const crypto_1 = __importDefault(require("crypto"));
|
|
50
50
|
const dbutils = __importStar(require("../../db/utils"));
|
51
51
|
const utils_1 = require("../utils");
|
52
52
|
const saml20_1 = __importDefault(require("@boxyhq/saml20"));
|
53
|
-
const x509_1 = __importDefault(require("../../saml/x509"));
|
54
53
|
const error_1 = require("../error");
|
54
|
+
const axios_1 = __importDefault(require("axios"));
|
55
|
+
function fetchMetadata(resource) {
|
56
|
+
return __awaiter(this, void 0, void 0, function* () {
|
57
|
+
const response = yield (0, axios_1.default)(resource, {
|
58
|
+
maxContentLength: 1000000,
|
59
|
+
maxBodyLength: 1000000,
|
60
|
+
timeout: 8000,
|
61
|
+
}).catch((error) => {
|
62
|
+
var _a;
|
63
|
+
throw new error_1.JacksonError("Couldn't fetch XML data", ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) || 400);
|
64
|
+
});
|
65
|
+
return response.data;
|
66
|
+
});
|
67
|
+
}
|
55
68
|
const saml = {
|
56
69
|
create: (body, connectionStore) => __awaiter(void 0, void 0, void 0, function* () {
|
57
|
-
const { encodedRawMetadata, rawMetadata, defaultRedirectUrl, redirectUrl, tenant, product, name, description, } = body;
|
70
|
+
const { encodedRawMetadata, rawMetadata, defaultRedirectUrl, redirectUrl, tenant, product, name, description, metadataUrl, } = body;
|
58
71
|
const forceAuthn = body.forceAuthn == 'true' || body.forceAuthn == true;
|
59
72
|
let connectionClientSecret;
|
60
73
|
(0, utils_1.validateSSOConnection)(body, 'saml');
|
@@ -70,12 +83,14 @@ const saml = {
|
|
70
83
|
clientID: '',
|
71
84
|
clientSecret: '',
|
72
85
|
forceAuthn,
|
86
|
+
metadataUrl,
|
73
87
|
};
|
74
|
-
let
|
88
|
+
let metadata = rawMetadata;
|
75
89
|
if (encodedRawMetadata) {
|
76
|
-
|
90
|
+
metadata = Buffer.from(encodedRawMetadata, 'base64').toString();
|
77
91
|
}
|
78
|
-
|
92
|
+
metadata = metadataUrl ? yield fetchMetadata(metadataUrl) : metadata;
|
93
|
+
const idpMetadata = (yield saml20_1.default.parseMetadata(metadata, {}));
|
79
94
|
if (!idpMetadata.entityID) {
|
80
95
|
throw new error_1.JacksonError("Couldn't parse EntityID from SAML metadata", 400);
|
81
96
|
}
|
@@ -86,12 +101,7 @@ const saml = {
|
|
86
101
|
}
|
87
102
|
idpMetadata.provider = providerName ? providerName : 'Unknown';
|
88
103
|
record.clientID = dbutils.keyDigest(dbutils.keyFromParts(tenant, product, idpMetadata.entityID));
|
89
|
-
const certs = yield x509_1.default.generate();
|
90
|
-
if (!certs) {
|
91
|
-
throw new error_1.JacksonError('Error generating x509 certs');
|
92
|
-
}
|
93
104
|
record.idpMetadata = idpMetadata;
|
94
|
-
record.certs = certs;
|
95
105
|
const exists = yield connectionStore.get(record.clientID);
|
96
106
|
if (exists) {
|
97
107
|
connectionClientSecret = exists.clientSecret;
|
@@ -113,7 +123,7 @@ const saml = {
|
|
113
123
|
update: (body, connectionStore, connectionsGetter) => __awaiter(void 0, void 0, void 0, function* () {
|
114
124
|
const { encodedRawMetadata, // could be empty
|
115
125
|
rawMetadata, // could be empty
|
116
|
-
defaultRedirectUrl, redirectUrl, name, description, forceAuthn = false } = body, clientInfo = __rest(body, ["encodedRawMetadata", "rawMetadata", "defaultRedirectUrl", "redirectUrl", "name", "description", "forceAuthn"]);
|
126
|
+
defaultRedirectUrl, redirectUrl, name, description, forceAuthn = false, metadataUrl } = body, clientInfo = __rest(body, ["encodedRawMetadata", "rawMetadata", "defaultRedirectUrl", "redirectUrl", "name", "description", "forceAuthn", "metadataUrl"]);
|
117
127
|
if (!(clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientID)) {
|
118
128
|
throw new error_1.JacksonError('Please provide clientID', 400);
|
119
129
|
}
|
@@ -135,13 +145,14 @@ const saml = {
|
|
135
145
|
if (_savedConnection.clientSecret !== (clientInfo === null || clientInfo === void 0 ? void 0 : clientInfo.clientSecret)) {
|
136
146
|
throw new error_1.JacksonError('clientSecret mismatch', 400);
|
137
147
|
}
|
138
|
-
let
|
148
|
+
let metadata = rawMetadata;
|
139
149
|
if (encodedRawMetadata) {
|
140
|
-
|
150
|
+
metadata = Buffer.from(encodedRawMetadata, 'base64').toString();
|
141
151
|
}
|
152
|
+
metadata = metadataUrl ? yield fetchMetadata(metadataUrl) : metadata;
|
142
153
|
let newMetadata;
|
143
|
-
if (
|
144
|
-
newMetadata = yield saml20_1.default.parseMetadata(
|
154
|
+
if (metadata) {
|
155
|
+
newMetadata = yield saml20_1.default.parseMetadata(metadata, {});
|
145
156
|
if (!newMetadata.entityID) {
|
146
157
|
throw new error_1.JacksonError("Couldn't parse EntityID from SAML metadata", 400);
|
147
158
|
}
|
@@ -46,6 +46,7 @@ const saml20_1 = __importDefault(require("@boxyhq/saml20"));
|
|
46
46
|
const error_1 = require("./error");
|
47
47
|
const redirect = __importStar(require("./oauth/redirect"));
|
48
48
|
const utils_1 = require("./utils");
|
49
|
+
const x509_1 = require("../saml/x509");
|
49
50
|
const deflateRawAsync = (0, util_1.promisify)(zlib_1.deflateRaw);
|
50
51
|
const relayStatePrefix = 'boxyhq_jackson_';
|
51
52
|
const logoutXPath = "/*[local-name(.)='LogoutRequest']";
|
@@ -72,7 +73,8 @@ class LogoutController {
|
|
72
73
|
if (!samlConnection) {
|
73
74
|
throw new error_1.JacksonError('SAML connection not found.', 403);
|
74
75
|
}
|
75
|
-
const { idpMetadata: { slo, provider },
|
76
|
+
const { idpMetadata: { slo, provider }, } = samlConnection;
|
77
|
+
const { privateKey, publicKey } = yield (0, x509_1.getDefaultCertificate)();
|
76
78
|
if ('redirectUrl' in slo === false && 'postUrl' in slo === false) {
|
77
79
|
throw new error_1.JacksonError(`${provider} doesn't support SLO or disabled by IdP.`, 400);
|
78
80
|
}
|
package/dist/controller/oauth.js
CHANGED
@@ -50,7 +50,7 @@ const allowed = __importStar(require("./oauth/allowed"));
|
|
50
50
|
const codeVerifier = __importStar(require("./oauth/code-verifier"));
|
51
51
|
const redirect = __importStar(require("./oauth/redirect"));
|
52
52
|
const utils_1 = require("./utils");
|
53
|
-
const x509_1 =
|
53
|
+
const x509_1 = require("../saml/x509");
|
54
54
|
const deflateRawAsync = (0, util_1.promisify)(zlib_1.deflateRaw);
|
55
55
|
const validateSAMLResponse = (rawResponse, validateOpts) => __awaiter(void 0, void 0, void 0, function* () {
|
56
56
|
const profile = yield saml20_1.default.validate(rawResponse, validateOpts);
|
@@ -61,6 +61,8 @@ const validateSAMLResponse = (rawResponse, validateOpts) => __awaiter(void 0, vo
|
|
61
61
|
if (!profile.claims.id && profile.claims.email) {
|
62
62
|
profile.claims.id = crypto_1.default.createHash('sha256').update(profile.claims.email).digest('hex');
|
63
63
|
}
|
64
|
+
// we'll send a ripemd160 hash of the id, this can be used in the case of email missing it can be used as the local part
|
65
|
+
profile.claims.idHash = dbutils.keyDigest(profile.claims.id);
|
64
66
|
}
|
65
67
|
return profile;
|
66
68
|
});
|
@@ -312,27 +314,8 @@ class OAuthController {
|
|
312
314
|
}),
|
313
315
|
};
|
314
316
|
}
|
317
|
+
const cert = yield (0, x509_1.getDefaultCertificate)();
|
315
318
|
try {
|
316
|
-
const { validTo } = new crypto_1.default.X509Certificate(connection.certs.publicKey);
|
317
|
-
const isValidExpiry = validTo != 'Bad time value' && new Date(validTo) > new Date();
|
318
|
-
if (!isValidExpiry) {
|
319
|
-
const certs = yield x509_1.default.generate();
|
320
|
-
connection.certs = certs;
|
321
|
-
if (certs) {
|
322
|
-
yield this.connectionStore.put(connection.clientID, connection, {
|
323
|
-
// secondary index on entityID
|
324
|
-
name: utils_1.IndexNames.EntityID,
|
325
|
-
value: connection.idpMetadata.entityID,
|
326
|
-
}, {
|
327
|
-
// secondary index on tenant + product
|
328
|
-
name: utils_1.IndexNames.TenantProduct,
|
329
|
-
value: dbutils.keyFromParts(connection.tenant, connection.product),
|
330
|
-
});
|
331
|
-
}
|
332
|
-
else {
|
333
|
-
throw new Error('Error generating x509 certs');
|
334
|
-
}
|
335
|
-
}
|
336
319
|
// We will get undefined or Space delimited, case sensitive list of ASCII string values in prompt
|
337
320
|
// If login is one of the value in prompt we want to enable forceAuthn
|
338
321
|
// Else use the saml connection forceAuthn value
|
@@ -341,8 +324,8 @@ class OAuthController {
|
|
341
324
|
ssoUrl,
|
342
325
|
entityID: this.opts.samlAudience,
|
343
326
|
callbackUrl: this.opts.externalUrl + this.opts.samlPath,
|
344
|
-
signingKey:
|
345
|
-
publicKey:
|
327
|
+
signingKey: cert.privateKey,
|
328
|
+
publicKey: cert.publicKey,
|
346
329
|
forceAuthn: promptOptions.length > 0 ? true : !!connection.forceAuthn,
|
347
330
|
});
|
348
331
|
}
|
@@ -544,10 +527,11 @@ class OAuthController {
|
|
544
527
|
if (!samlConnection) {
|
545
528
|
throw new error_1.JacksonError('SAML connection not found.', 403);
|
546
529
|
}
|
530
|
+
const { privateKey } = yield (0, x509_1.getDefaultCertificate)();
|
547
531
|
const validateOpts = {
|
548
532
|
thumbprint: samlConnection.idpMetadata.thumbprint,
|
549
533
|
audience: this.opts.samlAudience,
|
550
|
-
privateKey
|
534
|
+
privateKey,
|
551
535
|
};
|
552
536
|
if (session &&
|
553
537
|
session.redirect_uri &&
|
@@ -622,6 +606,7 @@ class OAuthController {
|
|
622
606
|
const idTokenClaims = tokenSet.claims();
|
623
607
|
const userinfo = yield oidcClient.userinfo(tokenSet);
|
624
608
|
profile.claims.id = idTokenClaims.sub;
|
609
|
+
profile.claims.idHash = dbutils.keyDigest(idTokenClaims.sub);
|
625
610
|
profile.claims.email = (_a = idTokenClaims.email) !== null && _a !== void 0 ? _a : userinfo.email;
|
626
611
|
profile.claims.firstName = (_b = idTokenClaims.given_name) !== null && _b !== void 0 ? _b : userinfo.given_name;
|
627
612
|
profile.claims.lastName = (_c = idTokenClaims.family_name) !== null && _c !== void 0 ? _c : userinfo.family_name;
|
@@ -1,21 +1,22 @@
|
|
1
1
|
import type { JacksonOption } from '../typings';
|
2
2
|
export declare class SPSAMLConfig {
|
3
3
|
private opts;
|
4
|
-
|
4
|
+
private getDefaultCertificate;
|
5
|
+
constructor(opts: JacksonOption, getDefaultCertificate: any);
|
5
6
|
private get acsUrl();
|
6
7
|
private get entityId();
|
7
8
|
private get responseSigned();
|
8
9
|
private get assertionSignature();
|
9
10
|
private get signatureAlgorithm();
|
10
|
-
|
11
|
-
get(): {
|
11
|
+
get(): Promise<{
|
12
12
|
acsUrl: string;
|
13
13
|
entityId: string;
|
14
14
|
response: string;
|
15
15
|
assertionSignature: string;
|
16
16
|
signatureAlgorithm: string;
|
17
|
-
|
18
|
-
|
17
|
+
publicKey: string;
|
18
|
+
publicKeyString: string;
|
19
|
+
}>;
|
19
20
|
toMarkdown(): string;
|
20
21
|
toHTML(): string;
|
21
22
|
}
|
@@ -1,11 +1,25 @@
|
|
1
1
|
"use strict";
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9
|
+
});
|
10
|
+
};
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
13
|
+
};
|
2
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
15
|
exports.SPSAMLConfig = void 0;
|
4
16
|
const marked_1 = require("marked");
|
17
|
+
const saml20_1 = __importDefault(require("@boxyhq/saml20"));
|
5
18
|
// Service Provider SAML Configuration
|
6
19
|
class SPSAMLConfig {
|
7
|
-
constructor(opts) {
|
20
|
+
constructor(opts, getDefaultCertificate) {
|
8
21
|
this.opts = opts;
|
22
|
+
this.getDefaultCertificate = getDefaultCertificate;
|
9
23
|
}
|
10
24
|
get acsUrl() {
|
11
25
|
return `${this.opts.externalUrl}${this.opts.samlPath}`;
|
@@ -22,18 +36,19 @@ class SPSAMLConfig {
|
|
22
36
|
get signatureAlgorithm() {
|
23
37
|
return 'RSA-SHA256';
|
24
38
|
}
|
25
|
-
get assertionEncryption() {
|
26
|
-
return 'Unencrypted';
|
27
|
-
}
|
28
39
|
get() {
|
29
|
-
return {
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
40
|
+
return __awaiter(this, void 0, void 0, function* () {
|
41
|
+
const cert = yield this.getDefaultCertificate();
|
42
|
+
return {
|
43
|
+
acsUrl: this.acsUrl,
|
44
|
+
entityId: this.entityId,
|
45
|
+
response: this.responseSigned,
|
46
|
+
assertionSignature: this.assertionSignature,
|
47
|
+
signatureAlgorithm: this.signatureAlgorithm,
|
48
|
+
publicKey: cert.publicKey,
|
49
|
+
publicKeyString: saml20_1.default.stripCertHeaderAndFooter(cert.publicKey),
|
50
|
+
};
|
51
|
+
});
|
37
52
|
}
|
38
53
|
toMarkdown() {
|
39
54
|
return markdownTemplate
|
@@ -41,8 +56,7 @@ class SPSAMLConfig {
|
|
41
56
|
.replace('{{entityId}}', this.entityId)
|
42
57
|
.replace('{{responseSigned}}', this.responseSigned)
|
43
58
|
.replace('{{assertionSignature}}', this.assertionSignature)
|
44
|
-
.replace('{{signatureAlgorithm}}', this.signatureAlgorithm)
|
45
|
-
.replace('{{assertionEncryption}}', this.assertionEncryption);
|
59
|
+
.replace('{{signatureAlgorithm}}', this.signatureAlgorithm);
|
46
60
|
}
|
47
61
|
toHTML() {
|
48
62
|
return marked_1.marked.parse(this.toMarkdown());
|
@@ -70,5 +84,5 @@ Your Identity Provider (IdP) will ask for the following information while config
|
|
70
84
|
{{signatureAlgorithm}}
|
71
85
|
|
72
86
|
**Assertion Encryption** <br />
|
73
|
-
|
87
|
+
If you want to encrypt the assertion, you can download our [public certificate](/.well-known/saml.cer). Otherwise select the 'Unencrypted' option.
|
74
88
|
`;
|
package/dist/controller/utils.js
CHANGED
@@ -128,12 +128,13 @@ const validateSSOConnection = (body, strategy) => {
|
|
128
128
|
const oidcDiscoveryUrl = 'oidcDiscoveryUrl' in body ? body.oidcDiscoveryUrl : undefined;
|
129
129
|
const oidcClientId = 'oidcClientId' in body ? body.oidcClientId : undefined;
|
130
130
|
const oidcClientSecret = 'oidcClientSecret' in body ? body.oidcClientSecret : undefined;
|
131
|
+
const metadataUrl = 'metadataUrl' in body ? body.metadataUrl : undefined;
|
131
132
|
if (strategy !== 'saml' && strategy !== 'oidc') {
|
132
133
|
throw new error_1.JacksonError(`Strategy: ${strategy} not supported`, 400);
|
133
134
|
}
|
134
135
|
if (strategy === 'saml') {
|
135
|
-
if (!rawMetadata && !encodedRawMetadata) {
|
136
|
-
throw new error_1.JacksonError('Please provide rawMetadata or encodedRawMetadata', 400);
|
136
|
+
if (!rawMetadata && !encodedRawMetadata && !metadataUrl) {
|
137
|
+
throw new error_1.JacksonError('Please provide rawMetadata or encodedRawMetadata or metadataUrl', 400);
|
137
138
|
}
|
138
139
|
}
|
139
140
|
if (strategy === 'oidc') {
|
package/dist/db/db.js
CHANGED
@@ -47,6 +47,9 @@ const JacksonTTL_1 = require("./sql/entity/JacksonTTL");
|
|
47
47
|
const JacksonStore_2 = require("./planetscale/entity/JacksonStore");
|
48
48
|
const JacksonIndex_2 = require("./planetscale/entity/JacksonIndex");
|
49
49
|
const JacksonTTL_2 = require("./planetscale/entity/JacksonTTL");
|
50
|
+
const JacksonStore_3 = require("./sql/mssql/entity/JacksonStore");
|
51
|
+
const JacksonIndex_3 = require("./sql/mssql/entity/JacksonIndex");
|
52
|
+
const JacksonTTL_3 = require("./sql/mssql/entity/JacksonTTL");
|
50
53
|
const decrypt = (res, encryptionKey) => {
|
51
54
|
if (res.iv && res.tag) {
|
52
55
|
return JSON.parse(encrypter.decrypt(res.value, res.iv, res.tag, encryptionKey));
|
@@ -113,11 +116,20 @@ exports.default = {
|
|
113
116
|
case 'redis':
|
114
117
|
return new DB(yield redis_1.default.new(options), encryptionKey);
|
115
118
|
case 'sql':
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
119
|
+
switch (options.type) {
|
120
|
+
case 'mssql':
|
121
|
+
return new DB(yield sql_1.default.new(options, {
|
122
|
+
JacksonStore: JacksonStore_3.JacksonStore,
|
123
|
+
JacksonIndex: JacksonIndex_3.JacksonIndex,
|
124
|
+
JacksonTTL: JacksonTTL_3.JacksonTTL,
|
125
|
+
}), encryptionKey);
|
126
|
+
default:
|
127
|
+
return new DB(yield sql_1.default.new(options, {
|
128
|
+
JacksonStore: JacksonStore_1.JacksonStore,
|
129
|
+
JacksonIndex: JacksonIndex_1.JacksonIndex,
|
130
|
+
JacksonTTL: JacksonTTL_1.JacksonTTL,
|
131
|
+
}), encryptionKey);
|
132
|
+
}
|
121
133
|
case 'planetscale':
|
122
134
|
return new DB(yield sql_1.default.new(options, {
|
123
135
|
JacksonStore: JacksonStore_2.JacksonStore,
|
package/dist/db/redis.js
CHANGED
@@ -54,7 +54,7 @@ class Redis {
|
|
54
54
|
};
|
55
55
|
}
|
56
56
|
this.client = redis.createClient(opts);
|
57
|
-
this.client.on('error', (err) => console.
|
57
|
+
this.client.on('error', (err) => console.info('Redis Client Error', err));
|
58
58
|
yield this.client.connect();
|
59
59
|
return this;
|
60
60
|
});
|
@@ -69,7 +69,7 @@ class Redis {
|
|
69
69
|
});
|
70
70
|
}
|
71
71
|
getAll(namespace, pageOffset, pageLimit) {
|
72
|
-
var e_1,
|
72
|
+
var _a, e_1, _b, _c;
|
73
73
|
return __awaiter(this, void 0, void 0, function* () {
|
74
74
|
const offsetAndLimitValueCheck = !dbutils.isNumeric(pageOffset) && !dbutils.isNumeric(pageLimit);
|
75
75
|
let take = Number(offsetAndLimitValueCheck ? this.options.pageLimit : pageLimit);
|
@@ -79,21 +79,28 @@ class Redis {
|
|
79
79
|
let count = 0;
|
80
80
|
take += skip;
|
81
81
|
try {
|
82
|
-
for (var
|
83
|
-
|
84
|
-
|
85
|
-
|
82
|
+
for (var _d = true, _e = __asyncValues(this.client.zScanIterator(dbutils.keyFromParts(dbutils.createdAtPrefix, namespace), Math.min(take, 1000))), _f; _f = yield _e.next(), _a = _f.done, !_a;) {
|
83
|
+
_c = _f.value;
|
84
|
+
_d = false;
|
85
|
+
try {
|
86
|
+
const { score, value } = _c;
|
87
|
+
if (count >= take) {
|
88
|
+
break;
|
89
|
+
}
|
90
|
+
if (count >= skip) {
|
91
|
+
keyArray.push(dbutils.keyFromParts(namespace, value));
|
92
|
+
}
|
93
|
+
count++;
|
86
94
|
}
|
87
|
-
|
88
|
-
|
95
|
+
finally {
|
96
|
+
_d = true;
|
89
97
|
}
|
90
|
-
count++;
|
91
98
|
}
|
92
99
|
}
|
93
100
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
94
101
|
finally {
|
95
102
|
try {
|
96
|
-
if (
|
103
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
97
104
|
}
|
98
105
|
finally { if (e_1) throw e_1.error; }
|
99
106
|
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
7
|
+
};
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
9
|
+
exports.JacksonIndex = void 0;
|
10
|
+
const JacksonStore_1 = require("./JacksonStore");
|
11
|
+
const typeorm_1 = require("typeorm");
|
12
|
+
let JacksonIndex = class JacksonIndex {
|
13
|
+
};
|
14
|
+
__decorate([
|
15
|
+
(0, typeorm_1.PrimaryGeneratedColumn)()
|
16
|
+
], JacksonIndex.prototype, "id", void 0);
|
17
|
+
__decorate([
|
18
|
+
(0, typeorm_1.Index)('_jackson_index_key'),
|
19
|
+
(0, typeorm_1.Column)({
|
20
|
+
type: 'varchar',
|
21
|
+
length: 1500,
|
22
|
+
})
|
23
|
+
], JacksonIndex.prototype, "key", void 0);
|
24
|
+
__decorate([
|
25
|
+
(0, typeorm_1.Column)({
|
26
|
+
type: 'varchar',
|
27
|
+
length: 1500,
|
28
|
+
})
|
29
|
+
], JacksonIndex.prototype, "storeKey", void 0);
|
30
|
+
__decorate([
|
31
|
+
(0, typeorm_1.ManyToOne)(() => JacksonStore_1.JacksonStore, undefined, {
|
32
|
+
//inverseSide: 'in',
|
33
|
+
eager: true,
|
34
|
+
onDelete: 'CASCADE',
|
35
|
+
})
|
36
|
+
], JacksonIndex.prototype, "store", void 0);
|
37
|
+
JacksonIndex = __decorate([
|
38
|
+
(0, typeorm_1.Index)('_jackson_index_key_store', ['key', 'storeKey']),
|
39
|
+
(0, typeorm_1.Entity)()
|
40
|
+
], JacksonIndex);
|
41
|
+
exports.JacksonIndex = JacksonIndex;
|