@boxyhq/saml-jackson 1.3.5 → 1.3.7
Sign up to get free protection for your applications and to get access to all the features.
- 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;
|