@boxyhq/saml-jackson 1.4.0 → 1.5.1

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.
Files changed (66) hide show
  1. package/dist/controller/analytics.d.ts +12 -0
  2. package/dist/controller/analytics.js +66 -0
  3. package/dist/controller/analytics.js.map +1 -0
  4. package/dist/controller/api.js +12 -1
  5. package/dist/controller/api.js.map +1 -1
  6. package/dist/controller/oauth.d.ts +3 -2
  7. package/dist/controller/oauth.js +132 -280
  8. package/dist/controller/oauth.js.map +1 -1
  9. package/dist/controller/saml-handler.d.ts +38 -0
  10. package/dist/controller/saml-handler.js +166 -0
  11. package/dist/controller/saml-handler.js.map +1 -0
  12. package/dist/controller/setup-link.d.ts +7 -7
  13. package/dist/controller/setup-link.js +56 -67
  14. package/dist/controller/setup-link.js.map +1 -1
  15. package/dist/controller/utils.d.ts +13 -1
  16. package/dist/controller/utils.js +45 -3
  17. package/dist/controller/utils.js.map +1 -1
  18. package/dist/db/db.d.ts +1 -1
  19. package/dist/db/db.js +2 -2
  20. package/dist/db/db.js.map +1 -1
  21. package/dist/db/mem.d.ts +2 -2
  22. package/dist/db/mem.js +27 -6
  23. package/dist/db/mem.js.map +1 -1
  24. package/dist/db/mongo.d.ts +2 -2
  25. package/dist/db/mongo.js +14 -8
  26. package/dist/db/mongo.js.map +1 -1
  27. package/dist/db/redis.d.ts +2 -2
  28. package/dist/db/redis.js +57 -5
  29. package/dist/db/redis.js.map +1 -1
  30. package/dist/db/sql/sql.d.ts +2 -2
  31. package/dist/db/sql/sql.js +19 -9
  32. package/dist/db/sql/sql.js.map +1 -1
  33. package/dist/db/store.js +2 -2
  34. package/dist/db/store.js.map +1 -1
  35. package/dist/db/utils.js +0 -1
  36. package/dist/db/utils.js.map +1 -1
  37. package/dist/directory-sync/Base.js +2 -2
  38. package/dist/directory-sync/Base.js.map +1 -1
  39. package/dist/directory-sync/WebhookEventsLogger.d.ts +4 -1
  40. package/dist/directory-sync/WebhookEventsLogger.js +3 -3
  41. package/dist/directory-sync/WebhookEventsLogger.js.map +1 -1
  42. package/dist/ee/common/checkLicense.d.ts +2 -0
  43. package/dist/ee/common/checkLicense.js +19 -0
  44. package/dist/ee/common/checkLicense.js.map +1 -0
  45. package/dist/ee/federated-saml/app.d.ts +19 -0
  46. package/dist/ee/federated-saml/app.js +126 -0
  47. package/dist/ee/federated-saml/app.js.map +1 -0
  48. package/dist/ee/federated-saml/index.d.ts +12 -0
  49. package/dist/ee/federated-saml/index.js +56 -0
  50. package/dist/ee/federated-saml/index.js.map +1 -0
  51. package/dist/ee/federated-saml/sso.d.ts +17 -0
  52. package/dist/ee/federated-saml/sso.js +76 -0
  53. package/dist/ee/federated-saml/sso.js.map +1 -0
  54. package/dist/ee/federated-saml/types.d.ts +18 -0
  55. package/dist/ee/federated-saml/types.js +3 -0
  56. package/dist/ee/federated-saml/types.js.map +1 -0
  57. package/dist/index.d.ts +7 -0
  58. package/dist/index.js +18 -2
  59. package/dist/index.js.map +1 -1
  60. package/dist/saml/lib.d.ts +31 -0
  61. package/dist/saml/lib.js +217 -0
  62. package/dist/saml/lib.js.map +1 -0
  63. package/dist/typings.d.ts +28 -21
  64. package/dist/typings.js +15 -0
  65. package/dist/typings.js.map +1 -1
  66. package/package.json +12 -16
@@ -37,55 +37,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
38
  exports.OAuthController = void 0;
39
39
  const crypto_1 = __importDefault(require("crypto"));
40
+ const jose = __importStar(require("jose"));
40
41
  const util_1 = require("util");
41
42
  const zlib_1 = require("zlib");
43
+ const saml20_1 = __importDefault(require("@boxyhq/saml20"));
42
44
  const openid_client_1 = require("openid-client");
43
- const jose = __importStar(require("jose"));
44
- const dbutils = __importStar(require("../db/utils"));
45
+ const utils_1 = require("./utils");
45
46
  const metrics = __importStar(require("../opentelemetry/metrics"));
46
- const saml20_1 = __importDefault(require("@boxyhq/saml20"));
47
- const claims_1 = __importDefault(require("../saml/claims"));
48
47
  const error_1 = require("./error");
49
48
  const allowed = __importStar(require("./oauth/allowed"));
50
49
  const codeVerifier = __importStar(require("./oauth/code-verifier"));
51
50
  const redirect = __importStar(require("./oauth/redirect"));
52
- const utils_1 = require("./utils");
53
51
  const x509_1 = require("../saml/x509");
52
+ const saml_handler_1 = require("./saml-handler");
53
+ const lib_1 = require("../saml/lib");
54
54
  const deflateRawAsync = (0, util_1.promisify)(zlib_1.deflateRaw);
55
- const validateSAMLResponse = (rawResponse, validateOpts) => __awaiter(void 0, void 0, void 0, function* () {
56
- const profile = yield saml20_1.default.validate(rawResponse, validateOpts);
57
- if (profile && profile.claims) {
58
- // we map claims to our attributes id, email, firstName, lastName where possible. We also map original claims to raw
59
- profile.claims = claims_1.default.map(profile.claims);
60
- // some providers don't return the id in the assertion, we set it to a sha256 hash of the email
61
- if (!profile.claims.id && profile.claims.email) {
62
- profile.claims.id = crypto_1.default.createHash('sha256').update(profile.claims.email).digest('hex');
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);
66
- }
67
- return profile;
68
- });
69
- function getEncodedTenantProduct(param) {
70
- try {
71
- const sp = new URLSearchParams(param);
72
- const tenant = sp.get('tenant');
73
- const product = sp.get('product');
74
- if (tenant && product) {
75
- return {
76
- tenant: sp.get('tenant'),
77
- product: sp.get('product'),
78
- };
79
- }
80
- return null;
81
- }
82
- catch (err) {
83
- return null;
84
- }
85
- }
86
- function getScopeValues(scope) {
87
- return typeof scope === 'string' ? scope.split(' ').filter((s) => s.length > 0) : [];
88
- }
89
55
  class OAuthController {
90
56
  constructor({ connectionStore, sessionStore, codeStore, tokenStore, opts }) {
91
57
  this.connectionStore = connectionStore;
@@ -93,53 +59,11 @@ class OAuthController {
93
59
  this.codeStore = codeStore;
94
60
  this.tokenStore = tokenStore;
95
61
  this.opts = opts;
96
- }
97
- resolveMultipleConnectionMatches(connections, idp_hint, originalParams, isIdpFlow = false) {
98
- if (connections.length > 1) {
99
- if (idp_hint) {
100
- return { resolvedConnection: connections.find(({ clientID }) => clientID === idp_hint) };
101
- }
102
- else if (this.opts.idpDiscoveryPath) {
103
- if (!isIdpFlow) {
104
- // redirect to IdP selection page
105
- const idpList = connections.map(({ idpMetadata, oidcProvider, clientID, name }) => {
106
- var _a;
107
- return JSON.stringify({
108
- provider: (_a = idpMetadata === null || idpMetadata === void 0 ? void 0 : idpMetadata.provider) !== null && _a !== void 0 ? _a : oidcProvider === null || oidcProvider === void 0 ? void 0 : oidcProvider.provider,
109
- clientID,
110
- name,
111
- connectionIsSAML: idpMetadata && typeof idpMetadata === 'object',
112
- connectionIsOIDC: oidcProvider && typeof oidcProvider === 'object',
113
- });
114
- });
115
- return {
116
- redirect_url: redirect.success(this.opts.externalUrl + this.opts.idpDiscoveryPath, Object.assign(Object.assign({}, originalParams), { idp: idpList })),
117
- };
118
- }
119
- else {
120
- // Relevant to IdP initiated SAML flow
121
- const appList = connections.map(({ product, name, description, clientID }) => ({
122
- product,
123
- name,
124
- description,
125
- clientID,
126
- }));
127
- return {
128
- app_select_form: saml20_1.default.createPostForm(this.opts.idpDiscoveryPath, [
129
- {
130
- name: 'SAMLResponse',
131
- value: originalParams.SAMLResponse,
132
- },
133
- {
134
- name: 'app',
135
- value: encodeURIComponent(JSON.stringify(appList)),
136
- },
137
- ]),
138
- };
139
- }
140
- }
141
- }
142
- return {};
62
+ this.samlHandler = new saml_handler_1.SAMLHandler({
63
+ connection: connectionStore,
64
+ session: sessionStore,
65
+ opts,
66
+ });
143
67
  }
144
68
  authorize(body) {
145
69
  var _a;
@@ -156,85 +80,58 @@ class OAuthController {
156
80
  throw new error_1.JacksonError('Please specify a redirect URL.', 400);
157
81
  }
158
82
  let connection;
159
- const requestedScopes = getScopeValues(scope);
83
+ const requestedScopes = (0, utils_1.getScopeValues)(scope);
160
84
  const requestedOIDCFlow = requestedScopes.includes('openid');
161
85
  if (tenant && product) {
162
- const connections = yield this.connectionStore.getByIndex({
163
- name: utils_1.IndexNames.TenantProduct,
164
- value: dbutils.keyFromParts(tenant, product),
165
- });
166
- if (!connections || connections.length === 0) {
167
- throw new error_1.JacksonError('IdP connection not found.', 403);
168
- }
169
- connection = connections[0];
170
- // Support multiple matches
171
- const { resolvedConnection, redirect_url } = this.resolveMultipleConnectionMatches(connections, idp_hint, {
172
- response_type,
173
- client_id,
174
- redirect_uri,
175
- state,
86
+ const response = yield this.samlHandler.resolveConnection({
176
87
  tenant,
177
88
  product,
178
- access_type,
179
- resource,
180
- scope,
181
- nonce,
182
- code_challenge,
183
- code_challenge_method,
89
+ idp_hint,
90
+ authFlow: 'oauth',
91
+ originalParams: Object.assign({}, body),
184
92
  });
185
- if (redirect_url) {
186
- return { redirect_url };
93
+ if ('redirectUrl' in response) {
94
+ return {
95
+ redirect_url: response.redirectUrl,
96
+ };
187
97
  }
188
- if (resolvedConnection) {
189
- connection = resolvedConnection;
98
+ if ('connection' in response) {
99
+ connection = response.connection;
190
100
  }
191
101
  }
192
102
  else if (client_id && client_id !== '' && client_id !== 'undefined' && client_id !== 'null') {
193
103
  // if tenant and product are encoded in the client_id then we parse it and check for the relevant connection(s)
194
- let sp = getEncodedTenantProduct(client_id);
104
+ let sp = (0, utils_1.getEncodedTenantProduct)(client_id);
195
105
  if (!sp && access_type) {
196
- sp = getEncodedTenantProduct(access_type);
106
+ sp = (0, utils_1.getEncodedTenantProduct)(access_type);
197
107
  }
198
108
  if (!sp && resource) {
199
- sp = getEncodedTenantProduct(resource);
109
+ sp = (0, utils_1.getEncodedTenantProduct)(resource);
200
110
  }
201
111
  if (!sp && requestedScopes) {
202
112
  const encodedParams = requestedScopes.find((scope) => scope.includes('=') && scope.includes('&')); // for now assume only one encoded param i.e. for tenant/product
203
113
  if (encodedParams) {
204
- sp = getEncodedTenantProduct(encodedParams);
114
+ sp = (0, utils_1.getEncodedTenantProduct)(encodedParams);
205
115
  }
206
116
  }
207
117
  if (sp && sp.tenant && sp.product) {
208
- requestedTenant = sp.tenant;
209
- requestedProduct = sp.product;
210
- const connections = yield this.connectionStore.getByIndex({
211
- name: utils_1.IndexNames.TenantProduct,
212
- value: dbutils.keyFromParts(sp.tenant, sp.product),
213
- });
214
- if (!connections || connections.length === 0) {
215
- throw new error_1.JacksonError('IdP connection not found.', 403);
216
- }
217
- connection = connections[0];
218
- // Support multiple matches
219
- const { resolvedConnection, redirect_url } = this.resolveMultipleConnectionMatches(connections, idp_hint, {
220
- response_type,
221
- client_id,
222
- redirect_uri,
223
- state,
118
+ const { tenant, product } = sp;
119
+ requestedTenant = tenant;
120
+ requestedProduct = product;
121
+ const response = yield this.samlHandler.resolveConnection({
224
122
  tenant,
225
123
  product,
226
- access_type,
227
- resource,
228
- scope,
229
- nonce,
230
- code_challenge,
231
- code_challenge_method,
124
+ idp_hint,
125
+ authFlow: 'oauth',
126
+ originalParams: Object.assign({}, body),
232
127
  });
233
- if (redirect_url) {
234
- return { redirect_url };
128
+ if ('redirectUrl' in response) {
129
+ return {
130
+ redirect_url: response.redirectUrl,
131
+ };
235
132
  }
236
- if (resolvedConnection) {
237
- connection = resolvedConnection;
133
+ if ('connection' in response) {
134
+ connection = response.connection;
238
135
  }
239
136
  }
240
137
  else {
@@ -286,14 +183,14 @@ class OAuthController {
286
183
  // Connection retrieved: Handover to IdP starts here
287
184
  let ssoUrl;
288
185
  let post = false;
289
- const connectionIsSAML = connection.idpMetadata && typeof connection.idpMetadata === 'object';
290
- const connectionIsOIDC = connection.oidcProvider && typeof connection.oidcProvider === 'object';
186
+ const connectionIsSAML = 'idpMetadata' in connection && connection.idpMetadata !== undefined;
187
+ const connectionIsOIDC = 'oidcProvider' in connection && connection.oidcProvider !== undefined;
291
188
  // Init sessionId
292
189
  const sessionId = crypto_1.default.randomBytes(16).toString('hex');
293
190
  const relayState = utils_1.relayStatePrefix + sessionId;
294
191
  // SAML connection: SAML request will be constructed here
295
192
  let samlReq;
296
- if (connectionIsSAML) {
193
+ if ('idpMetadata' in connection) {
297
194
  const { sso } = connection.idpMetadata;
298
195
  if ('redirectUrl' in sso) {
299
196
  // HTTP Redirect binding
@@ -342,7 +239,7 @@ class OAuthController {
342
239
  }
343
240
  // OIDC Connection: Issuer discovery, openid-client init and extraction of authorization endpoint happens here
344
241
  let oidcCodeVerifier;
345
- if (connectionIsOIDC) {
242
+ if (connectionIsOIDC && 'oidcProvider' in connection) {
346
243
  if (!this.opts.oidcPath) {
347
244
  return {
348
245
  redirect_url: (0, utils_1.OAuthErrorResponse)({
@@ -473,148 +370,114 @@ class OAuthController {
473
370
  });
474
371
  }
475
372
  samlResponse(body) {
476
- var _a, _b;
373
+ var _a;
477
374
  return __awaiter(this, void 0, void 0, function* () {
478
- const { SAMLResponse, idp_hint } = body;
479
- let RelayState = body.RelayState || ''; // RelayState will contain the sessionId from earlier quasi-oauth flow
375
+ const { SAMLResponse, idp_hint, RelayState = '' } = body;
480
376
  const isIdPFlow = !RelayState.startsWith(utils_1.relayStatePrefix);
377
+ // IdP is disabled so block the request
481
378
  if (!this.opts.idpEnabled && isIdPFlow) {
482
379
  // IdP login is disabled so block the request
483
380
  throw new error_1.JacksonError('IdP (Identity Provider) flow has been disabled. Please head to your Service Provider to login.', 403);
484
381
  }
485
- RelayState = RelayState.replace(utils_1.relayStatePrefix, '');
382
+ const sessionId = RelayState.replace(utils_1.relayStatePrefix, '');
486
383
  const rawResponse = Buffer.from(SAMLResponse, 'base64').toString();
487
384
  const issuer = saml20_1.default.parseIssuer(rawResponse);
488
385
  if (!issuer) {
489
386
  throw new error_1.JacksonError('Issuer not found.', 403);
490
387
  }
491
- const samlConnections = yield this.connectionStore.getByIndex({
388
+ const connections = yield this.connectionStore.getByIndex({
492
389
  name: utils_1.IndexNames.EntityID,
493
390
  value: issuer,
494
391
  });
495
- if (!samlConnections || samlConnections.length === 0) {
392
+ if (!connections || connections.length === 0) {
496
393
  throw new error_1.JacksonError('SAML connection not found.', 403);
497
394
  }
498
- let samlConnection = samlConnections[0];
395
+ const session = sessionId ? yield this.sessionStore.get(sessionId) : null;
396
+ if (!isIdPFlow && !session) {
397
+ throw new error_1.JacksonError('Unable to validate state from the origin request.', 403);
398
+ }
399
+ const isSAMLFederated = session && 'samlFederated' in session;
400
+ const isSPFflow = !isIdPFlow && !isSAMLFederated;
401
+ let connection;
402
+ // IdP initiated SSO flow
499
403
  if (isIdPFlow) {
500
- RelayState = '';
501
- const { resolvedConnection, app_select_form } = this.resolveMultipleConnectionMatches(samlConnections, idp_hint, { SAMLResponse }, true);
502
- if (app_select_form) {
503
- return { app_select_form };
504
- }
505
- if (resolvedConnection) {
506
- samlConnection = resolvedConnection;
507
- }
508
- }
509
- let session;
510
- if (RelayState !== '') {
511
- session = yield this.sessionStore.get(RelayState);
512
- if (!session) {
513
- throw new error_1.JacksonError('Unable to validate state from the origin request.', 403);
514
- }
515
- }
516
- if (!isIdPFlow) {
517
- // Resolve if there are multiple matches for SP login. TODO: Support multiple matches for IdP login
518
- samlConnection =
519
- samlConnections.length === 1
520
- ? samlConnections[0]
521
- : samlConnections.filter((c) => {
522
- var _a, _b, _c;
523
- return (c.clientID === ((_a = session === null || session === void 0 ? void 0 : session.requested) === null || _a === void 0 ? void 0 : _a.client_id) ||
524
- (c.tenant === ((_b = session === null || session === void 0 ? void 0 : session.requested) === null || _b === void 0 ? void 0 : _b.tenant) && c.product === ((_c = session === null || session === void 0 ? void 0 : session.requested) === null || _c === void 0 ? void 0 : _c.product)));
525
- })[0];
526
- }
527
- if (!samlConnection) {
404
+ const response = yield this.samlHandler.resolveConnection({
405
+ idp_hint,
406
+ authFlow: 'idp-initiated',
407
+ entityId: issuer,
408
+ originalParams: {
409
+ SAMLResponse,
410
+ },
411
+ });
412
+ // Redirect to the product selection page
413
+ if ('postForm' in response) {
414
+ return {
415
+ app_select_form: response.postForm,
416
+ };
417
+ }
418
+ // Found a connection
419
+ if ('connection' in response) {
420
+ connection = response.connection;
421
+ }
422
+ }
423
+ // SP initiated SSO flow
424
+ // Resolve if there are multiple matches for SP login
425
+ if (isSPFflow) {
426
+ connection = connections.filter((c) => {
427
+ return (c.clientID === session.requested.client_id ||
428
+ (c.tenant === session.requested.tenant && c.product === session.requested.product));
429
+ })[0];
430
+ }
431
+ if (!connection) {
432
+ connection = connections[0];
433
+ }
434
+ if (!connection) {
528
435
  throw new error_1.JacksonError('SAML connection not found.', 403);
529
436
  }
530
- const { privateKey } = yield (0, x509_1.getDefaultCertificate)();
531
- const validateOpts = {
532
- thumbprint: samlConnection.idpMetadata.thumbprint,
533
- audience: this.opts.samlAudience,
534
- privateKey,
535
- };
536
437
  if (session &&
537
438
  session.redirect_uri &&
538
- !allowed.redirect(session.redirect_uri, samlConnection.redirectUrl)) {
439
+ !allowed.redirect(session.redirect_uri, connection.redirectUrl)) {
539
440
  throw new error_1.JacksonError('Redirect URL is not allowed.', 403);
540
441
  }
442
+ const { privateKey } = yield (0, x509_1.getDefaultCertificate)();
443
+ const validateOpts = {
444
+ thumbprint: `${connection.idpMetadata.thumbprint}`,
445
+ audience: `${this.opts.samlAudience}`,
446
+ privateKey,
447
+ };
541
448
  if (session && session.id) {
542
- validateOpts.inResponseTo = session.id;
449
+ validateOpts['inResponseTo'] = session.id;
543
450
  }
544
- let profile;
545
- const redirect_uri = (session && session.redirect_uri) || samlConnection.defaultRedirectUrl;
451
+ const redirect_uri = (session && session.redirect_uri) || connection.defaultRedirectUrl;
452
+ let profile = null;
546
453
  try {
547
- profile = yield validateSAMLResponse(rawResponse, validateOpts);
454
+ profile = yield (0, lib_1.extractSAMLResponseAttributes)(rawResponse, validateOpts);
548
455
  }
549
456
  catch (err) {
550
- // return error to redirect_uri
551
457
  return {
552
458
  redirect_url: (0, utils_1.OAuthErrorResponse)({
553
459
  error: 'access_denied',
554
460
  error_description: (0, utils_1.getErrorMessage)(err),
555
461
  redirect_uri,
556
- state: (_a = session === null || session === void 0 ? void 0 : session.requested) === null || _a === void 0 ? void 0 : _a.state,
462
+ state: (_a = session.requested) === null || _a === void 0 ? void 0 : _a.state,
557
463
  }),
558
464
  };
559
465
  }
560
- // store details against a code
561
- const code = crypto_1.default.randomBytes(20).toString('hex');
562
- const codeVal = {
563
- profile,
564
- clientID: samlConnection.clientID,
565
- clientSecret: samlConnection.clientSecret,
566
- requested: session === null || session === void 0 ? void 0 : session.requested,
567
- isIdPFlow,
568
- };
569
- if (session) {
570
- codeVal.session = session;
571
- }
572
- try {
573
- yield this.codeStore.put(code, codeVal);
574
- }
575
- catch (err) {
576
- // return error to redirect_uri
577
- return {
578
- redirect_url: (0, utils_1.OAuthErrorResponse)({
579
- error: 'server_error',
580
- error_description: (0, utils_1.getErrorMessage)(err),
581
- redirect_uri,
582
- state: (_b = session === null || session === void 0 ? void 0 : session.requested) === null || _b === void 0 ? void 0 : _b.state,
583
- }),
584
- };
466
+ // This is a federated SAML flow, let's create a new SAMLResponse and POST it to the SP
467
+ if (isSAMLFederated) {
468
+ const { responseForm } = yield this.samlHandler.createSAMLResponse({ profile, session });
469
+ yield this.sessionStore.delete(sessionId);
470
+ return { responseForm };
585
471
  }
472
+ const code = yield this._buildAuthorizationCode(connection, profile, session, isIdPFlow);
586
473
  const params = {
587
474
  code,
588
475
  };
589
476
  if (session && session.state) {
590
- params.state = session.state;
591
- }
592
- const redirectUrl = redirect.success(redirect_uri, params);
593
- // delete the session
594
- try {
595
- yield this.sessionStore.delete(RelayState);
477
+ params['state'] = session.state;
596
478
  }
597
- catch (_err) {
598
- // ignore error
599
- }
600
- return { redirect_url: redirectUrl };
601
- });
602
- }
603
- extractOIDCUserProfile(tokenSet, oidcClient) {
604
- var _a, _b, _c, _d, _e;
605
- return __awaiter(this, void 0, void 0, function* () {
606
- const profile = { claims: {} };
607
- const idTokenClaims = tokenSet.claims();
608
- const userinfo = yield oidcClient.userinfo(tokenSet);
609
- profile.claims.id = idTokenClaims.sub;
610
- profile.claims.idHash = dbutils.keyDigest(idTokenClaims.sub);
611
- profile.claims.email = (_a = idTokenClaims.email) !== null && _a !== void 0 ? _a : userinfo.email;
612
- profile.claims.firstName = (_b = idTokenClaims.given_name) !== null && _b !== void 0 ? _b : userinfo.given_name;
613
- profile.claims.lastName = (_c = idTokenClaims.family_name) !== null && _c !== void 0 ? _c : userinfo.family_name;
614
- profile.claims.roles = (_d = idTokenClaims.roles) !== null && _d !== void 0 ? _d : userinfo.roles;
615
- profile.claims.groups = (_e = idTokenClaims.groups) !== null && _e !== void 0 ? _e : userinfo.groups;
616
- profile.claims.raw = userinfo;
617
- return profile;
479
+ yield this.sessionStore.delete(sessionId);
480
+ return { redirect_url: redirect.success(redirect_uri, params) };
618
481
  });
619
482
  }
620
483
  oidcAuthzResponse(body) {
@@ -668,7 +531,7 @@ class OAuthController {
668
531
  const tokenSet = yield oidcClient.callback(this.opts.externalUrl + this.opts.oidcPath, {
669
532
  code: opCode,
670
533
  }, { code_verifier: session.oidcCodeVerifier });
671
- profile = yield this.extractOIDCUserProfile(tokenSet, oidcClient);
534
+ profile = yield (0, utils_1.extractOIDCUserProfile)(tokenSet, oidcClient);
672
535
  }
673
536
  catch (err) {
674
537
  if (err) {
@@ -682,48 +545,37 @@ class OAuthController {
682
545
  };
683
546
  }
684
547
  }
685
- // store details against a code
686
- const code = crypto_1.default.randomBytes(20).toString('hex');
687
- const codeVal = {
688
- profile,
689
- clientID: oidcConnection.clientID,
690
- clientSecret: oidcConnection.clientSecret,
691
- requested: session === null || session === void 0 ? void 0 : session.requested,
692
- };
693
- if (session) {
694
- codeVal.session = session;
695
- }
696
- try {
697
- yield this.codeStore.put(code, codeVal);
698
- }
699
- catch (err) {
700
- // return error to redirect_uri
701
- return {
702
- redirect_url: (0, utils_1.OAuthErrorResponse)({
703
- error: 'server_error',
704
- error_description: (0, utils_1.getErrorMessage)(err),
705
- redirect_uri,
706
- state: session.state,
707
- }),
708
- };
709
- }
548
+ const code = yield this._buildAuthorizationCode(oidcConnection, profile, session, false);
710
549
  const params = {
711
550
  code,
712
551
  };
713
552
  if (session && session.state) {
714
- params.state = session.state;
553
+ params['state'] = session.state;
715
554
  }
716
555
  const redirectUrl = redirect.success(redirect_uri, params);
717
- // delete the session
718
- try {
719
- yield this.sessionStore.delete(RelayState);
720
- }
721
- catch (_err) {
722
- // ignore error
723
- }
556
+ yield this.sessionStore.delete(RelayState);
724
557
  return { redirect_url: redirectUrl };
725
558
  });
726
559
  }
560
+ // Build the authorization code for the session
561
+ _buildAuthorizationCode(connection, profile, session, isIdPFlow) {
562
+ return __awaiter(this, void 0, void 0, function* () {
563
+ // Store details against a code
564
+ const code = crypto_1.default.randomBytes(20).toString('hex');
565
+ const codeVal = {
566
+ profile,
567
+ clientID: connection.clientID,
568
+ clientSecret: connection.clientSecret,
569
+ requested: session ? session.requested : null,
570
+ isIdPFlow,
571
+ };
572
+ if (session) {
573
+ codeVal['session'] = session;
574
+ }
575
+ yield this.codeStore.put(code, codeVal);
576
+ return code;
577
+ });
578
+ }
727
579
  /**
728
580
  * @swagger
729
581
  *
@@ -819,7 +671,7 @@ class OAuthController {
819
671
  else if (client_id && client_secret) {
820
672
  // check if we have an encoded client_id
821
673
  if (client_id !== 'dummy') {
822
- const sp = getEncodedTenantProduct(client_id);
674
+ const sp = (0, utils_1.getEncodedTenantProduct)(client_id);
823
675
  if (!sp) {
824
676
  // OAuth flow
825
677
  if (client_id !== codeVal.clientID || client_secret !== codeVal.clientSecret) {