@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.
@@ -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
+ }