@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.
@@ -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'
@@ -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 metaData = rawMetadata;
88
+ let metadata = rawMetadata;
75
89
  if (encodedRawMetadata) {
76
- metaData = Buffer.from(encodedRawMetadata, 'base64').toString();
90
+ metadata = Buffer.from(encodedRawMetadata, 'base64').toString();
77
91
  }
78
- const idpMetadata = (yield saml20_1.default.parseMetadata(metaData, {}));
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 metaData = rawMetadata;
148
+ let metadata = rawMetadata;
139
149
  if (encodedRawMetadata) {
140
- metaData = Buffer.from(encodedRawMetadata, 'base64').toString();
150
+ metadata = Buffer.from(encodedRawMetadata, 'base64').toString();
141
151
  }
152
+ metadata = metadataUrl ? yield fetchMetadata(metadataUrl) : metadata;
142
153
  let newMetadata;
143
- if (metaData) {
144
- newMetadata = yield saml20_1.default.parseMetadata(metaData, {});
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 }, certs: { privateKey, publicKey }, } = samlConnection;
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
  }
@@ -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 = __importDefault(require("../saml/x509"));
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: connection.certs.privateKey,
345
- publicKey: connection.certs.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: samlConnection.certs.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
- constructor(opts: JacksonOption);
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
- private get assertionEncryption();
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
- assertionEncryption: string;
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
- acsUrl: this.acsUrl,
31
- entityId: this.entityId,
32
- response: this.responseSigned,
33
- assertionSignature: this.assertionSignature,
34
- signatureAlgorithm: this.signatureAlgorithm,
35
- assertionEncryption: this.assertionEncryption,
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
- {{assertionEncryption}}
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
  `;
@@ -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
- return new DB(yield sql_1.default.new(options, {
117
- JacksonStore: JacksonStore_1.JacksonStore,
118
- JacksonIndex: JacksonIndex_1.JacksonIndex,
119
- JacksonTTL: JacksonTTL_1.JacksonTTL,
120
- }), encryptionKey);
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.log('Redis Client Error', err));
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, _a;
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 _b = __asyncValues(this.client.zScanIterator(dbutils.keyFromParts(dbutils.createdAtPrefix, namespace), Math.min(take, 1000))), _c; _c = yield _b.next(), !_c.done;) {
83
- const { score, value } = _c.value;
84
- if (count >= take) {
85
- break;
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
- if (count >= skip) {
88
- keyArray.push(dbutils.keyFromParts(namespace, value));
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 (_c && !_c.done && (_a = _b.return)) yield _a.call(_b);
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,7 @@
1
+ import { JacksonStore } from './JacksonStore';
2
+ export declare class JacksonIndex {
3
+ id: number;
4
+ key: string;
5
+ storeKey: string;
6
+ store?: JacksonStore;
7
+ }
@@ -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;
@@ -0,0 +1,8 @@
1
+ export declare class JacksonStore {
2
+ key: string;
3
+ value: string;
4
+ iv?: string;
5
+ tag?: string;
6
+ createdAt?: Date;
7
+ modifiedAt?: string;
8
+ }