@boxyhq/saml-jackson 1.20.2 → 1.20.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,8 +10,20 @@ const redirect = (redirectUrl, redirectUrls) => {
10
10
  const url = new URL(redirectUrl);
11
11
  for (const idx in redirectUrls) {
12
12
  const rUrl = new URL(redirectUrls[idx]);
13
+ let hostname = url.hostname;
14
+ let hostNameAllowed = rUrl.hostname;
15
+ // allow subdomain globbing *.example.com only
16
+ try {
17
+ if (rUrl.hostname.startsWith('*.')) {
18
+ hostNameAllowed = rUrl.hostname.slice(2);
19
+ hostname = hostname.slice(hostname.indexOf('.') + 1);
20
+ }
21
+ }
22
+ catch (e) {
23
+ // no-op
24
+ }
13
25
  // TODO: Check pathname, for now pathname is ignored
14
- if (rUrl.protocol === url.protocol && rUrl.hostname === url.hostname && rUrl.port === url.port) {
26
+ if (rUrl.protocol === url.protocol && hostNameAllowed === hostname && rUrl.port === url.port) {
15
27
  return true;
16
28
  }
17
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"allowed.js","sourceRoot":"","sources":["../../../src/controller/oauth/allowed.ts"],"names":[],"mappings":";;;AAAA,MAAM,sBAAsB,GAAG,oCAAoC,CAAC;AAE7D,MAAM,QAAQ,GAAG,CAAC,WAAmB,EAAE,YAAsB,EAAW,EAAE;IAC/E,0CAA0C;IAC1C,IAAI,WAAW,KAAK,sBAAsB,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,GAAG,GAAQ,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IAEtC,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAQ,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QAE7C,oDAAoD;QAEpD,IAAI,IAAI,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;YAC/F,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAnBW,QAAA,QAAQ,YAmBnB"}
1
+ {"version":3,"file":"allowed.js","sourceRoot":"","sources":["../../../src/controller/oauth/allowed.ts"],"names":[],"mappings":";;;AAAA,MAAM,sBAAsB,GAAG,oCAAoC,CAAC;AAE7D,MAAM,QAAQ,GAAG,CAAC,WAAmB,EAAE,YAAsB,EAAW,EAAE;IAC/E,0CAA0C;IAC1C,IAAI,WAAW,KAAK,sBAAsB,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,GAAG,GAAQ,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IAEtC,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAQ,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QAE7C,IAAI,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;QAC5B,IAAI,eAAe,GAAG,IAAI,CAAC,QAAQ,CAAC;QAEpC,8CAA8C;QAC9C,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnC,eAAe,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACzC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,QAAQ;QACV,CAAC;QAED,oDAAoD;QAEpD,IAAI,IAAI,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ,IAAI,eAAe,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;YAC7F,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAhCW,QAAA,QAAQ,YAgCnB"}
@@ -7,13 +7,15 @@ export declare class OAuthController implements IOAuthController {
7
7
  private ssoTracer;
8
8
  private opts;
9
9
  private ssoHandler;
10
- constructor({ connectionStore, sessionStore, codeStore, tokenStore, ssoTracer, opts }: {
10
+ private samlFedApp;
11
+ constructor({ connectionStore, sessionStore, codeStore, tokenStore, ssoTracer, opts, samlFedApp }: {
11
12
  connectionStore: any;
12
13
  sessionStore: any;
13
14
  codeStore: any;
14
15
  tokenStore: any;
15
16
  ssoTracer: any;
16
17
  opts: any;
18
+ samlFedApp: any;
17
19
  });
18
20
  authorize(body: OAuthReq): Promise<{
19
21
  redirect_url?: string;
@@ -43,6 +43,7 @@ const zlib_1 = require("zlib");
43
43
  const saml20_1 = __importDefault(require("@boxyhq/saml20"));
44
44
  const openid_client_1 = require("openid-client");
45
45
  const utils_1 = require("./utils");
46
+ const utils_2 = require("./utils");
46
47
  const metrics = __importStar(require("../opentelemetry/metrics"));
47
48
  const error_1 = require("./error");
48
49
  const allowed = __importStar(require("./oauth/allowed"));
@@ -54,13 +55,14 @@ const lib_1 = require("../saml/lib");
54
55
  const oidc_issuer_1 = require("./oauth/oidc-issuer");
55
56
  const deflateRawAsync = (0, util_1.promisify)(zlib_1.deflateRaw);
56
57
  class OAuthController {
57
- constructor({ connectionStore, sessionStore, codeStore, tokenStore, ssoTracer, opts }) {
58
+ constructor({ connectionStore, sessionStore, codeStore, tokenStore, ssoTracer, opts, samlFedApp }) {
58
59
  this.connectionStore = connectionStore;
59
60
  this.sessionStore = sessionStore;
60
61
  this.codeStore = codeStore;
61
62
  this.tokenStore = tokenStore;
62
63
  this.ssoTracer = ssoTracer;
63
64
  this.opts = opts;
65
+ this.samlFedApp = samlFedApp;
64
66
  this.ssoHandler = new sso_handler_1.SSOHandler({
65
67
  connection: connectionStore,
66
68
  session: sessionStore,
@@ -76,6 +78,7 @@ class OAuthController {
76
78
  let requestedScopes;
77
79
  let requestedOIDCFlow;
78
80
  let connection;
81
+ let fedApp;
79
82
  try {
80
83
  const tenant = 'tenant' in body ? body.tenant : undefined;
81
84
  const product = 'product' in body ? body.product : undefined;
@@ -87,7 +90,7 @@ class OAuthController {
87
90
  if (!redirect_uri) {
88
91
  throw new error_1.JacksonError('Please specify a redirect URL.', 400);
89
92
  }
90
- requestedScopes = (0, utils_1.getScopeValues)(scope);
93
+ requestedScopes = (0, utils_2.getScopeValues)(scope);
91
94
  requestedOIDCFlow = requestedScopes.includes('openid');
92
95
  if (tenant && product) {
93
96
  const response = yield this.ssoHandler.resolveConnection({
@@ -108,17 +111,17 @@ class OAuthController {
108
111
  }
109
112
  else if (client_id && client_id !== '' && client_id !== 'undefined' && client_id !== 'null') {
110
113
  // if tenant and product are encoded in the client_id then we parse it and check for the relevant connection(s)
111
- let sp = (0, utils_1.getEncodedTenantProduct)(client_id);
114
+ let sp = (0, utils_2.getEncodedTenantProduct)(client_id);
112
115
  if (!sp && access_type) {
113
- sp = (0, utils_1.getEncodedTenantProduct)(access_type);
116
+ sp = (0, utils_2.getEncodedTenantProduct)(access_type);
114
117
  }
115
118
  if (!sp && resource) {
116
- sp = (0, utils_1.getEncodedTenantProduct)(resource);
119
+ sp = (0, utils_2.getEncodedTenantProduct)(resource);
117
120
  }
118
121
  if (!sp && requestedScopes) {
119
122
  const encodedParams = requestedScopes.find((scope) => scope.includes('=') && scope.includes('&')); // for now assume only one encoded param i.e. for tenant/product
120
123
  if (encodedParams) {
121
- sp = (0, utils_1.getEncodedTenantProduct)(encodedParams);
124
+ sp = (0, utils_2.getEncodedTenantProduct)(encodedParams);
122
125
  }
123
126
  }
124
127
  if (sp && sp.tenant && sp.product) {
@@ -142,10 +145,38 @@ class OAuthController {
142
145
  }
143
146
  }
144
147
  else {
145
- connection = yield this.connectionStore.get(client_id);
146
- if (connection) {
147
- requestedTenant = connection.tenant;
148
- requestedProduct = connection.product;
148
+ // client_id is not encoded, so we look for the connection using the client_id
149
+ // First we check if it's a federated connection
150
+ if (client_id.startsWith(`${utils_1.clientIDFederatedPrefix}${utils_1.clientIDOIDCPrefix}`)) {
151
+ fedApp = yield this.samlFedApp.get({
152
+ id: client_id.replace(utils_1.clientIDFederatedPrefix, ''),
153
+ });
154
+ const response = yield this.ssoHandler.resolveConnection({
155
+ tenant: fedApp.tenant,
156
+ product: fedApp.product,
157
+ idp_hint,
158
+ authFlow: 'oauth',
159
+ originalParams: Object.assign({}, body),
160
+ tenants: fedApp.tenants,
161
+ samlFedAppId: fedApp.id,
162
+ fedType: fedApp.type,
163
+ });
164
+ if ('redirectUrl' in response) {
165
+ return {
166
+ redirect_url: response.redirectUrl,
167
+ };
168
+ }
169
+ if ('connection' in response) {
170
+ connection = response.connection;
171
+ }
172
+ }
173
+ else {
174
+ // If it's not a federated connection, we look for the connection using the client_id
175
+ connection = yield this.connectionStore.get(client_id);
176
+ if (connection) {
177
+ requestedTenant = connection.tenant;
178
+ requestedProduct = connection.product;
179
+ }
149
180
  }
150
181
  }
151
182
  }
@@ -156,11 +187,18 @@ class OAuthController {
156
187
  throw new error_1.JacksonError('IdP connection not found.', 403);
157
188
  }
158
189
  if (!allowed.redirect(redirect_uri, connection.redirectUrl)) {
159
- throw new error_1.JacksonError('Redirect URL is not allowed.', 403);
190
+ if (fedApp) {
191
+ if (!allowed.redirect(redirect_uri, fedApp.redirectUrl)) {
192
+ throw new error_1.JacksonError('Redirect URL is not allowed.', 403);
193
+ }
194
+ }
195
+ else {
196
+ throw new error_1.JacksonError('Redirect URL is not allowed.', 403);
197
+ }
160
198
  }
161
199
  }
162
200
  catch (err) {
163
- const error_description = (0, utils_1.getErrorMessage)(err);
201
+ const error_description = (0, utils_2.getErrorMessage)(err);
164
202
  // Save the error trace
165
203
  yield this.ssoTracer.saveTrace({
166
204
  error: error_description,
@@ -174,11 +212,11 @@ class OAuthController {
174
212
  });
175
213
  throw err;
176
214
  }
177
- if (!(0, utils_1.isConnectionActive)(connection)) {
215
+ if (!(0, utils_2.isConnectionActive)(connection)) {
178
216
  throw new error_1.JacksonError('SSO connection is deactivated. Please contact your administrator.', 403);
179
217
  }
180
218
  const isMissingJWTKeysForOIDCFlow = requestedOIDCFlow &&
181
- (!((_a = this.opts.openid) === null || _a === void 0 ? void 0 : _a.jwtSigningKeys) || !(0, utils_1.isJWSKeyPairLoaded)(this.opts.openid.jwtSigningKeys));
219
+ (!((_a = this.opts.openid) === null || _a === void 0 ? void 0 : _a.jwtSigningKeys) || !(0, utils_2.isJWSKeyPairLoaded)(this.opts.openid.jwtSigningKeys));
182
220
  const oAuthClientReqError = !state || response_type !== 'code';
183
221
  const connectionIsSAML = 'idpMetadata' in connection && connection.idpMetadata !== undefined;
184
222
  const connectionIsOIDC = 'oidcProvider' in connection && connection.oidcProvider !== undefined;
@@ -213,7 +251,7 @@ class OAuthController {
213
251
  },
214
252
  });
215
253
  return {
216
- redirect_url: (0, utils_1.OAuthErrorResponse)({
254
+ redirect_url: (0, utils_2.OAuthErrorResponse)({
217
255
  error,
218
256
  error_description: traceId ? `${traceId}: ${error_description}` : error_description,
219
257
  redirect_uri,
@@ -226,7 +264,7 @@ class OAuthController {
226
264
  let post = false;
227
265
  // Init sessionId
228
266
  const sessionId = crypto_1.default.randomBytes(16).toString('hex');
229
- const relayState = utils_1.relayStatePrefix + sessionId;
267
+ const relayState = utils_2.relayStatePrefix + sessionId;
230
268
  // SAML connection: SAML request will be constructed here
231
269
  let samlReq;
232
270
  if (connectionIsSAML) {
@@ -256,7 +294,7 @@ class OAuthController {
256
294
  },
257
295
  });
258
296
  return {
259
- redirect_url: (0, utils_1.OAuthErrorResponse)({
297
+ redirect_url: (0, utils_2.OAuthErrorResponse)({
260
298
  error: 'invalid_request',
261
299
  error_description: traceId ? `${traceId}: ${error_description}` : error_description,
262
300
  redirect_uri,
@@ -278,7 +316,7 @@ class OAuthController {
278
316
  });
279
317
  }
280
318
  catch (err) {
281
- const error_description = (0, utils_1.getErrorMessage)(err);
319
+ const error_description = (0, utils_2.getErrorMessage)(err);
282
320
  // Save the error trace
283
321
  const traceId = yield this.ssoTracer.saveTrace({
284
322
  error: error_description,
@@ -291,7 +329,7 @@ class OAuthController {
291
329
  },
292
330
  });
293
331
  return {
294
- redirect_url: (0, utils_1.OAuthErrorResponse)({
332
+ redirect_url: (0, utils_2.OAuthErrorResponse)({
295
333
  error: 'server_error',
296
334
  error_description: traceId ? `${traceId}: ${error_description}` : error_description,
297
335
  redirect_uri,
@@ -306,7 +344,7 @@ class OAuthController {
306
344
  if (connectionIsOIDC) {
307
345
  if (!this.opts.oidcPath) {
308
346
  return {
309
- redirect_url: (0, utils_1.OAuthErrorResponse)({
347
+ redirect_url: (0, utils_2.OAuthErrorResponse)({
310
348
  error: 'server_error',
311
349
  error_description: 'OpenID response handler path (oidcPath) is not set',
312
350
  redirect_uri,
@@ -340,9 +378,9 @@ class OAuthController {
340
378
  catch (err) {
341
379
  if (err) {
342
380
  return {
343
- redirect_url: (0, utils_1.OAuthErrorResponse)({
381
+ redirect_url: (0, utils_2.OAuthErrorResponse)({
344
382
  error: 'server_error',
345
- error_description: (err === null || err === void 0 ? void 0 : err.error) || (0, utils_1.getErrorMessage)(err),
383
+ error_description: (err === null || err === void 0 ? void 0 : err.error) || (0, utils_2.getErrorMessage)(err),
346
384
  redirect_uri,
347
385
  state,
348
386
  }),
@@ -362,6 +400,11 @@ class OAuthController {
362
400
  if (idp_hint) {
363
401
  requested.idp_hint = idp_hint;
364
402
  }
403
+ else {
404
+ if (fedApp) {
405
+ requested.idp_hint = connection.clientID;
406
+ }
407
+ }
365
408
  if (requestedOIDCFlow) {
366
409
  requested.oidc = true;
367
410
  if (nonce) {
@@ -378,6 +421,7 @@ class OAuthController {
378
421
  code_challenge,
379
422
  code_challenge_method,
380
423
  requested,
424
+ oidcFederated: fedApp ? { redirectUrl: fedApp.redirectUrl, id: fedApp.id } : undefined,
381
425
  };
382
426
  yield this.sessionStore.put(sessionId, connectionIsSAML
383
427
  ? Object.assign(Object.assign({}, sessionObj), { id: samlReq === null || samlReq === void 0 ? void 0 : samlReq.id }) : Object.assign(Object.assign({}, sessionObj), { id: connection.clientID, oidcCodeVerifier, oidcNonce }));
@@ -416,7 +460,7 @@ class OAuthController {
416
460
  throw 'Connection appears to be misconfigured';
417
461
  }
418
462
  catch (err) {
419
- const error_description = (0, utils_1.getErrorMessage)(err);
463
+ const error_description = (0, utils_2.getErrorMessage)(err);
420
464
  // Save the error trace
421
465
  const traceId = yield this.ssoTracer.saveTrace({
422
466
  error: error_description,
@@ -430,7 +474,7 @@ class OAuthController {
430
474
  },
431
475
  });
432
476
  return {
433
- redirect_url: (0, utils_1.OAuthErrorResponse)({
477
+ redirect_url: (0, utils_2.OAuthErrorResponse)({
434
478
  error: 'server_error',
435
479
  error_description: traceId ? `${traceId}: ${error_description}` : error_description,
436
480
  redirect_uri,
@@ -441,7 +485,7 @@ class OAuthController {
441
485
  });
442
486
  }
443
487
  samlResponse(body) {
444
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
488
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
445
489
  return __awaiter(this, void 0, void 0, function* () {
446
490
  let connection;
447
491
  let rawResponse;
@@ -450,23 +494,24 @@ class OAuthController {
450
494
  let issuer;
451
495
  let isIdPFlow;
452
496
  let isSAMLFederated;
497
+ let isOIDCFederated;
453
498
  let validateOpts;
454
499
  let redirect_uri;
455
500
  const { SAMLResponse, idp_hint, RelayState = '' } = body;
456
501
  try {
457
- isIdPFlow = !RelayState.startsWith(utils_1.relayStatePrefix);
502
+ isIdPFlow = !RelayState.startsWith(utils_2.relayStatePrefix);
458
503
  rawResponse = Buffer.from(SAMLResponse, 'base64').toString();
459
504
  issuer = saml20_1.default.parseIssuer(rawResponse);
460
505
  if (!this.opts.idpEnabled && isIdPFlow) {
461
506
  // IdP login is disabled so block the request
462
507
  throw new error_1.JacksonError('IdP (Identity Provider) flow has been disabled. Please head to your Service Provider to login.', 403);
463
508
  }
464
- sessionId = RelayState.replace(utils_1.relayStatePrefix, '');
509
+ sessionId = RelayState.replace(utils_2.relayStatePrefix, '');
465
510
  if (!issuer) {
466
511
  throw new error_1.JacksonError('Issuer not found.', 403);
467
512
  }
468
513
  const connections = (yield this.connectionStore.getByIndex({
469
- name: utils_1.IndexNames.EntityID,
514
+ name: utils_2.IndexNames.EntityID,
470
515
  value: issuer,
471
516
  })).data;
472
517
  if (!connections || connections.length === 0) {
@@ -477,6 +522,7 @@ class OAuthController {
477
522
  throw new error_1.JacksonError('Unable to validate state from the origin request.', 403);
478
523
  }
479
524
  isSAMLFederated = session && 'samlFederated' in session;
525
+ isOIDCFederated = session && 'oidcFederated' in session;
480
526
  const isSPFlow = !isIdPFlow && !isSAMLFederated;
481
527
  // IdP initiated SSO flow
482
528
  if (isIdPFlow) {
@@ -501,9 +547,10 @@ class OAuthController {
501
547
  }
502
548
  // SP initiated SSO flow
503
549
  // Resolve if there are multiple matches for SP login
504
- if (isSPFlow || isSAMLFederated) {
550
+ if (isSPFlow || isSAMLFederated || isOIDCFederated) {
505
551
  connection = connections.filter((c) => {
506
552
  return (c.clientID === session.requested.client_id ||
553
+ c.clientID === session.requested.idp_hint ||
507
554
  (c.tenant === session.requested.tenant && c.product === session.requested.product));
508
555
  })[0];
509
556
  }
@@ -513,7 +560,14 @@ class OAuthController {
513
560
  if (session &&
514
561
  session.redirect_uri &&
515
562
  !allowed.redirect(session.redirect_uri, connection.redirectUrl)) {
516
- throw new error_1.JacksonError('Redirect URL is not allowed.', 403);
563
+ if (isOIDCFederated) {
564
+ if (!allowed.redirect(session.redirect_uri, (_a = session.oidcFederated) === null || _a === void 0 ? void 0 : _a.redirectUrl)) {
565
+ throw new error_1.JacksonError('Redirect URL is not allowed.', 403);
566
+ }
567
+ }
568
+ else {
569
+ throw new error_1.JacksonError('Redirect URL is not allowed.', 403);
570
+ }
517
571
  }
518
572
  const { privateKey } = yield (0, x509_1.getDefaultCertificate)();
519
573
  validateOpts = {
@@ -534,20 +588,20 @@ class OAuthController {
534
588
  catch (err) {
535
589
  // Save the error trace
536
590
  yield this.ssoTracer.saveTrace({
537
- error: (0, utils_1.getErrorMessage)(err),
591
+ error: (0, utils_2.getErrorMessage)(err),
538
592
  context: {
539
593
  samlResponse: rawResponse,
540
- tenant: ((_a = session === null || session === void 0 ? void 0 : session.requested) === null || _a === void 0 ? void 0 : _a.tenant) || (connection === null || connection === void 0 ? void 0 : connection.tenant),
541
- product: ((_b = session === null || session === void 0 ? void 0 : session.requested) === null || _b === void 0 ? void 0 : _b.product) || (connection === null || connection === void 0 ? void 0 : connection.product),
542
- clientID: ((_c = session === null || session === void 0 ? void 0 : session.requested) === null || _c === void 0 ? void 0 : _c.client_id) || (connection === null || connection === void 0 ? void 0 : connection.clientID),
543
- providerName: (_d = connection === null || connection === void 0 ? void 0 : connection.idpMetadata) === null || _d === void 0 ? void 0 : _d.provider,
594
+ tenant: ((_b = session === null || session === void 0 ? void 0 : session.requested) === null || _b === void 0 ? void 0 : _b.tenant) || (connection === null || connection === void 0 ? void 0 : connection.tenant),
595
+ product: ((_c = session === null || session === void 0 ? void 0 : session.requested) === null || _c === void 0 ? void 0 : _c.product) || (connection === null || connection === void 0 ? void 0 : connection.product),
596
+ clientID: ((_d = session === null || session === void 0 ? void 0 : session.requested) === null || _d === void 0 ? void 0 : _d.client_id) || (connection === null || connection === void 0 ? void 0 : connection.clientID),
597
+ providerName: (_e = connection === null || connection === void 0 ? void 0 : connection.idpMetadata) === null || _e === void 0 ? void 0 : _e.provider,
544
598
  redirectUri: isIdPFlow ? connection === null || connection === void 0 ? void 0 : connection.defaultRedirectUrl : session === null || session === void 0 ? void 0 : session.redirect_uri,
545
599
  issuer,
546
600
  isSAMLFederated: !!isSAMLFederated,
547
601
  isIdPFlow: !!isIdPFlow,
548
- requestedOIDCFlow: !!((_e = session === null || session === void 0 ? void 0 : session.requested) === null || _e === void 0 ? void 0 : _e.oidc),
549
- acsUrl: (_f = session === null || session === void 0 ? void 0 : session.requested) === null || _f === void 0 ? void 0 : _f.acsUrl,
550
- entityId: (_g = session === null || session === void 0 ? void 0 : session.requested) === null || _g === void 0 ? void 0 : _g.entityId,
602
+ requestedOIDCFlow: !!((_f = session === null || session === void 0 ? void 0 : session.requested) === null || _f === void 0 ? void 0 : _f.oidc),
603
+ acsUrl: (_g = session === null || session === void 0 ? void 0 : session.requested) === null || _g === void 0 ? void 0 : _g.acsUrl,
604
+ entityId: (_h = session === null || session === void 0 ? void 0 : session.requested) === null || _h === void 0 ? void 0 : _h.entityId,
551
605
  relayState: RelayState,
552
606
  },
553
607
  });
@@ -573,7 +627,7 @@ class OAuthController {
573
627
  return { redirect_url: redirect.success(redirect_uri, params) };
574
628
  }
575
629
  catch (err) {
576
- const error_description = (0, utils_1.getErrorMessage)(err);
630
+ const error_description = (0, utils_2.getErrorMessage)(err);
577
631
  // Trace the error
578
632
  const traceId = yield this.ssoTracer.saveTrace({
579
633
  error: error_description,
@@ -582,7 +636,7 @@ class OAuthController {
582
636
  tenant: connection.tenant,
583
637
  product: connection.product,
584
638
  clientID: connection.clientID,
585
- providerName: (_h = connection === null || connection === void 0 ? void 0 : connection.idpMetadata) === null || _h === void 0 ? void 0 : _h.provider,
639
+ providerName: (_j = connection === null || connection === void 0 ? void 0 : connection.idpMetadata) === null || _j === void 0 ? void 0 : _j.provider,
586
640
  redirectUri: isIdPFlow ? connection === null || connection === void 0 ? void 0 : connection.defaultRedirectUrl : session === null || session === void 0 ? void 0 : session.redirect_uri,
587
641
  isSAMLFederated,
588
642
  isIdPFlow,
@@ -598,22 +652,23 @@ class OAuthController {
598
652
  throw err;
599
653
  }
600
654
  return {
601
- redirect_url: (0, utils_1.OAuthErrorResponse)({
655
+ redirect_url: (0, utils_2.OAuthErrorResponse)({
602
656
  error: 'access_denied',
603
657
  error_description: traceId ? `${traceId}: ${error_description}` : error_description,
604
658
  redirect_uri,
605
- state: (_j = session.requested) === null || _j === void 0 ? void 0 : _j.state,
659
+ state: (_k = session.requested) === null || _k === void 0 ? void 0 : _k.state,
606
660
  }),
607
661
  };
608
662
  }
609
663
  });
610
664
  }
611
665
  oidcAuthzResponse(body) {
612
- var _a, _b, _c, _d, _e, _f, _g;
666
+ var _a, _b, _c, _d, _e, _f, _g, _h;
613
667
  return __awaiter(this, void 0, void 0, function* () {
614
668
  let oidcConnection;
615
669
  let session;
616
670
  let isSAMLFederated;
671
+ let isOIDCFederated;
617
672
  let redirect_uri;
618
673
  let profile;
619
674
  const callbackParams = body;
@@ -622,12 +677,13 @@ class OAuthController {
622
677
  if (!RelayState) {
623
678
  throw new error_1.JacksonError('State from original request is missing.', 403);
624
679
  }
625
- RelayState = RelayState.replace(utils_1.relayStatePrefix, '');
680
+ RelayState = RelayState.replace(utils_2.relayStatePrefix, '');
626
681
  session = yield this.sessionStore.get(RelayState);
627
682
  if (!session) {
628
683
  throw new error_1.JacksonError('Unable to validate state from the original request.', 403);
629
684
  }
630
685
  isSAMLFederated = session && 'samlFederated' in session;
686
+ isOIDCFederated = session && 'oidcFederated' in session;
631
687
  oidcConnection = yield this.connectionStore.get(session.id);
632
688
  if (!oidcConnection) {
633
689
  throw new error_1.JacksonError('OIDC connection not found.', 403);
@@ -638,24 +694,32 @@ class OAuthController {
638
694
  throw new error_1.JacksonError('Redirect URL from the authorization request could not be retrieved', 403);
639
695
  }
640
696
  if (redirect_uri && !allowed.redirect(redirect_uri, oidcConnection.redirectUrl)) {
641
- throw new error_1.JacksonError('Redirect URL is not allowed.', 403);
697
+ if (isOIDCFederated) {
698
+ if (!allowed.redirect(redirect_uri, (_a = session.oidcFederated) === null || _a === void 0 ? void 0 : _a.redirectUrl)) {
699
+ throw new error_1.JacksonError('Redirect URL is not allowed.', 403);
700
+ }
701
+ }
702
+ else {
703
+ throw new error_1.JacksonError('Redirect URL is not allowed.', 403);
704
+ }
642
705
  }
643
706
  }
644
707
  }
645
708
  catch (err) {
646
709
  yield this.ssoTracer.saveTrace({
647
- error: (0, utils_1.getErrorMessage)(err),
710
+ error: (0, utils_2.getErrorMessage)(err),
648
711
  context: {
649
- tenant: ((_a = session === null || session === void 0 ? void 0 : session.requested) === null || _a === void 0 ? void 0 : _a.tenant) || (oidcConnection === null || oidcConnection === void 0 ? void 0 : oidcConnection.tenant),
650
- product: ((_b = session === null || session === void 0 ? void 0 : session.requested) === null || _b === void 0 ? void 0 : _b.product) || (oidcConnection === null || oidcConnection === void 0 ? void 0 : oidcConnection.product),
651
- clientID: ((_c = session === null || session === void 0 ? void 0 : session.requested) === null || _c === void 0 ? void 0 : _c.client_id) || (oidcConnection === null || oidcConnection === void 0 ? void 0 : oidcConnection.clientID),
652
- providerName: (_d = oidcConnection === null || oidcConnection === void 0 ? void 0 : oidcConnection.oidcProvider) === null || _d === void 0 ? void 0 : _d.provider,
653
- acsUrl: (_e = session === null || session === void 0 ? void 0 : session.requested) === null || _e === void 0 ? void 0 : _e.acsUrl,
654
- entityId: (_f = session === null || session === void 0 ? void 0 : session.requested) === null || _f === void 0 ? void 0 : _f.entityId,
712
+ tenant: ((_b = session === null || session === void 0 ? void 0 : session.requested) === null || _b === void 0 ? void 0 : _b.tenant) || (oidcConnection === null || oidcConnection === void 0 ? void 0 : oidcConnection.tenant),
713
+ product: ((_c = session === null || session === void 0 ? void 0 : session.requested) === null || _c === void 0 ? void 0 : _c.product) || (oidcConnection === null || oidcConnection === void 0 ? void 0 : oidcConnection.product),
714
+ clientID: ((_d = session === null || session === void 0 ? void 0 : session.requested) === null || _d === void 0 ? void 0 : _d.client_id) || (oidcConnection === null || oidcConnection === void 0 ? void 0 : oidcConnection.clientID),
715
+ providerName: (_e = oidcConnection === null || oidcConnection === void 0 ? void 0 : oidcConnection.oidcProvider) === null || _e === void 0 ? void 0 : _e.provider,
716
+ acsUrl: (_f = session === null || session === void 0 ? void 0 : session.requested) === null || _f === void 0 ? void 0 : _f.acsUrl,
717
+ entityId: (_g = session === null || session === void 0 ? void 0 : session.requested) === null || _g === void 0 ? void 0 : _g.entityId,
655
718
  redirectUri: redirect_uri,
656
719
  relayState: RelayState,
657
720
  isSAMLFederated: !!isSAMLFederated,
658
- requestedOIDCFlow: !!((_g = session === null || session === void 0 ? void 0 : session.requested) === null || _g === void 0 ? void 0 : _g.oidc),
721
+ isOIDCFederated: !!isOIDCFederated,
722
+ requestedOIDCFlow: !!((_h = session === null || session === void 0 ? void 0 : session.requested) === null || _h === void 0 ? void 0 : _h.oidc),
659
723
  },
660
724
  });
661
725
  // Rethrow err and redirect to Jackson error page
@@ -677,7 +741,7 @@ class OAuthController {
677
741
  nonce: session.oidcNonce,
678
742
  state: callbackParams.state,
679
743
  });
680
- profile = yield (0, utils_1.extractOIDCUserProfile)(tokenSet, oidcClient);
744
+ profile = yield (0, utils_2.extractOIDCUserProfile)(tokenSet, oidcClient);
681
745
  if (isSAMLFederated) {
682
746
  const { responseForm } = yield this.ssoHandler.createSAMLResponse({ profile, session });
683
747
  yield this.sessionStore.delete(RelayState);
@@ -695,7 +759,7 @@ class OAuthController {
695
759
  }
696
760
  catch (err) {
697
761
  const { error, error_description, error_uri, session_state, scope, stack } = err;
698
- const error_message = (0, utils_1.getErrorMessage)(err);
762
+ const error_message = (0, utils_2.getErrorMessage)(err);
699
763
  const traceId = yield this.ssoTracer.saveTrace({
700
764
  error: error_message,
701
765
  context: {
@@ -706,6 +770,7 @@ class OAuthController {
706
770
  redirectUri: redirect_uri,
707
771
  relayState: RelayState,
708
772
  isSAMLFederated: !!isSAMLFederated,
773
+ isOIDCFederated: !!isOIDCFederated,
709
774
  acsUrl: session.requested.acsUrl,
710
775
  entityId: session.requested.entityId,
711
776
  requestedOIDCFlow: !!session.requested.oidc,
@@ -723,7 +788,7 @@ class OAuthController {
723
788
  throw err;
724
789
  }
725
790
  return {
726
- redirect_url: (0, utils_1.OAuthErrorResponse)({
791
+ redirect_url: (0, utils_2.OAuthErrorResponse)({
727
792
  error: error || 'server_error',
728
793
  error_description: traceId ? `${traceId}: ${error_message}` : error_message,
729
794
  redirect_uri: redirect_uri,
@@ -852,7 +917,7 @@ class OAuthController {
852
917
  else if (client_id && client_secret) {
853
918
  // check if we have an encoded client_id
854
919
  if (client_id !== 'dummy') {
855
- const sp = (0, utils_1.getEncodedTenantProduct)(client_id);
920
+ const sp = (0, utils_2.getEncodedTenantProduct)(client_id);
856
921
  if (!sp) {
857
922
  // OAuth flow
858
923
  if (client_id !== codeVal.clientID || client_secret !== codeVal.clientSecret) {
@@ -886,12 +951,12 @@ class OAuthController {
886
951
  const requestHasNonce = !!((_f = codeVal.requested) === null || _f === void 0 ? void 0 : _f.nonce);
887
952
  if (requestedOIDCFlow) {
888
953
  const { jwtSigningKeys, jwsAlg } = (_g = this.opts.openid) !== null && _g !== void 0 ? _g : {};
889
- if (!jwtSigningKeys || !(0, utils_1.isJWSKeyPairLoaded)(jwtSigningKeys)) {
954
+ if (!jwtSigningKeys || !(0, utils_2.isJWSKeyPairLoaded)(jwtSigningKeys)) {
890
955
  throw new error_1.JacksonError('JWT signing keys are not loaded', 500);
891
956
  }
892
957
  let claims = requestHasNonce ? { nonce: codeVal.requested.nonce } : {};
893
958
  claims = Object.assign(Object.assign({}, claims), { id: codeVal.profile.claims.id, email: codeVal.profile.claims.email, firstName: codeVal.profile.claims.firstName, lastName: codeVal.profile.claims.lastName, roles: codeVal.profile.claims.roles, groups: codeVal.profile.claims.groups });
894
- const signingKey = yield (0, utils_1.loadJWSPrivateKey)(jwtSigningKeys.private, jwsAlg);
959
+ const signingKey = yield (0, utils_2.loadJWSPrivateKey)(jwtSigningKeys.private, jwsAlg);
895
960
  const id_token = yield new jose.SignJWT(claims)
896
961
  .setProtectedHeader({ alg: jwsAlg })
897
962
  .setIssuedAt()