@backstage/plugin-auth-backend 0.0.0-nightly-202111282332 → 0.0.0-nightly-2021112922954

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.
package/dist/index.cjs.js CHANGED
@@ -5,25 +5,25 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var express = require('express');
6
6
  var Router = require('express-promise-router');
7
7
  var cookieParser = require('cookie-parser');
8
- var passportGithub2 = require('passport-github2');
9
- var jwtDecoder = require('jwt-decode');
8
+ var OAuth2Strategy = require('passport-oauth2');
10
9
  var errors = require('@backstage/errors');
11
10
  var pickBy = require('lodash/pickBy');
12
11
  var crypto = require('crypto');
13
12
  var url = require('url');
14
13
  var catalogModel = require('@backstage/catalog-model');
14
+ var jwtDecoder = require('jwt-decode');
15
+ var fetch = require('node-fetch');
16
+ var NodeCache = require('node-cache');
17
+ var jose = require('jose');
18
+ var passportBitbucketOauth2 = require('passport-bitbucket-oauth2');
19
+ var passportGithub2 = require('passport-github2');
15
20
  var passportGitlab2 = require('passport-gitlab2');
16
21
  var passportGoogleOauth20 = require('passport-google-oauth20');
17
22
  var passportMicrosoft = require('passport-microsoft');
18
- var fetch = require('node-fetch');
19
- var OAuth2Strategy = require('passport-oauth2');
20
23
  var openidClient = require('openid-client');
21
24
  var passportOktaOauth = require('passport-okta-oauth');
22
- var passportBitbucketOauth2 = require('passport-bitbucket-oauth2');
23
- var NodeCache = require('node-cache');
24
- var jose = require('jose');
25
- var passportSaml = require('passport-saml');
26
25
  var passportOneloginOauth = require('passport-onelogin-oauth');
26
+ var passportSaml = require('passport-saml');
27
27
  var catalogClient = require('@backstage/catalog-client');
28
28
  var uuid = require('uuid');
29
29
  var luxon = require('luxon');
@@ -57,128 +57,69 @@ function _interopNamespace(e) {
57
57
  var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
58
58
  var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
59
59
  var cookieParser__default = /*#__PURE__*/_interopDefaultLegacy(cookieParser);
60
- var jwtDecoder__default = /*#__PURE__*/_interopDefaultLegacy(jwtDecoder);
60
+ var OAuth2Strategy__default = /*#__PURE__*/_interopDefaultLegacy(OAuth2Strategy);
61
61
  var pickBy__default = /*#__PURE__*/_interopDefaultLegacy(pickBy);
62
62
  var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
63
63
  var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
64
+ var jwtDecoder__default = /*#__PURE__*/_interopDefaultLegacy(jwtDecoder);
64
65
  var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
65
- var OAuth2Strategy__default = /*#__PURE__*/_interopDefaultLegacy(OAuth2Strategy);
66
66
  var NodeCache__default = /*#__PURE__*/_interopDefaultLegacy(NodeCache);
67
67
  var session__default = /*#__PURE__*/_interopDefaultLegacy(session);
68
68
  var passport__default = /*#__PURE__*/_interopDefaultLegacy(passport);
69
69
 
70
- const makeProfileInfo = (profile, idToken) => {
71
- var _a, _b;
72
- let email = void 0;
73
- if (profile.emails && profile.emails.length > 0) {
74
- const [firstEmail] = profile.emails;
75
- email = firstEmail.value;
76
- }
77
- let picture = void 0;
78
- if (profile.avatarUrl) {
79
- picture = profile.avatarUrl;
80
- } else if (profile.photos && profile.photos.length > 0) {
81
- const [firstPhoto] = profile.photos;
82
- picture = firstPhoto.value;
83
- }
84
- let displayName = (_b = (_a = profile.displayName) != null ? _a : profile.username) != null ? _b : profile.id;
85
- if ((!email || !picture || !displayName) && idToken) {
86
- try {
87
- const decoded = jwtDecoder__default["default"](idToken);
88
- if (!email && decoded.email) {
89
- email = decoded.email;
90
- }
91
- if (!picture && decoded.picture) {
92
- picture = decoded.picture;
93
- }
94
- if (!displayName && decoded.name) {
95
- displayName = decoded.name;
96
- }
97
- } catch (e) {
98
- throw new Error(`Failed to parse id token and get profile info, ${e}`);
70
+ const defaultScopes = ["offline_access", "read:me"];
71
+ class AtlassianStrategy extends OAuth2Strategy__default["default"] {
72
+ constructor(options, verify) {
73
+ if (!options.scope) {
74
+ throw new TypeError("Atlassian requires a scope option");
99
75
  }
100
- }
101
- return {
102
- email,
103
- picture,
104
- displayName
105
- };
106
- };
107
- const executeRedirectStrategy = async (req, providerStrategy, options) => {
108
- return new Promise((resolve) => {
109
- const strategy = Object.create(providerStrategy);
110
- strategy.redirect = (url, status) => {
111
- resolve({ url, status: status != null ? status : void 0 });
112
- };
113
- strategy.authenticate(req, { ...options });
114
- });
115
- };
116
- const executeFrameHandlerStrategy = async (req, providerStrategy) => {
117
- return new Promise((resolve, reject) => {
118
- const strategy = Object.create(providerStrategy);
119
- strategy.success = (result, privateInfo) => {
120
- resolve({ result, privateInfo });
121
- };
122
- strategy.fail = (info) => {
123
- var _a;
124
- reject(new Error(`Authentication rejected, ${(_a = info.message) != null ? _a : ""}`));
125
- };
126
- strategy.error = (error) => {
127
- var _a;
128
- let message = `Authentication failed, ${error.message}`;
129
- if ((_a = error.oauthError) == null ? void 0 : _a.data) {
130
- try {
131
- const errorData = JSON.parse(error.oauthError.data);
132
- if (errorData.message) {
133
- message += ` - ${errorData.message}`;
134
- }
135
- } catch (parseError) {
136
- message += ` - ${error.oauthError}`;
137
- }
138
- }
139
- reject(new Error(message));
76
+ const scopes = options.scope.split(" ");
77
+ const optionsWithURLs = {
78
+ ...options,
79
+ authorizationURL: `https://auth.atlassian.com/authorize`,
80
+ tokenURL: `https://auth.atlassian.com/oauth/token`,
81
+ scope: Array.from(/* @__PURE__ */ new Set([...defaultScopes, ...scopes]))
140
82
  };
141
- strategy.redirect = () => {
142
- reject(new Error("Unexpected redirect"));
83
+ super(optionsWithURLs, verify);
84
+ this.profileURL = "https://api.atlassian.com/me";
85
+ this.name = "atlassian";
86
+ this._oauth2.useAuthorizationHeaderforGET(true);
87
+ }
88
+ authorizationParams() {
89
+ return {
90
+ audience: "api.atlassian.com",
91
+ prompt: "consent"
143
92
  };
144
- strategy.authenticate(req, {});
145
- });
146
- };
147
- const executeRefreshTokenStrategy = async (providerStrategy, refreshToken, scope) => {
148
- return new Promise((resolve, reject) => {
149
- const anyStrategy = providerStrategy;
150
- const OAuth2 = anyStrategy._oauth2.constructor;
151
- const oauth2 = new OAuth2(anyStrategy._oauth2._clientId, anyStrategy._oauth2._clientSecret, anyStrategy._oauth2._baseSite, anyStrategy._oauth2._authorizeUrl, anyStrategy._refreshURL || anyStrategy._oauth2._accessTokenUrl, anyStrategy._oauth2._customHeaders);
152
- oauth2.getOAuthAccessToken(refreshToken, {
153
- scope,
154
- grant_type: "refresh_token"
155
- }, (err, accessToken, newRefreshToken, params) => {
93
+ }
94
+ userProfile(accessToken, done) {
95
+ this._oauth2.get(this.profileURL, accessToken, (err, body) => {
156
96
  if (err) {
157
- reject(new Error(`Failed to refresh access token ${err.toString()}`));
97
+ return done(new OAuth2Strategy.InternalOAuthError("Failed to fetch user profile", err.statusCode));
158
98
  }
159
- if (!accessToken) {
160
- reject(new Error(`Failed to refresh access token, no access token received`));
99
+ if (!body) {
100
+ return done(new Error("Failed to fetch user profile, body cannot be empty"));
161
101
  }
162
- resolve({
163
- accessToken,
164
- refreshToken: newRefreshToken,
165
- params
166
- });
167
- });
168
- });
169
- };
170
- const executeFetchUserProfileStrategy = async (providerStrategy, accessToken) => {
171
- return new Promise((resolve, reject) => {
172
- const anyStrategy = providerStrategy;
173
- anyStrategy.userProfile(accessToken, (error, rawProfile) => {
174
- if (error) {
175
- reject(error);
176
- } else {
177
- resolve(rawProfile);
102
+ try {
103
+ const json = typeof body !== "string" ? body.toString() : body;
104
+ const profile = AtlassianStrategy.parse(json);
105
+ return done(null, profile);
106
+ } catch (e) {
107
+ return done(new Error("Failed to parse user profile"));
178
108
  }
179
109
  });
180
- });
181
- };
110
+ }
111
+ static parse(json) {
112
+ const resp = JSON.parse(json);
113
+ return {
114
+ id: resp.account_id,
115
+ provider: "atlassian",
116
+ username: resp.nickname,
117
+ displayName: resp.name,
118
+ emails: [{ value: resp.email }],
119
+ photos: [{ value: resp.picture }]
120
+ };
121
+ }
122
+ }
182
123
 
183
124
  const readState = (stateString) => {
184
125
  var _a, _b;
@@ -460,10 +401,10 @@ class OAuthAdapter {
460
401
  }
461
402
  const scope = (_b = (_a = req.query.scope) == null ? void 0 : _a.toString()) != null ? _b : "";
462
403
  const forwardReq = Object.assign(req, { scope, refreshToken });
463
- const response = await this.handlers.refresh(forwardReq);
404
+ const { response, refreshToken: newRefreshToken } = await this.handlers.refresh(forwardReq);
464
405
  const backstageIdentity = await this.populateIdentity(response.backstageIdentity);
465
- if (response.providerInfo.refreshToken && response.providerInfo.refreshToken !== refreshToken) {
466
- this.setRefreshTokenCookie(res, response.providerInfo.refreshToken);
406
+ if (newRefreshToken && newRefreshToken !== refreshToken) {
407
+ this.setRefreshTokenCookie(res, newRefreshToken);
467
408
  }
468
409
  res.status(200).json({ ...response, backstageIdentity });
469
410
  } catch (error) {
@@ -488,101 +429,347 @@ class OAuthAdapter {
488
429
  }
489
430
  }
490
431
 
491
- class CatalogIdentityClient {
492
- constructor(options) {
493
- this.catalogApi = options.catalogApi;
494
- this.tokenIssuer = options.tokenIssuer;
432
+ const makeProfileInfo = (profile, idToken) => {
433
+ var _a, _b;
434
+ let email = void 0;
435
+ if (profile.emails && profile.emails.length > 0) {
436
+ const [firstEmail] = profile.emails;
437
+ email = firstEmail.value;
495
438
  }
496
- async findUser(query) {
497
- const filter = {
498
- kind: "user"
499
- };
500
- for (const [key, value] of Object.entries(query.annotations)) {
501
- filter[`metadata.annotations.${key}`] = value;
502
- }
503
- const token = await this.tokenIssuer.issueToken({
504
- claims: { sub: "backstage.io/auth-backend" }
505
- });
506
- const { items } = await this.catalogApi.getEntities({ filter }, { token });
507
- if (items.length !== 1) {
508
- if (items.length > 1) {
509
- throw new errors.ConflictError("User lookup resulted in multiple matches");
510
- } else {
511
- throw new errors.NotFoundError("User not found");
512
- }
513
- }
514
- return items[0];
439
+ let picture = void 0;
440
+ if (profile.avatarUrl) {
441
+ picture = profile.avatarUrl;
442
+ } else if (profile.photos && profile.photos.length > 0) {
443
+ const [firstPhoto] = profile.photos;
444
+ picture = firstPhoto.value;
515
445
  }
516
- async resolveCatalogMembership(query) {
517
- const { entityRefs, logger } = query;
518
- const resolvedEntityRefs = entityRefs.map((ref) => {
519
- try {
520
- const parsedRef = catalogModel.parseEntityRef(ref.toLocaleLowerCase("en-US"), {
521
- defaultKind: "user",
522
- defaultNamespace: "default"
523
- });
524
- return parsedRef;
525
- } catch {
526
- logger == null ? void 0 : logger.warn(`Failed to parse entityRef from ${ref}, ignoring`);
527
- return null;
446
+ let displayName = (_b = (_a = profile.displayName) != null ? _a : profile.username) != null ? _b : profile.id;
447
+ if ((!email || !picture || !displayName) && idToken) {
448
+ try {
449
+ const decoded = jwtDecoder__default["default"](idToken);
450
+ if (!email && decoded.email) {
451
+ email = decoded.email;
528
452
  }
529
- }).filter((ref) => ref !== null);
530
- const filter = resolvedEntityRefs.map((ref) => ({
531
- kind: ref.kind,
532
- "metadata.namespace": ref.namespace,
533
- "metadata.name": ref.name
534
- }));
535
- const entities = await this.catalogApi.getEntities({ filter }).then((r) => r.items);
536
- if (entityRefs.length !== entities.length) {
537
- const foundEntityNames = entities.map(catalogModel.stringifyEntityRef);
538
- const missingEntityNames = resolvedEntityRefs.map(catalogModel.stringifyEntityRef).filter((s) => !foundEntityNames.includes(s));
539
- logger == null ? void 0 : logger.debug(`Entities not found for refs ${missingEntityNames.join()}`);
453
+ if (!picture && decoded.picture) {
454
+ picture = decoded.picture;
455
+ }
456
+ if (!displayName && decoded.name) {
457
+ displayName = decoded.name;
458
+ }
459
+ } catch (e) {
460
+ throw new Error(`Failed to parse id token and get profile info, ${e}`);
540
461
  }
541
- const memberOf = entities.flatMap((e) => {
542
- var _a, _b;
543
- return (_b = (_a = e.relations) == null ? void 0 : _a.filter((r) => r.type === catalogModel.RELATION_MEMBER_OF).map((r) => r.target)) != null ? _b : [];
544
- });
545
- const newEntityRefs = [
546
- ...new Set(resolvedEntityRefs.concat(memberOf).map(catalogModel.stringifyEntityRef))
547
- ];
548
- logger == null ? void 0 : logger.debug(`Found catalog membership: ${newEntityRefs.join()}`);
549
- return newEntityRefs;
550
462
  }
551
- }
552
-
553
- function getEntityClaims(entity) {
554
- var _a, _b;
555
- const userRef = catalogModel.stringifyEntityRef(entity);
556
- const membershipRefs = (_b = (_a = entity.relations) == null ? void 0 : _a.filter((r) => r.type === catalogModel.RELATION_MEMBER_OF && r.target.kind.toLocaleLowerCase("en-US") === "group").map((r) => catalogModel.stringifyEntityRef(r.target))) != null ? _b : [];
463
+ return {
464
+ email,
465
+ picture,
466
+ displayName
467
+ };
468
+ };
469
+ const executeRedirectStrategy = async (req, providerStrategy, options) => {
470
+ return new Promise((resolve) => {
471
+ const strategy = Object.create(providerStrategy);
472
+ strategy.redirect = (url, status) => {
473
+ resolve({ url, status: status != null ? status : void 0 });
474
+ };
475
+ strategy.authenticate(req, { ...options });
476
+ });
477
+ };
478
+ const executeFrameHandlerStrategy = async (req, providerStrategy) => {
479
+ return new Promise((resolve, reject) => {
480
+ const strategy = Object.create(providerStrategy);
481
+ strategy.success = (result, privateInfo) => {
482
+ resolve({ result, privateInfo });
483
+ };
484
+ strategy.fail = (info) => {
485
+ var _a;
486
+ reject(new Error(`Authentication rejected, ${(_a = info.message) != null ? _a : ""}`));
487
+ };
488
+ strategy.error = (error) => {
489
+ var _a;
490
+ let message = `Authentication failed, ${error.message}`;
491
+ if ((_a = error.oauthError) == null ? void 0 : _a.data) {
492
+ try {
493
+ const errorData = JSON.parse(error.oauthError.data);
494
+ if (errorData.message) {
495
+ message += ` - ${errorData.message}`;
496
+ }
497
+ } catch (parseError) {
498
+ message += ` - ${error.oauthError}`;
499
+ }
500
+ }
501
+ reject(new Error(message));
502
+ };
503
+ strategy.redirect = () => {
504
+ reject(new Error("Unexpected redirect"));
505
+ };
506
+ strategy.authenticate(req, {});
507
+ });
508
+ };
509
+ const executeRefreshTokenStrategy = async (providerStrategy, refreshToken, scope) => {
510
+ return new Promise((resolve, reject) => {
511
+ const anyStrategy = providerStrategy;
512
+ const OAuth2 = anyStrategy._oauth2.constructor;
513
+ const oauth2 = new OAuth2(anyStrategy._oauth2._clientId, anyStrategy._oauth2._clientSecret, anyStrategy._oauth2._baseSite, anyStrategy._oauth2._authorizeUrl, anyStrategy._refreshURL || anyStrategy._oauth2._accessTokenUrl, anyStrategy._oauth2._customHeaders);
514
+ oauth2.getOAuthAccessToken(refreshToken, {
515
+ scope,
516
+ grant_type: "refresh_token"
517
+ }, (err, accessToken, newRefreshToken, params) => {
518
+ if (err) {
519
+ reject(new Error(`Failed to refresh access token ${err.toString()}`));
520
+ }
521
+ if (!accessToken) {
522
+ reject(new Error(`Failed to refresh access token, no access token received`));
523
+ }
524
+ resolve({
525
+ accessToken,
526
+ refreshToken: newRefreshToken,
527
+ params
528
+ });
529
+ });
530
+ });
531
+ };
532
+ const executeFetchUserProfileStrategy = async (providerStrategy, accessToken) => {
533
+ return new Promise((resolve, reject) => {
534
+ const anyStrategy = providerStrategy;
535
+ anyStrategy.userProfile(accessToken, (error, rawProfile) => {
536
+ if (error) {
537
+ reject(error);
538
+ } else {
539
+ resolve(rawProfile);
540
+ }
541
+ });
542
+ });
543
+ };
544
+
545
+ class CatalogIdentityClient {
546
+ constructor(options) {
547
+ this.catalogApi = options.catalogApi;
548
+ this.tokenIssuer = options.tokenIssuer;
549
+ }
550
+ async findUser(query) {
551
+ const filter = {
552
+ kind: "user"
553
+ };
554
+ for (const [key, value] of Object.entries(query.annotations)) {
555
+ filter[`metadata.annotations.${key}`] = value;
556
+ }
557
+ const token = await this.tokenIssuer.issueToken({
558
+ claims: { sub: "backstage.io/auth-backend" }
559
+ });
560
+ const { items } = await this.catalogApi.getEntities({ filter }, { token });
561
+ if (items.length !== 1) {
562
+ if (items.length > 1) {
563
+ throw new errors.ConflictError("User lookup resulted in multiple matches");
564
+ } else {
565
+ throw new errors.NotFoundError("User not found");
566
+ }
567
+ }
568
+ return items[0];
569
+ }
570
+ async resolveCatalogMembership(query) {
571
+ const { entityRefs, logger } = query;
572
+ const resolvedEntityRefs = entityRefs.map((ref) => {
573
+ try {
574
+ const parsedRef = catalogModel.parseEntityRef(ref.toLocaleLowerCase("en-US"), {
575
+ defaultKind: "user",
576
+ defaultNamespace: "default"
577
+ });
578
+ return parsedRef;
579
+ } catch {
580
+ logger == null ? void 0 : logger.warn(`Failed to parse entityRef from ${ref}, ignoring`);
581
+ return null;
582
+ }
583
+ }).filter((ref) => ref !== null);
584
+ const filter = resolvedEntityRefs.map((ref) => ({
585
+ kind: ref.kind,
586
+ "metadata.namespace": ref.namespace,
587
+ "metadata.name": ref.name
588
+ }));
589
+ const entities = await this.catalogApi.getEntities({ filter }).then((r) => r.items);
590
+ if (entityRefs.length !== entities.length) {
591
+ const foundEntityNames = entities.map(catalogModel.stringifyEntityRef);
592
+ const missingEntityNames = resolvedEntityRefs.map(catalogModel.stringifyEntityRef).filter((s) => !foundEntityNames.includes(s));
593
+ logger == null ? void 0 : logger.debug(`Entities not found for refs ${missingEntityNames.join()}`);
594
+ }
595
+ const memberOf = entities.flatMap((e) => {
596
+ var _a, _b;
597
+ return (_b = (_a = e.relations) == null ? void 0 : _a.filter((r) => r.type === catalogModel.RELATION_MEMBER_OF).map((r) => r.target)) != null ? _b : [];
598
+ });
599
+ const newEntityRefs = [
600
+ ...new Set(resolvedEntityRefs.concat(memberOf).map(catalogModel.stringifyEntityRef))
601
+ ];
602
+ logger == null ? void 0 : logger.debug(`Found catalog membership: ${newEntityRefs.join()}`);
603
+ return newEntityRefs;
604
+ }
605
+ }
606
+
607
+ function getEntityClaims(entity) {
608
+ var _a, _b;
609
+ const userRef = catalogModel.stringifyEntityRef(entity);
610
+ const membershipRefs = (_b = (_a = entity.relations) == null ? void 0 : _a.filter((r) => r.type === catalogModel.RELATION_MEMBER_OF && r.target.kind.toLocaleLowerCase("en-US") === "group").map((r) => catalogModel.stringifyEntityRef(r.target))) != null ? _b : [];
557
611
  return {
558
612
  sub: userRef,
559
613
  ent: [userRef, ...membershipRefs]
560
614
  };
561
615
  }
562
616
 
563
- class GithubAuthProvider {
617
+ const atlassianDefaultAuthHandler = async ({
618
+ fullProfile,
619
+ params
620
+ }) => ({
621
+ profile: makeProfileInfo(fullProfile, params.id_token)
622
+ });
623
+ class AtlassianAuthProvider {
624
+ constructor(options) {
625
+ this.catalogIdentityClient = options.catalogIdentityClient;
626
+ this.logger = options.logger;
627
+ this.tokenIssuer = options.tokenIssuer;
628
+ this.authHandler = options.authHandler;
629
+ this.signInResolver = options.signInResolver;
630
+ this._strategy = new AtlassianStrategy({
631
+ clientID: options.clientId,
632
+ clientSecret: options.clientSecret,
633
+ callbackURL: options.callbackUrl,
634
+ scope: options.scopes
635
+ }, (accessToken, refreshToken, params, fullProfile, done) => {
636
+ done(void 0, {
637
+ fullProfile,
638
+ accessToken,
639
+ refreshToken,
640
+ params
641
+ });
642
+ });
643
+ }
644
+ async start(req) {
645
+ return await executeRedirectStrategy(req, this._strategy, {
646
+ state: encodeState(req.state)
647
+ });
648
+ }
649
+ async handler(req) {
650
+ const { result } = await executeFrameHandlerStrategy(req, this._strategy);
651
+ return {
652
+ response: await this.handleResult(result),
653
+ refreshToken: result.refreshToken
654
+ };
655
+ }
656
+ async handleResult(result) {
657
+ const { profile } = await this.authHandler(result);
658
+ const response = {
659
+ providerInfo: {
660
+ idToken: result.params.id_token,
661
+ accessToken: result.accessToken,
662
+ scope: result.params.scope,
663
+ expiresInSeconds: result.params.expires_in
664
+ },
665
+ profile
666
+ };
667
+ if (this.signInResolver) {
668
+ response.backstageIdentity = await this.signInResolver({
669
+ result,
670
+ profile
671
+ }, {
672
+ tokenIssuer: this.tokenIssuer,
673
+ catalogIdentityClient: this.catalogIdentityClient,
674
+ logger: this.logger
675
+ });
676
+ }
677
+ return response;
678
+ }
679
+ async refresh(req) {
680
+ const { accessToken, params, refreshToken } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
681
+ const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
682
+ return {
683
+ response: await this.handleResult({
684
+ fullProfile,
685
+ params,
686
+ accessToken
687
+ }),
688
+ refreshToken
689
+ };
690
+ }
691
+ }
692
+ const createAtlassianProvider = (options) => {
693
+ return ({
694
+ providerId,
695
+ globalConfig,
696
+ config,
697
+ tokenIssuer,
698
+ catalogApi,
699
+ logger
700
+ }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
701
+ var _a, _b;
702
+ const clientId = envConfig.getString("clientId");
703
+ const clientSecret = envConfig.getString("clientSecret");
704
+ const scopes = envConfig.getString("scopes");
705
+ const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
706
+ const catalogIdentityClient = new CatalogIdentityClient({
707
+ catalogApi,
708
+ tokenIssuer
709
+ });
710
+ const authHandler = (_a = options == null ? void 0 : options.authHandler) != null ? _a : atlassianDefaultAuthHandler;
711
+ const provider = new AtlassianAuthProvider({
712
+ clientId,
713
+ clientSecret,
714
+ scopes,
715
+ callbackUrl,
716
+ authHandler,
717
+ signInResolver: (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver,
718
+ catalogIdentityClient,
719
+ logger,
720
+ tokenIssuer
721
+ });
722
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
723
+ disableRefresh: true,
724
+ providerId,
725
+ tokenIssuer
726
+ });
727
+ });
728
+ };
729
+
730
+ class Auth0Strategy extends OAuth2Strategy__default["default"] {
731
+ constructor(options, verify) {
732
+ const optionsWithURLs = {
733
+ ...options,
734
+ authorizationURL: `https://${options.domain}/authorize`,
735
+ tokenURL: `https://${options.domain}/oauth/token`,
736
+ userInfoURL: `https://${options.domain}/userinfo`,
737
+ apiUrl: `https://${options.domain}/api`
738
+ };
739
+ super(optionsWithURLs, verify);
740
+ }
741
+ }
742
+
743
+ class Auth0AuthProvider {
564
744
  constructor(options) {
565
745
  this.signInResolver = options.signInResolver;
566
746
  this.authHandler = options.authHandler;
567
- this.stateEncoder = options.stateEncoder;
568
747
  this.tokenIssuer = options.tokenIssuer;
569
748
  this.catalogIdentityClient = options.catalogIdentityClient;
570
749
  this.logger = options.logger;
571
- this._strategy = new passportGithub2.Strategy({
750
+ this._strategy = new Auth0Strategy({
572
751
  clientID: options.clientId,
573
752
  clientSecret: options.clientSecret,
574
753
  callbackURL: options.callbackUrl,
575
- tokenURL: options.tokenUrl,
576
- userProfileURL: options.userProfileUrl,
577
- authorizationURL: options.authorizationUrl
754
+ domain: options.domain,
755
+ passReqToCallback: false
578
756
  }, (accessToken, refreshToken, params, fullProfile, done) => {
579
- done(void 0, { fullProfile, params, accessToken }, { refreshToken });
757
+ done(void 0, {
758
+ fullProfile,
759
+ accessToken,
760
+ refreshToken,
761
+ params
762
+ }, {
763
+ refreshToken
764
+ });
580
765
  });
581
766
  }
582
767
  async start(req) {
583
768
  return await executeRedirectStrategy(req, this._strategy, {
769
+ accessType: "offline",
770
+ prompt: "consent",
584
771
  scope: req.scope,
585
- state: (await this.stateEncoder(req)).encodedState
772
+ state: encodeState(req.state)
586
773
  });
587
774
  }
588
775
  async handler(req) {
@@ -593,28 +780,25 @@ class GithubAuthProvider {
593
780
  };
594
781
  }
595
782
  async refresh(req) {
596
- const {
597
- accessToken,
598
- refreshToken: newRefreshToken,
599
- params
600
- } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
783
+ const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
601
784
  const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
602
- return this.handleResult({
603
- fullProfile,
604
- params,
605
- accessToken,
606
- refreshToken: newRefreshToken
607
- });
785
+ return {
786
+ response: await this.handleResult({
787
+ fullProfile,
788
+ params,
789
+ accessToken
790
+ }),
791
+ refreshToken
792
+ };
608
793
  }
609
794
  async handleResult(result) {
610
795
  const { profile } = await this.authHandler(result);
611
- const expiresInStr = result.params.expires_in;
612
796
  const response = {
613
797
  providerInfo: {
798
+ idToken: result.params.id_token,
614
799
  accessToken: result.accessToken,
615
- refreshToken: result.refreshToken,
616
800
  scope: result.params.scope,
617
- expiresInSeconds: expiresInStr === void 0 ? void 0 : Number(expiresInStr)
801
+ expiresInSeconds: result.params.expires_in
618
802
  },
619
803
  profile
620
804
  };
@@ -631,15 +815,15 @@ class GithubAuthProvider {
631
815
  return response;
632
816
  }
633
817
  }
634
- const githubDefaultSignInResolver = async (info, ctx) => {
635
- const { fullProfile } = info.result;
636
- const userId = fullProfile.username || fullProfile.id;
637
- const token = await ctx.tokenIssuer.issueToken({
638
- claims: { sub: userId, ent: [`user:default/${userId}`] }
639
- });
640
- return { id: userId, token };
818
+ const defaultSignInResolver$1 = async (info) => {
819
+ const { profile } = info;
820
+ if (!profile.email) {
821
+ throw new Error("Profile does not contain an email");
822
+ }
823
+ const id = profile.email.split("@")[0];
824
+ return { id, token: "" };
641
825
  };
642
- const createGithubProvider = (options) => {
826
+ const createAuth0Provider = (options) => {
643
827
  return ({
644
828
  providerId,
645
829
  globalConfig,
@@ -648,90 +832,193 @@ const createGithubProvider = (options) => {
648
832
  catalogApi,
649
833
  logger
650
834
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
651
- var _a, _b, _c;
835
+ var _a, _b;
652
836
  const clientId = envConfig.getString("clientId");
653
837
  const clientSecret = envConfig.getString("clientSecret");
654
- const enterpriseInstanceUrl = envConfig.getOptionalString("enterpriseInstanceUrl");
655
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
656
- const authorizationUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/login/oauth/authorize` : void 0;
657
- const tokenUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/login/oauth/access_token` : void 0;
658
- const userProfileUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/api/v3/user` : void 0;
659
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
838
+ const domain = envConfig.getString("domain");
839
+ const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
660
840
  const catalogIdentityClient = new CatalogIdentityClient({
661
841
  catalogApi,
662
842
  tokenIssuer
663
843
  });
664
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
665
- profile: makeProfileInfo(fullProfile)
666
- });
667
- const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : githubDefaultSignInResolver;
668
- const signInResolver = (info) => signInResolverFn(info, {
669
- catalogIdentityClient,
670
- tokenIssuer,
671
- logger
844
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
845
+ profile: makeProfileInfo(fullProfile, params.id_token)
672
846
  });
673
- const stateEncoder = (_c = options == null ? void 0 : options.stateEncoder) != null ? _c : async (req) => {
674
- return { encodedState: encodeState(req.state) };
675
- };
676
- const provider = new GithubAuthProvider({
847
+ const signInResolver = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : defaultSignInResolver$1;
848
+ const provider = new Auth0AuthProvider({
677
849
  clientId,
678
850
  clientSecret,
679
851
  callbackUrl,
680
- tokenUrl,
681
- userProfileUrl,
682
- authorizationUrl,
683
- signInResolver,
852
+ domain,
684
853
  authHandler,
854
+ signInResolver,
685
855
  tokenIssuer,
686
856
  catalogIdentityClient,
687
- stateEncoder,
688
857
  logger
689
858
  });
690
859
  return OAuthAdapter.fromConfig(globalConfig, provider, {
691
- persistScopes: true,
860
+ disableRefresh: true,
692
861
  providerId,
693
862
  tokenIssuer
694
863
  });
695
864
  });
696
865
  };
697
866
 
698
- const gitlabDefaultSignInResolver = async (info, ctx) => {
699
- const { profile, result } = info;
700
- let id = result.fullProfile.id;
701
- if (profile.email) {
702
- id = profile.email.split("@")[0];
703
- }
704
- const token = await ctx.tokenIssuer.issueToken({
705
- claims: { sub: id, ent: [`user:default/${id}`] }
706
- });
707
- return { id, token };
867
+ const ALB_JWT_HEADER = "x-amzn-oidc-data";
868
+ const ALB_ACCESSTOKEN_HEADER = "x-amzn-oidc-accesstoken";
869
+ const getJWTHeaders = (input) => {
870
+ const encoded = input.split(".")[0];
871
+ return JSON.parse(Buffer.from(encoded, "base64").toString("utf8"));
708
872
  };
709
- const gitlabDefaultAuthHandler = async ({
710
- fullProfile,
711
- params
712
- }) => ({
713
- profile: makeProfileInfo(fullProfile, params.id_token)
714
- });
715
- class GitlabAuthProvider {
873
+ class AwsAlbAuthProvider {
874
+ constructor(options) {
875
+ this.region = options.region;
876
+ this.issuer = options.issuer;
877
+ this.authHandler = options.authHandler;
878
+ this.signInResolver = options.signInResolver;
879
+ this.tokenIssuer = options.tokenIssuer;
880
+ this.catalogIdentityClient = options.catalogIdentityClient;
881
+ this.logger = options.logger;
882
+ this.keyCache = new NodeCache__default["default"]({ stdTTL: 3600 });
883
+ }
884
+ frameHandler() {
885
+ return Promise.resolve(void 0);
886
+ }
887
+ async refresh(req, res) {
888
+ try {
889
+ const result = await this.getResult(req);
890
+ const response = await this.handleResult(result);
891
+ res.json(response);
892
+ } catch (e) {
893
+ this.logger.error("Exception occurred during AWS ALB token refresh", e);
894
+ res.status(401);
895
+ res.end();
896
+ }
897
+ }
898
+ start() {
899
+ return Promise.resolve(void 0);
900
+ }
901
+ async getResult(req) {
902
+ const jwt = req.header(ALB_JWT_HEADER);
903
+ const accessToken = req.header(ALB_ACCESSTOKEN_HEADER);
904
+ if (jwt === void 0) {
905
+ throw new errors.AuthenticationError(`Missing ALB OIDC header: ${ALB_JWT_HEADER}`);
906
+ }
907
+ if (accessToken === void 0) {
908
+ throw new errors.AuthenticationError(`Missing ALB OIDC header: ${ALB_ACCESSTOKEN_HEADER}`);
909
+ }
910
+ try {
911
+ const headers = getJWTHeaders(jwt);
912
+ const key = await this.getKey(headers.kid);
913
+ const claims = jose.JWT.verify(jwt, key);
914
+ if (this.issuer && claims.iss !== this.issuer) {
915
+ throw new errors.AuthenticationError("Issuer mismatch on JWT token");
916
+ }
917
+ const fullProfile = {
918
+ provider: "unknown",
919
+ id: claims.sub,
920
+ displayName: claims.name,
921
+ username: claims.email.split("@")[0].toLowerCase(),
922
+ name: {
923
+ familyName: claims.family_name,
924
+ givenName: claims.given_name
925
+ },
926
+ emails: [{ value: claims.email.toLowerCase() }],
927
+ photos: [{ value: claims.picture }]
928
+ };
929
+ return {
930
+ fullProfile,
931
+ expiresInSeconds: claims.exp,
932
+ accessToken
933
+ };
934
+ } catch (e) {
935
+ throw new Error(`Exception occurred during JWT processing: ${e}`);
936
+ }
937
+ }
938
+ async handleResult(result) {
939
+ const { profile } = await this.authHandler(result);
940
+ const backstageIdentity = await this.signInResolver({
941
+ result,
942
+ profile
943
+ }, {
944
+ tokenIssuer: this.tokenIssuer,
945
+ catalogIdentityClient: this.catalogIdentityClient,
946
+ logger: this.logger
947
+ });
948
+ return {
949
+ providerInfo: {
950
+ accessToken: result.accessToken,
951
+ expiresInSeconds: result.expiresInSeconds
952
+ },
953
+ backstageIdentity: prepareBackstageIdentityResponse(backstageIdentity),
954
+ profile
955
+ };
956
+ }
957
+ async getKey(keyId) {
958
+ const optionalCacheKey = this.keyCache.get(keyId);
959
+ if (optionalCacheKey) {
960
+ return crypto__namespace.createPublicKey(optionalCacheKey);
961
+ }
962
+ const keyText = await fetch__default["default"](`https://public-keys.auth.elb.${this.region}.amazonaws.com/${keyId}`).then((response) => response.text());
963
+ const keyValue = crypto__namespace.createPublicKey(keyText);
964
+ this.keyCache.set(keyId, keyValue.export({ format: "pem", type: "spki" }));
965
+ return keyValue;
966
+ }
967
+ }
968
+ const createAwsAlbProvider = (options) => {
969
+ return ({ config, tokenIssuer, catalogApi, logger }) => {
970
+ const region = config.getString("region");
971
+ const issuer = config.getOptionalString("iss");
972
+ if ((options == null ? void 0 : options.signIn.resolver) === void 0) {
973
+ throw new Error("SignInResolver is required to use this authentication provider");
974
+ }
975
+ const catalogIdentityClient = new CatalogIdentityClient({
976
+ catalogApi,
977
+ tokenIssuer
978
+ });
979
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
980
+ profile: makeProfileInfo(fullProfile)
981
+ });
982
+ const signInResolver = options == null ? void 0 : options.signIn.resolver;
983
+ return new AwsAlbAuthProvider({
984
+ region,
985
+ issuer,
986
+ signInResolver,
987
+ authHandler,
988
+ tokenIssuer,
989
+ catalogIdentityClient,
990
+ logger
991
+ });
992
+ };
993
+ };
994
+
995
+ class BitbucketAuthProvider {
716
996
  constructor(options) {
997
+ this.signInResolver = options.signInResolver;
998
+ this.authHandler = options.authHandler;
999
+ this.tokenIssuer = options.tokenIssuer;
717
1000
  this.catalogIdentityClient = options.catalogIdentityClient;
718
1001
  this.logger = options.logger;
719
- this.tokenIssuer = options.tokenIssuer;
720
- this.authHandler = options.authHandler;
721
- this.signInResolver = options.signInResolver;
722
- this._strategy = new passportGitlab2.Strategy({
1002
+ this._strategy = new passportBitbucketOauth2.Strategy({
723
1003
  clientID: options.clientId,
724
1004
  clientSecret: options.clientSecret,
725
1005
  callbackURL: options.callbackUrl,
726
- baseURL: options.baseUrl
1006
+ passReqToCallback: false
727
1007
  }, (accessToken, refreshToken, params, fullProfile, done) => {
728
- done(void 0, { fullProfile, params, accessToken }, {
1008
+ done(void 0, {
1009
+ fullProfile,
1010
+ params,
1011
+ accessToken,
1012
+ refreshToken
1013
+ }, {
729
1014
  refreshToken
730
1015
  });
731
1016
  });
732
1017
  }
733
1018
  async start(req) {
734
1019
  return await executeRedirectStrategy(req, this._strategy, {
1020
+ accessType: "offline",
1021
+ prompt: "consent",
735
1022
  scope: req.scope,
736
1023
  state: encodeState(req.state)
737
1024
  });
@@ -744,26 +1031,24 @@ class GitlabAuthProvider {
744
1031
  };
745
1032
  }
746
1033
  async refresh(req) {
747
- const {
748
- accessToken,
749
- refreshToken: newRefreshToken,
750
- params
751
- } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1034
+ const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
752
1035
  const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
753
- return this.handleResult({
754
- fullProfile,
755
- params,
756
- accessToken,
757
- refreshToken: newRefreshToken
758
- });
1036
+ return {
1037
+ response: await this.handleResult({
1038
+ fullProfile,
1039
+ params,
1040
+ accessToken
1041
+ }),
1042
+ refreshToken
1043
+ };
759
1044
  }
760
1045
  async handleResult(result) {
1046
+ result.fullProfile.avatarUrl = result.fullProfile._json.links.avatar.href;
761
1047
  const { profile } = await this.authHandler(result);
762
1048
  const response = {
763
1049
  providerInfo: {
764
1050
  idToken: result.params.id_token,
765
1051
  accessToken: result.accessToken,
766
- refreshToken: result.refreshToken,
767
1052
  scope: result.params.scope,
768
1053
  expiresInSeconds: result.params.expires_in
769
1054
  },
@@ -782,7 +1067,35 @@ class GitlabAuthProvider {
782
1067
  return response;
783
1068
  }
784
1069
  }
785
- const createGitlabProvider = (options) => {
1070
+ const bitbucketUsernameSignInResolver = async (info, ctx) => {
1071
+ const { result } = info;
1072
+ if (!result.fullProfile.username) {
1073
+ throw new Error("Bitbucket profile contained no Username");
1074
+ }
1075
+ const entity = await ctx.catalogIdentityClient.findUser({
1076
+ annotations: {
1077
+ "bitbucket.org/username": result.fullProfile.username
1078
+ }
1079
+ });
1080
+ const claims = getEntityClaims(entity);
1081
+ const token = await ctx.tokenIssuer.issueToken({ claims });
1082
+ return { id: entity.metadata.name, entity, token };
1083
+ };
1084
+ const bitbucketUserIdSignInResolver = async (info, ctx) => {
1085
+ const { result } = info;
1086
+ if (!result.fullProfile.id) {
1087
+ throw new Error("Bitbucket profile contained no User ID");
1088
+ }
1089
+ const entity = await ctx.catalogIdentityClient.findUser({
1090
+ annotations: {
1091
+ "bitbucket.org/user-id": result.fullProfile.id
1092
+ }
1093
+ });
1094
+ const claims = getEntityClaims(entity);
1095
+ const token = await ctx.tokenIssuer.issueToken({ claims });
1096
+ return { id: entity.metadata.name, entity, token };
1097
+ };
1098
+ const createBitbucketProvider = (options) => {
786
1099
  return ({
787
1100
  providerId,
788
1101
  globalConfig,
@@ -791,33 +1104,26 @@ const createGitlabProvider = (options) => {
791
1104
  catalogApi,
792
1105
  logger
793
1106
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
794
- var _a, _b, _c;
1107
+ var _a;
795
1108
  const clientId = envConfig.getString("clientId");
796
1109
  const clientSecret = envConfig.getString("clientSecret");
797
- const audience = envConfig.getOptionalString("audience");
798
- const baseUrl = audience || "https://gitlab.com";
799
1110
  const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
800
1111
  const catalogIdentityClient = new CatalogIdentityClient({
801
1112
  catalogApi,
802
1113
  tokenIssuer
803
1114
  });
804
- const authHandler = (_a = options == null ? void 0 : options.authHandler) != null ? _a : gitlabDefaultAuthHandler;
805
- const signInResolverFn = (_c = (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver) != null ? _c : gitlabDefaultSignInResolver;
806
- const signInResolver = (info) => signInResolverFn(info, {
807
- catalogIdentityClient,
808
- tokenIssuer,
809
- logger
1115
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1116
+ profile: makeProfileInfo(fullProfile, params.id_token)
810
1117
  });
811
- const provider = new GitlabAuthProvider({
1118
+ const provider = new BitbucketAuthProvider({
812
1119
  clientId,
813
1120
  clientSecret,
814
1121
  callbackUrl,
815
- baseUrl,
1122
+ signInResolver: (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver,
816
1123
  authHandler,
817
- signInResolver,
1124
+ tokenIssuer,
818
1125
  catalogIdentityClient,
819
- logger,
820
- tokenIssuer
1126
+ logger
821
1127
  });
822
1128
  return OAuthAdapter.fromConfig(globalConfig, provider, {
823
1129
  disableRefresh: false,
@@ -827,35 +1133,29 @@ const createGitlabProvider = (options) => {
827
1133
  });
828
1134
  };
829
1135
 
830
- class GoogleAuthProvider {
1136
+ class GithubAuthProvider {
831
1137
  constructor(options) {
832
1138
  this.signInResolver = options.signInResolver;
833
1139
  this.authHandler = options.authHandler;
1140
+ this.stateEncoder = options.stateEncoder;
834
1141
  this.tokenIssuer = options.tokenIssuer;
835
1142
  this.catalogIdentityClient = options.catalogIdentityClient;
836
1143
  this.logger = options.logger;
837
- this._strategy = new passportGoogleOauth20.Strategy({
1144
+ this._strategy = new passportGithub2.Strategy({
838
1145
  clientID: options.clientId,
839
1146
  clientSecret: options.clientSecret,
840
1147
  callbackURL: options.callbackUrl,
841
- passReqToCallback: false
1148
+ tokenURL: options.tokenUrl,
1149
+ userProfileURL: options.userProfileUrl,
1150
+ authorizationURL: options.authorizationUrl
842
1151
  }, (accessToken, refreshToken, params, fullProfile, done) => {
843
- done(void 0, {
844
- fullProfile,
845
- params,
846
- accessToken,
847
- refreshToken
848
- }, {
849
- refreshToken
850
- });
1152
+ done(void 0, { fullProfile, params, accessToken }, { refreshToken });
851
1153
  });
852
1154
  }
853
1155
  async start(req) {
854
1156
  return await executeRedirectStrategy(req, this._strategy, {
855
- accessType: "offline",
856
- prompt: "consent",
857
1157
  scope: req.scope,
858
- state: encodeState(req.state)
1158
+ state: (await this.stateEncoder(req)).encodedState
859
1159
  });
860
1160
  }
861
1161
  async handler(req) {
@@ -866,23 +1166,25 @@ class GoogleAuthProvider {
866
1166
  };
867
1167
  }
868
1168
  async refresh(req) {
869
- const { accessToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1169
+ const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
870
1170
  const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
871
- return this.handleResult({
872
- fullProfile,
873
- params,
874
- accessToken,
875
- refreshToken: req.refreshToken
876
- });
1171
+ return {
1172
+ response: await this.handleResult({
1173
+ fullProfile,
1174
+ params,
1175
+ accessToken
1176
+ }),
1177
+ refreshToken
1178
+ };
877
1179
  }
878
1180
  async handleResult(result) {
879
1181
  const { profile } = await this.authHandler(result);
1182
+ const expiresInStr = result.params.expires_in;
880
1183
  const response = {
881
1184
  providerInfo: {
882
- idToken: result.params.id_token,
883
1185
  accessToken: result.accessToken,
884
1186
  scope: result.params.scope,
885
- expiresInSeconds: result.params.expires_in
1187
+ expiresInSeconds: expiresInStr === void 0 ? void 0 : Number(expiresInStr)
886
1188
  },
887
1189
  profile
888
1190
  };
@@ -899,43 +1201,15 @@ class GoogleAuthProvider {
899
1201
  return response;
900
1202
  }
901
1203
  }
902
- const googleEmailSignInResolver = async (info, ctx) => {
903
- const { profile } = info;
904
- if (!profile.email) {
905
- throw new Error("Google profile contained no email");
906
- }
907
- const entity = await ctx.catalogIdentityClient.findUser({
908
- annotations: {
909
- "google.com/email": profile.email
910
- }
911
- });
912
- const claims = getEntityClaims(entity);
913
- const token = await ctx.tokenIssuer.issueToken({ claims });
914
- return { id: entity.metadata.name, entity, token };
915
- };
916
- const googleDefaultSignInResolver = async (info, ctx) => {
917
- const { profile } = info;
918
- if (!profile.email) {
919
- throw new Error("Google profile contained no email");
920
- }
921
- let userId;
922
- try {
923
- const entity = await ctx.catalogIdentityClient.findUser({
924
- annotations: {
925
- "google.com/email": profile.email
926
- }
927
- });
928
- userId = entity.metadata.name;
929
- } catch (error) {
930
- ctx.logger.warn(`Failed to look up user, ${error}, falling back to allowing login based on email pattern, this will probably break in the future`);
931
- userId = profile.email.split("@")[0];
932
- }
1204
+ const githubDefaultSignInResolver = async (info, ctx) => {
1205
+ const { fullProfile } = info.result;
1206
+ const userId = fullProfile.username || fullProfile.id;
933
1207
  const token = await ctx.tokenIssuer.issueToken({
934
1208
  claims: { sub: userId, ent: [`user:default/${userId}`] }
935
1209
  });
936
1210
  return { id: userId, token };
937
1211
  };
938
- const createGoogleProvider = (options) => {
1212
+ const createGithubProvider = (options) => {
939
1213
  return ({
940
1214
  providerId,
941
1215
  globalConfig,
@@ -944,57 +1218,86 @@ const createGoogleProvider = (options) => {
944
1218
  catalogApi,
945
1219
  logger
946
1220
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
947
- var _a, _b;
1221
+ var _a, _b, _c;
948
1222
  const clientId = envConfig.getString("clientId");
949
1223
  const clientSecret = envConfig.getString("clientSecret");
950
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1224
+ const enterpriseInstanceUrl = envConfig.getOptionalString("enterpriseInstanceUrl");
1225
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1226
+ const authorizationUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/login/oauth/authorize` : void 0;
1227
+ const tokenUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/login/oauth/access_token` : void 0;
1228
+ const userProfileUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/api/v3/user` : void 0;
1229
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
951
1230
  const catalogIdentityClient = new CatalogIdentityClient({
952
1231
  catalogApi,
953
1232
  tokenIssuer
954
1233
  });
955
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
956
- profile: makeProfileInfo(fullProfile, params.id_token)
1234
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
1235
+ profile: makeProfileInfo(fullProfile)
957
1236
  });
958
- const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : googleDefaultSignInResolver;
1237
+ const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : githubDefaultSignInResolver;
959
1238
  const signInResolver = (info) => signInResolverFn(info, {
960
1239
  catalogIdentityClient,
961
1240
  tokenIssuer,
962
1241
  logger
963
1242
  });
964
- const provider = new GoogleAuthProvider({
1243
+ const stateEncoder = (_c = options == null ? void 0 : options.stateEncoder) != null ? _c : async (req) => {
1244
+ return { encodedState: encodeState(req.state) };
1245
+ };
1246
+ const provider = new GithubAuthProvider({
965
1247
  clientId,
966
1248
  clientSecret,
967
1249
  callbackUrl,
1250
+ tokenUrl,
1251
+ userProfileUrl,
1252
+ authorizationUrl,
968
1253
  signInResolver,
969
1254
  authHandler,
970
1255
  tokenIssuer,
971
1256
  catalogIdentityClient,
1257
+ stateEncoder,
972
1258
  logger
973
1259
  });
974
1260
  return OAuthAdapter.fromConfig(globalConfig, provider, {
975
- disableRefresh: false,
1261
+ persistScopes: true,
976
1262
  providerId,
977
1263
  tokenIssuer
978
1264
  });
979
1265
  });
980
1266
  };
981
1267
 
982
- class MicrosoftAuthProvider {
1268
+ const gitlabDefaultSignInResolver = async (info, ctx) => {
1269
+ const { profile, result } = info;
1270
+ let id = result.fullProfile.id;
1271
+ if (profile.email) {
1272
+ id = profile.email.split("@")[0];
1273
+ }
1274
+ const token = await ctx.tokenIssuer.issueToken({
1275
+ claims: { sub: id, ent: [`user:default/${id}`] }
1276
+ });
1277
+ return { id, token };
1278
+ };
1279
+ const gitlabDefaultAuthHandler = async ({
1280
+ fullProfile,
1281
+ params
1282
+ }) => ({
1283
+ profile: makeProfileInfo(fullProfile, params.id_token)
1284
+ });
1285
+ class GitlabAuthProvider {
983
1286
  constructor(options) {
984
- this.signInResolver = options.signInResolver;
985
- this.authHandler = options.authHandler;
986
- this.tokenIssuer = options.tokenIssuer;
987
- this.logger = options.logger;
988
1287
  this.catalogIdentityClient = options.catalogIdentityClient;
989
- this._strategy = new passportMicrosoft.Strategy({
1288
+ this.logger = options.logger;
1289
+ this.tokenIssuer = options.tokenIssuer;
1290
+ this.authHandler = options.authHandler;
1291
+ this.signInResolver = options.signInResolver;
1292
+ this._strategy = new passportGitlab2.Strategy({
990
1293
  clientID: options.clientId,
991
1294
  clientSecret: options.clientSecret,
992
1295
  callbackURL: options.callbackUrl,
993
- authorizationURL: options.authorizationUrl,
994
- tokenURL: options.tokenUrl,
995
- passReqToCallback: false
1296
+ baseURL: options.baseUrl
996
1297
  }, (accessToken, refreshToken, params, fullProfile, done) => {
997
- done(void 0, { fullProfile, accessToken, params }, { refreshToken });
1298
+ done(void 0, { fullProfile, params, accessToken }, {
1299
+ refreshToken
1300
+ });
998
1301
  });
999
1302
  }
1000
1303
  async start(req) {
@@ -1011,18 +1314,18 @@ class MicrosoftAuthProvider {
1011
1314
  };
1012
1315
  }
1013
1316
  async refresh(req) {
1014
- const { accessToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1317
+ const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1015
1318
  const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
1016
- return this.handleResult({
1017
- fullProfile,
1018
- params,
1019
- accessToken,
1020
- refreshToken: req.refreshToken
1021
- });
1319
+ return {
1320
+ response: await this.handleResult({
1321
+ fullProfile,
1322
+ params,
1323
+ accessToken
1324
+ }),
1325
+ refreshToken
1326
+ };
1022
1327
  }
1023
1328
  async handleResult(result) {
1024
- const photo = await this.getUserPhoto(result.accessToken);
1025
- result.fullProfile.photos = photo ? [{ value: photo }] : void 0;
1026
1329
  const { profile } = await this.authHandler(result);
1027
1330
  const response = {
1028
1331
  providerInfo: {
@@ -1035,58 +1338,18 @@ class MicrosoftAuthProvider {
1035
1338
  };
1036
1339
  if (this.signInResolver) {
1037
1340
  response.backstageIdentity = await this.signInResolver({
1038
- result,
1039
- profile
1040
- }, {
1041
- tokenIssuer: this.tokenIssuer,
1042
- catalogIdentityClient: this.catalogIdentityClient,
1043
- logger: this.logger
1044
- });
1045
- }
1046
- return response;
1047
- }
1048
- getUserPhoto(accessToken) {
1049
- return new Promise((resolve) => {
1050
- fetch__default["default"]("https://graph.microsoft.com/v1.0/me/photos/48x48/$value", {
1051
- headers: {
1052
- Authorization: `Bearer ${accessToken}`
1053
- }
1054
- }).then((response) => response.arrayBuffer()).then((arrayBuffer) => {
1055
- const imageUrl = `data:image/jpeg;base64,${Buffer.from(arrayBuffer).toString("base64")}`;
1056
- resolve(imageUrl);
1057
- }).catch((error) => {
1058
- this.logger.warn(`Could not retrieve user profile photo from Microsoft Graph API: ${error}`);
1059
- resolve(void 0);
1060
- });
1061
- });
1062
- }
1063
- }
1064
- const microsoftEmailSignInResolver = async (info, ctx) => {
1065
- const { profile } = info;
1066
- if (!profile.email) {
1067
- throw new Error("Microsoft profile contained no email");
1068
- }
1069
- const entity = await ctx.catalogIdentityClient.findUser({
1070
- annotations: {
1071
- "microsoft.com/email": profile.email
1341
+ result,
1342
+ profile
1343
+ }, {
1344
+ tokenIssuer: this.tokenIssuer,
1345
+ catalogIdentityClient: this.catalogIdentityClient,
1346
+ logger: this.logger
1347
+ });
1072
1348
  }
1073
- });
1074
- const claims = getEntityClaims(entity);
1075
- const token = await ctx.tokenIssuer.issueToken({ claims });
1076
- return { id: entity.metadata.name, entity, token };
1077
- };
1078
- const microsoftDefaultSignInResolver = async (info, ctx) => {
1079
- const { profile } = info;
1080
- if (!profile.email) {
1081
- throw new Error("Profile contained no email");
1349
+ return response;
1082
1350
  }
1083
- const userId = profile.email.split("@")[0];
1084
- const token = await ctx.tokenIssuer.issueToken({
1085
- claims: { sub: userId, ent: [`user:default/${userId}`] }
1086
- });
1087
- return { id: userId, token };
1088
- };
1089
- const createMicrosoftProvider = (options) => {
1351
+ }
1352
+ const createGitlabProvider = (options) => {
1090
1353
  return ({
1091
1354
  providerId,
1092
1355
  globalConfig,
@@ -1095,32 +1358,28 @@ const createMicrosoftProvider = (options) => {
1095
1358
  catalogApi,
1096
1359
  logger
1097
1360
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1098
- var _a, _b;
1361
+ var _a, _b, _c;
1099
1362
  const clientId = envConfig.getString("clientId");
1100
1363
  const clientSecret = envConfig.getString("clientSecret");
1101
- const tenantId = envConfig.getString("tenantId");
1364
+ const audience = envConfig.getOptionalString("audience");
1365
+ const baseUrl = audience || "https://gitlab.com";
1102
1366
  const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1103
- const authorizationUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`;
1104
- const tokenUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
1105
1367
  const catalogIdentityClient = new CatalogIdentityClient({
1106
1368
  catalogApi,
1107
1369
  tokenIssuer
1108
1370
  });
1109
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1110
- profile: makeProfileInfo(fullProfile, params.id_token)
1111
- });
1112
- const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : microsoftDefaultSignInResolver;
1371
+ const authHandler = (_a = options == null ? void 0 : options.authHandler) != null ? _a : gitlabDefaultAuthHandler;
1372
+ const signInResolverFn = (_c = (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver) != null ? _c : gitlabDefaultSignInResolver;
1113
1373
  const signInResolver = (info) => signInResolverFn(info, {
1114
1374
  catalogIdentityClient,
1115
1375
  tokenIssuer,
1116
1376
  logger
1117
1377
  });
1118
- const provider = new MicrosoftAuthProvider({
1378
+ const provider = new GitlabAuthProvider({
1119
1379
  clientId,
1120
1380
  clientSecret,
1121
1381
  callbackUrl,
1122
- authorizationUrl,
1123
- tokenUrl,
1382
+ baseUrl,
1124
1383
  authHandler,
1125
1384
  signInResolver,
1126
1385
  catalogIdentityClient,
@@ -1135,30 +1394,24 @@ const createMicrosoftProvider = (options) => {
1135
1394
  });
1136
1395
  };
1137
1396
 
1138
- class OAuth2AuthProvider {
1397
+ class GoogleAuthProvider {
1139
1398
  constructor(options) {
1140
1399
  this.signInResolver = options.signInResolver;
1141
1400
  this.authHandler = options.authHandler;
1142
1401
  this.tokenIssuer = options.tokenIssuer;
1143
1402
  this.catalogIdentityClient = options.catalogIdentityClient;
1144
1403
  this.logger = options.logger;
1145
- this._strategy = new OAuth2Strategy.Strategy({
1404
+ this._strategy = new passportGoogleOauth20.Strategy({
1146
1405
  clientID: options.clientId,
1147
1406
  clientSecret: options.clientSecret,
1148
1407
  callbackURL: options.callbackUrl,
1149
- authorizationURL: options.authorizationUrl,
1150
- tokenURL: options.tokenUrl,
1151
- passReqToCallback: false,
1152
- scope: options.scope,
1153
- customHeaders: options.includeBasicAuth ? {
1154
- Authorization: `Basic ${this.encodeClientCredentials(options.clientId, options.clientSecret)}`
1155
- } : void 0
1408
+ passReqToCallback: false
1156
1409
  }, (accessToken, refreshToken, params, fullProfile, done) => {
1157
1410
  done(void 0, {
1158
1411
  fullProfile,
1412
+ params,
1159
1413
  accessToken,
1160
- refreshToken,
1161
- params
1414
+ refreshToken
1162
1415
  }, {
1163
1416
  refreshToken
1164
1417
  });
@@ -1180,19 +1433,16 @@ class OAuth2AuthProvider {
1180
1433
  };
1181
1434
  }
1182
1435
  async refresh(req) {
1183
- const refreshTokenResponse = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1184
- const {
1185
- accessToken,
1186
- params,
1187
- refreshToken: updatedRefreshToken
1188
- } = refreshTokenResponse;
1436
+ const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1189
1437
  const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
1190
- return this.handleResult({
1191
- fullProfile,
1192
- params,
1193
- accessToken,
1194
- refreshToken: updatedRefreshToken
1195
- });
1438
+ return {
1439
+ response: await this.handleResult({
1440
+ fullProfile,
1441
+ params,
1442
+ accessToken
1443
+ }),
1444
+ refreshToken
1445
+ };
1196
1446
  }
1197
1447
  async handleResult(result) {
1198
1448
  const { profile } = await this.authHandler(result);
@@ -1201,8 +1451,7 @@ class OAuth2AuthProvider {
1201
1451
  idToken: result.params.id_token,
1202
1452
  accessToken: result.accessToken,
1203
1453
  scope: result.params.scope,
1204
- expiresInSeconds: result.params.expires_in,
1205
- refreshToken: result.refreshToken
1454
+ expiresInSeconds: result.params.expires_in
1206
1455
  },
1207
1456
  profile
1208
1457
  };
@@ -1218,22 +1467,44 @@ class OAuth2AuthProvider {
1218
1467
  }
1219
1468
  return response;
1220
1469
  }
1221
- encodeClientCredentials(clientID, clientSecret) {
1222
- return Buffer.from(`${clientID}:${clientSecret}`).toString("base64");
1223
- }
1224
1470
  }
1225
- const oAuth2DefaultSignInResolver$1 = async (info, ctx) => {
1471
+ const googleEmailSignInResolver = async (info, ctx) => {
1226
1472
  const { profile } = info;
1227
1473
  if (!profile.email) {
1228
- throw new Error("Profile contained no email");
1474
+ throw new Error("Google profile contained no email");
1475
+ }
1476
+ const entity = await ctx.catalogIdentityClient.findUser({
1477
+ annotations: {
1478
+ "google.com/email": profile.email
1479
+ }
1480
+ });
1481
+ const claims = getEntityClaims(entity);
1482
+ const token = await ctx.tokenIssuer.issueToken({ claims });
1483
+ return { id: entity.metadata.name, entity, token };
1484
+ };
1485
+ const googleDefaultSignInResolver = async (info, ctx) => {
1486
+ const { profile } = info;
1487
+ if (!profile.email) {
1488
+ throw new Error("Google profile contained no email");
1489
+ }
1490
+ let userId;
1491
+ try {
1492
+ const entity = await ctx.catalogIdentityClient.findUser({
1493
+ annotations: {
1494
+ "google.com/email": profile.email
1495
+ }
1496
+ });
1497
+ userId = entity.metadata.name;
1498
+ } catch (error) {
1499
+ ctx.logger.warn(`Failed to look up user, ${error}, falling back to allowing login based on email pattern, this will probably break in the future`);
1500
+ userId = profile.email.split("@")[0];
1229
1501
  }
1230
- const userId = profile.email.split("@")[0];
1231
1502
  const token = await ctx.tokenIssuer.issueToken({
1232
1503
  claims: { sub: userId, ent: [`user:default/${userId}`] }
1233
1504
  });
1234
1505
  return { id: userId, token };
1235
1506
  };
1236
- const createOAuth2Provider = (options) => {
1507
+ const createGoogleProvider = (options) => {
1237
1508
  return ({
1238
1509
  providerId,
1239
1510
  globalConfig,
@@ -1242,15 +1513,10 @@ const createOAuth2Provider = (options) => {
1242
1513
  catalogApi,
1243
1514
  logger
1244
1515
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1245
- var _a, _b, _c;
1516
+ var _a, _b;
1246
1517
  const clientId = envConfig.getString("clientId");
1247
1518
  const clientSecret = envConfig.getString("clientSecret");
1248
1519
  const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1249
- const authorizationUrl = envConfig.getString("authorizationUrl");
1250
- const tokenUrl = envConfig.getString("tokenUrl");
1251
- const scope = envConfig.getOptionalString("scope");
1252
- const includeBasicAuth = envConfig.getOptionalBoolean("includeBasicAuth");
1253
- const disableRefresh = (_a = envConfig.getOptionalBoolean("disableRefresh")) != null ? _a : false;
1254
1520
  const catalogIdentityClient = new CatalogIdentityClient({
1255
1521
  catalogApi,
1256
1522
  tokenIssuer
@@ -1258,113 +1524,83 @@ const createOAuth2Provider = (options) => {
1258
1524
  const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1259
1525
  profile: makeProfileInfo(fullProfile, params.id_token)
1260
1526
  });
1261
- const signInResolverFn = (_c = (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver) != null ? _c : oAuth2DefaultSignInResolver$1;
1527
+ const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : googleDefaultSignInResolver;
1262
1528
  const signInResolver = (info) => signInResolverFn(info, {
1263
1529
  catalogIdentityClient,
1264
1530
  tokenIssuer,
1265
1531
  logger
1266
1532
  });
1267
- const provider = new OAuth2AuthProvider({
1533
+ const provider = new GoogleAuthProvider({
1268
1534
  clientId,
1269
1535
  clientSecret,
1270
- tokenIssuer,
1271
- catalogIdentityClient,
1272
1536
  callbackUrl,
1273
1537
  signInResolver,
1274
1538
  authHandler,
1275
- authorizationUrl,
1276
- tokenUrl,
1277
- scope,
1278
- logger,
1279
- includeBasicAuth
1539
+ tokenIssuer,
1540
+ catalogIdentityClient,
1541
+ logger
1280
1542
  });
1281
1543
  return OAuthAdapter.fromConfig(globalConfig, provider, {
1282
- disableRefresh,
1544
+ disableRefresh: false,
1283
1545
  providerId,
1284
1546
  tokenIssuer
1285
1547
  });
1286
1548
  });
1287
1549
  };
1288
1550
 
1289
- class OidcAuthProvider {
1551
+ class MicrosoftAuthProvider {
1290
1552
  constructor(options) {
1291
- this.implementation = this.setupStrategy(options);
1292
- this.scope = options.scope;
1293
- this.prompt = options.prompt;
1294
1553
  this.signInResolver = options.signInResolver;
1295
1554
  this.authHandler = options.authHandler;
1296
1555
  this.tokenIssuer = options.tokenIssuer;
1297
- this.catalogIdentityClient = options.catalogIdentityClient;
1298
1556
  this.logger = options.logger;
1557
+ this.catalogIdentityClient = options.catalogIdentityClient;
1558
+ this._strategy = new passportMicrosoft.Strategy({
1559
+ clientID: options.clientId,
1560
+ clientSecret: options.clientSecret,
1561
+ callbackURL: options.callbackUrl,
1562
+ authorizationURL: options.authorizationUrl,
1563
+ tokenURL: options.tokenUrl,
1564
+ passReqToCallback: false
1565
+ }, (accessToken, refreshToken, params, fullProfile, done) => {
1566
+ done(void 0, { fullProfile, accessToken, params }, { refreshToken });
1567
+ });
1299
1568
  }
1300
1569
  async start(req) {
1301
- const { strategy } = await this.implementation;
1302
- const options = {
1303
- scope: req.scope || this.scope || "openid profile email",
1570
+ return await executeRedirectStrategy(req, this._strategy, {
1571
+ scope: req.scope,
1304
1572
  state: encodeState(req.state)
1305
- };
1306
- const prompt = this.prompt || "none";
1307
- if (prompt !== "auto") {
1308
- options.prompt = prompt;
1309
- }
1310
- return await executeRedirectStrategy(req, strategy, options);
1573
+ });
1311
1574
  }
1312
1575
  async handler(req) {
1313
- const { strategy } = await this.implementation;
1314
- const strategyResponse = await executeFrameHandlerStrategy(req, strategy);
1315
- const {
1316
- result: { userinfo, tokenset },
1317
- privateInfo
1318
- } = strategyResponse;
1319
- const identityResponse = await this.handleResult({ tokenset, userinfo });
1576
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
1320
1577
  return {
1321
- response: identityResponse,
1578
+ response: await this.handleResult(result),
1322
1579
  refreshToken: privateInfo.refreshToken
1323
1580
  };
1324
1581
  }
1325
1582
  async refresh(req) {
1326
- const { client } = await this.implementation;
1327
- const tokenset = await client.refresh(req.refreshToken);
1328
- if (!tokenset.access_token) {
1329
- throw new Error("Refresh failed");
1330
- }
1331
- const profile = await client.userinfo(tokenset.access_token);
1332
- return this.handleResult({ tokenset, userinfo: profile });
1333
- }
1334
- async setupStrategy(options) {
1335
- const issuer = await openidClient.Issuer.discover(options.metadataUrl);
1336
- const client = new issuer.Client({
1337
- access_type: "offline",
1338
- client_id: options.clientId,
1339
- client_secret: options.clientSecret,
1340
- redirect_uris: [options.callbackUrl],
1341
- response_types: ["code"],
1342
- id_token_signed_response_alg: options.tokenSignedResponseAlg || "RS256",
1343
- scope: options.scope || ""
1344
- });
1345
- const strategy = new openidClient.Strategy({
1346
- client,
1347
- passReqToCallback: false
1348
- }, (tokenset, userinfo, done) => {
1349
- if (typeof done !== "function") {
1350
- throw new Error("OIDC IdP must provide a userinfo_endpoint in the metadata response");
1351
- }
1352
- done(void 0, { tokenset, userinfo }, {
1353
- refreshToken: tokenset.refresh_token
1354
- });
1355
- });
1356
- strategy.error = console.error;
1357
- return { strategy, client };
1583
+ const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1584
+ const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
1585
+ return {
1586
+ response: await this.handleResult({
1587
+ fullProfile,
1588
+ params,
1589
+ accessToken
1590
+ }),
1591
+ refreshToken
1592
+ };
1358
1593
  }
1359
1594
  async handleResult(result) {
1595
+ const photo = await this.getUserPhoto(result.accessToken);
1596
+ result.fullProfile.photos = photo ? [{ value: photo }] : void 0;
1360
1597
  const { profile } = await this.authHandler(result);
1361
1598
  const response = {
1362
1599
  providerInfo: {
1363
- idToken: result.tokenset.id_token,
1364
- accessToken: result.tokenset.access_token,
1365
- refreshToken: result.tokenset.refresh_token,
1366
- scope: result.tokenset.scope,
1367
- expiresInSeconds: result.tokenset.expires_in
1600
+ idToken: result.params.id_token,
1601
+ accessToken: result.accessToken,
1602
+ scope: result.params.scope,
1603
+ expiresInSeconds: result.params.expires_in
1368
1604
  },
1369
1605
  profile
1370
1606
  };
@@ -1380,8 +1616,37 @@ class OidcAuthProvider {
1380
1616
  }
1381
1617
  return response;
1382
1618
  }
1619
+ getUserPhoto(accessToken) {
1620
+ return new Promise((resolve) => {
1621
+ fetch__default["default"]("https://graph.microsoft.com/v1.0/me/photos/48x48/$value", {
1622
+ headers: {
1623
+ Authorization: `Bearer ${accessToken}`
1624
+ }
1625
+ }).then((response) => response.arrayBuffer()).then((arrayBuffer) => {
1626
+ const imageUrl = `data:image/jpeg;base64,${Buffer.from(arrayBuffer).toString("base64")}`;
1627
+ resolve(imageUrl);
1628
+ }).catch((error) => {
1629
+ this.logger.warn(`Could not retrieve user profile photo from Microsoft Graph API: ${error}`);
1630
+ resolve(void 0);
1631
+ });
1632
+ });
1633
+ }
1383
1634
  }
1384
- const oAuth2DefaultSignInResolver = async (info, ctx) => {
1635
+ const microsoftEmailSignInResolver = async (info, ctx) => {
1636
+ const { profile } = info;
1637
+ if (!profile.email) {
1638
+ throw new Error("Microsoft profile contained no email");
1639
+ }
1640
+ const entity = await ctx.catalogIdentityClient.findUser({
1641
+ annotations: {
1642
+ "microsoft.com/email": profile.email
1643
+ }
1644
+ });
1645
+ const claims = getEntityClaims(entity);
1646
+ const token = await ctx.tokenIssuer.issueToken({ claims });
1647
+ return { id: entity.metadata.name, entity, token };
1648
+ };
1649
+ const microsoftDefaultSignInResolver = async (info, ctx) => {
1385
1650
  const { profile } = info;
1386
1651
  if (!profile.email) {
1387
1652
  throw new Error("Profile contained no email");
@@ -1392,7 +1657,7 @@ const oAuth2DefaultSignInResolver = async (info, ctx) => {
1392
1657
  });
1393
1658
  return { id: userId, token };
1394
1659
  };
1395
- const createOidcProvider = (options) => {
1660
+ const createMicrosoftProvider = (options) => {
1396
1661
  return ({
1397
1662
  providerId,
1398
1663
  globalConfig,
@@ -1404,41 +1669,34 @@ const createOidcProvider = (options) => {
1404
1669
  var _a, _b;
1405
1670
  const clientId = envConfig.getString("clientId");
1406
1671
  const clientSecret = envConfig.getString("clientSecret");
1672
+ const tenantId = envConfig.getString("tenantId");
1407
1673
  const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1408
- const metadataUrl = envConfig.getString("metadataUrl");
1409
- const tokenSignedResponseAlg = envConfig.getOptionalString("tokenSignedResponseAlg");
1410
- const scope = envConfig.getOptionalString("scope");
1411
- const prompt = envConfig.getOptionalString("prompt");
1674
+ const authorizationUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`;
1675
+ const tokenUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
1412
1676
  const catalogIdentityClient = new CatalogIdentityClient({
1413
1677
  catalogApi,
1414
1678
  tokenIssuer
1415
1679
  });
1416
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ userinfo }) => ({
1417
- profile: {
1418
- displayName: userinfo.name,
1419
- email: userinfo.email,
1420
- picture: userinfo.picture
1421
- }
1680
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1681
+ profile: makeProfileInfo(fullProfile, params.id_token)
1422
1682
  });
1423
- const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : oAuth2DefaultSignInResolver;
1683
+ const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : microsoftDefaultSignInResolver;
1424
1684
  const signInResolver = (info) => signInResolverFn(info, {
1425
1685
  catalogIdentityClient,
1426
1686
  tokenIssuer,
1427
1687
  logger
1428
1688
  });
1429
- const provider = new OidcAuthProvider({
1689
+ const provider = new MicrosoftAuthProvider({
1430
1690
  clientId,
1431
1691
  clientSecret,
1432
1692
  callbackUrl,
1433
- tokenSignedResponseAlg,
1434
- metadataUrl,
1435
- scope,
1436
- prompt,
1437
- signInResolver,
1693
+ authorizationUrl,
1694
+ tokenUrl,
1438
1695
  authHandler,
1696
+ signInResolver,
1697
+ catalogIdentityClient,
1439
1698
  logger,
1440
- tokenIssuer,
1441
- catalogIdentityClient
1699
+ tokenIssuer
1442
1700
  });
1443
1701
  return OAuthAdapter.fromConfig(globalConfig, provider, {
1444
1702
  disableRefresh: false,
@@ -1448,35 +1706,30 @@ const createOidcProvider = (options) => {
1448
1706
  });
1449
1707
  };
1450
1708
 
1451
- class OktaAuthProvider {
1709
+ class OAuth2AuthProvider {
1452
1710
  constructor(options) {
1453
- this._store = {
1454
- store(_req, cb) {
1455
- cb(null, null);
1456
- },
1457
- verify(_req, _state, cb) {
1458
- cb(null, true);
1459
- }
1460
- };
1461
- this._signInResolver = options.signInResolver;
1462
- this._authHandler = options.authHandler;
1463
- this._tokenIssuer = options.tokenIssuer;
1464
- this._catalogIdentityClient = options.catalogIdentityClient;
1465
- this._logger = options.logger;
1466
- this._strategy = new passportOktaOauth.Strategy({
1711
+ this.signInResolver = options.signInResolver;
1712
+ this.authHandler = options.authHandler;
1713
+ this.tokenIssuer = options.tokenIssuer;
1714
+ this.catalogIdentityClient = options.catalogIdentityClient;
1715
+ this.logger = options.logger;
1716
+ this._strategy = new OAuth2Strategy.Strategy({
1467
1717
  clientID: options.clientId,
1468
1718
  clientSecret: options.clientSecret,
1469
1719
  callbackURL: options.callbackUrl,
1470
- audience: options.audience,
1720
+ authorizationURL: options.authorizationUrl,
1721
+ tokenURL: options.tokenUrl,
1471
1722
  passReqToCallback: false,
1472
- store: this._store,
1473
- response_type: "code"
1723
+ scope: options.scope,
1724
+ customHeaders: options.includeBasicAuth ? {
1725
+ Authorization: `Basic ${this.encodeClientCredentials(options.clientId, options.clientSecret)}`
1726
+ } : void 0
1474
1727
  }, (accessToken, refreshToken, params, fullProfile, done) => {
1475
1728
  done(void 0, {
1729
+ fullProfile,
1476
1730
  accessToken,
1477
1731
  refreshToken,
1478
- params,
1479
- fullProfile
1732
+ params
1480
1733
  }, {
1481
1734
  refreshToken
1482
1735
  });
@@ -1498,17 +1751,20 @@ class OktaAuthProvider {
1498
1751
  };
1499
1752
  }
1500
1753
  async refresh(req) {
1501
- const { accessToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1754
+ const refreshTokenResponse = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1755
+ const { accessToken, params, refreshToken } = refreshTokenResponse;
1502
1756
  const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
1503
- return this.handleResult({
1504
- fullProfile,
1505
- params,
1506
- accessToken,
1507
- refreshToken: req.refreshToken
1508
- });
1757
+ return {
1758
+ response: await this.handleResult({
1759
+ fullProfile,
1760
+ params,
1761
+ accessToken
1762
+ }),
1763
+ refreshToken
1764
+ };
1509
1765
  }
1510
1766
  async handleResult(result) {
1511
- const { profile } = await this._authHandler(result);
1767
+ const { profile } = await this.authHandler(result);
1512
1768
  const response = {
1513
1769
  providerInfo: {
1514
1770
  idToken: result.params.id_token,
@@ -1518,37 +1774,26 @@ class OktaAuthProvider {
1518
1774
  },
1519
1775
  profile
1520
1776
  };
1521
- if (this._signInResolver) {
1522
- response.backstageIdentity = await this._signInResolver({
1777
+ if (this.signInResolver) {
1778
+ response.backstageIdentity = await this.signInResolver({
1523
1779
  result,
1524
1780
  profile
1525
1781
  }, {
1526
- tokenIssuer: this._tokenIssuer,
1527
- catalogIdentityClient: this._catalogIdentityClient,
1528
- logger: this._logger
1782
+ tokenIssuer: this.tokenIssuer,
1783
+ catalogIdentityClient: this.catalogIdentityClient,
1784
+ logger: this.logger
1529
1785
  });
1530
1786
  }
1531
1787
  return response;
1532
1788
  }
1533
- }
1534
- const oktaEmailSignInResolver = async (info, ctx) => {
1535
- const { profile } = info;
1536
- if (!profile.email) {
1537
- throw new Error("Okta profile contained no email");
1789
+ encodeClientCredentials(clientID, clientSecret) {
1790
+ return Buffer.from(`${clientID}:${clientSecret}`).toString("base64");
1538
1791
  }
1539
- const entity = await ctx.catalogIdentityClient.findUser({
1540
- annotations: {
1541
- "okta.com/email": profile.email
1542
- }
1543
- });
1544
- const claims = getEntityClaims(entity);
1545
- const token = await ctx.tokenIssuer.issueToken({ claims });
1546
- return { id: entity.metadata.name, entity, token };
1547
- };
1548
- const oktaDefaultSignInResolver = async (info, ctx) => {
1792
+ }
1793
+ const oAuth2DefaultSignInResolver$1 = async (info, ctx) => {
1549
1794
  const { profile } = info;
1550
1795
  if (!profile.email) {
1551
- throw new Error("Okta profile contained no email");
1796
+ throw new Error("Profile contained no email");
1552
1797
  }
1553
1798
  const userId = profile.email.split("@")[0];
1554
1799
  const token = await ctx.tokenIssuer.issueToken({
@@ -1556,7 +1801,7 @@ const oktaDefaultSignInResolver = async (info, ctx) => {
1556
1801
  });
1557
1802
  return { id: userId, token };
1558
1803
  };
1559
- const createOktaProvider = (_options) => {
1804
+ const createOAuth2Provider = (options) => {
1560
1805
  return ({
1561
1806
  providerId,
1562
1807
  globalConfig,
@@ -1565,103 +1810,126 @@ const createOktaProvider = (_options) => {
1565
1810
  catalogApi,
1566
1811
  logger
1567
1812
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1568
- var _a, _b;
1813
+ var _a, _b, _c;
1569
1814
  const clientId = envConfig.getString("clientId");
1570
1815
  const clientSecret = envConfig.getString("clientSecret");
1571
- const audience = envConfig.getString("audience");
1572
1816
  const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1573
- if (!audience.startsWith("https://")) {
1574
- throw new Error("URL for 'audience' must start with 'https://'.");
1575
- }
1817
+ const authorizationUrl = envConfig.getString("authorizationUrl");
1818
+ const tokenUrl = envConfig.getString("tokenUrl");
1819
+ const scope = envConfig.getOptionalString("scope");
1820
+ const includeBasicAuth = envConfig.getOptionalBoolean("includeBasicAuth");
1821
+ const disableRefresh = (_a = envConfig.getOptionalBoolean("disableRefresh")) != null ? _a : false;
1576
1822
  const catalogIdentityClient = new CatalogIdentityClient({
1577
1823
  catalogApi,
1578
1824
  tokenIssuer
1579
1825
  });
1580
- const authHandler = (_options == null ? void 0 : _options.authHandler) ? _options.authHandler : async ({ fullProfile, params }) => ({
1826
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1581
1827
  profile: makeProfileInfo(fullProfile, params.id_token)
1582
1828
  });
1583
- const signInResolverFn = (_b = (_a = _options == null ? void 0 : _options.signIn) == null ? void 0 : _a.resolver) != null ? _b : oktaDefaultSignInResolver;
1829
+ const signInResolverFn = (_c = (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver) != null ? _c : oAuth2DefaultSignInResolver$1;
1584
1830
  const signInResolver = (info) => signInResolverFn(info, {
1585
1831
  catalogIdentityClient,
1586
1832
  tokenIssuer,
1587
1833
  logger
1588
1834
  });
1589
- const provider = new OktaAuthProvider({
1590
- audience,
1835
+ const provider = new OAuth2AuthProvider({
1591
1836
  clientId,
1592
1837
  clientSecret,
1593
- callbackUrl,
1594
- authHandler,
1595
- signInResolver,
1596
1838
  tokenIssuer,
1597
1839
  catalogIdentityClient,
1598
- logger
1840
+ callbackUrl,
1841
+ signInResolver,
1842
+ authHandler,
1843
+ authorizationUrl,
1844
+ tokenUrl,
1845
+ scope,
1846
+ logger,
1847
+ includeBasicAuth
1599
1848
  });
1600
1849
  return OAuthAdapter.fromConfig(globalConfig, provider, {
1601
- disableRefresh: false,
1850
+ disableRefresh,
1602
1851
  providerId,
1603
1852
  tokenIssuer
1604
1853
  });
1605
1854
  });
1606
1855
  };
1607
1856
 
1608
- class BitbucketAuthProvider {
1857
+ class OidcAuthProvider {
1609
1858
  constructor(options) {
1859
+ this.implementation = this.setupStrategy(options);
1860
+ this.scope = options.scope;
1861
+ this.prompt = options.prompt;
1610
1862
  this.signInResolver = options.signInResolver;
1611
1863
  this.authHandler = options.authHandler;
1612
1864
  this.tokenIssuer = options.tokenIssuer;
1613
1865
  this.catalogIdentityClient = options.catalogIdentityClient;
1614
1866
  this.logger = options.logger;
1615
- this._strategy = new passportBitbucketOauth2.Strategy({
1616
- clientID: options.clientId,
1617
- clientSecret: options.clientSecret,
1618
- callbackURL: options.callbackUrl,
1619
- passReqToCallback: false
1620
- }, (accessToken, refreshToken, params, fullProfile, done) => {
1621
- done(void 0, {
1622
- fullProfile,
1623
- params,
1624
- accessToken,
1625
- refreshToken
1626
- }, {
1627
- refreshToken
1628
- });
1629
- });
1630
1867
  }
1631
1868
  async start(req) {
1632
- return await executeRedirectStrategy(req, this._strategy, {
1633
- accessType: "offline",
1634
- prompt: "consent",
1635
- scope: req.scope,
1869
+ const { strategy } = await this.implementation;
1870
+ const options = {
1871
+ scope: req.scope || this.scope || "openid profile email",
1636
1872
  state: encodeState(req.state)
1637
- });
1873
+ };
1874
+ const prompt = this.prompt || "none";
1875
+ if (prompt !== "auto") {
1876
+ options.prompt = prompt;
1877
+ }
1878
+ return await executeRedirectStrategy(req, strategy, options);
1638
1879
  }
1639
1880
  async handler(req) {
1640
- const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
1881
+ const { strategy } = await this.implementation;
1882
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, strategy);
1641
1883
  return {
1642
1884
  response: await this.handleResult(result),
1643
1885
  refreshToken: privateInfo.refreshToken
1644
1886
  };
1645
1887
  }
1646
1888
  async refresh(req) {
1647
- const { accessToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1648
- const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
1649
- return this.handleResult({
1650
- fullProfile,
1651
- params,
1652
- accessToken,
1653
- refreshToken: req.refreshToken
1889
+ const { client } = await this.implementation;
1890
+ const tokenset = await client.refresh(req.refreshToken);
1891
+ if (!tokenset.access_token) {
1892
+ throw new Error("Refresh failed");
1893
+ }
1894
+ const userinfo = await client.userinfo(tokenset.access_token);
1895
+ return {
1896
+ response: await this.handleResult({ tokenset, userinfo }),
1897
+ refreshToken: tokenset.refresh_token
1898
+ };
1899
+ }
1900
+ async setupStrategy(options) {
1901
+ const issuer = await openidClient.Issuer.discover(options.metadataUrl);
1902
+ const client = new issuer.Client({
1903
+ access_type: "offline",
1904
+ client_id: options.clientId,
1905
+ client_secret: options.clientSecret,
1906
+ redirect_uris: [options.callbackUrl],
1907
+ response_types: ["code"],
1908
+ id_token_signed_response_alg: options.tokenSignedResponseAlg || "RS256",
1909
+ scope: options.scope || ""
1910
+ });
1911
+ const strategy = new openidClient.Strategy({
1912
+ client,
1913
+ passReqToCallback: false
1914
+ }, (tokenset, userinfo, done) => {
1915
+ if (typeof done !== "function") {
1916
+ throw new Error("OIDC IdP must provide a userinfo_endpoint in the metadata response");
1917
+ }
1918
+ done(void 0, { tokenset, userinfo }, {
1919
+ refreshToken: tokenset.refresh_token
1920
+ });
1654
1921
  });
1922
+ strategy.error = console.error;
1923
+ return { strategy, client };
1655
1924
  }
1656
1925
  async handleResult(result) {
1657
- result.fullProfile.avatarUrl = result.fullProfile._json.links.avatar.href;
1658
1926
  const { profile } = await this.authHandler(result);
1659
1927
  const response = {
1660
1928
  providerInfo: {
1661
- idToken: result.params.id_token,
1662
- accessToken: result.accessToken,
1663
- scope: result.params.scope,
1664
- expiresInSeconds: result.params.expires_in
1929
+ idToken: result.tokenset.id_token,
1930
+ accessToken: result.tokenset.access_token,
1931
+ scope: result.tokenset.scope,
1932
+ expiresInSeconds: result.tokenset.expires_in
1665
1933
  },
1666
1934
  profile
1667
1935
  };
@@ -1678,35 +1946,18 @@ class BitbucketAuthProvider {
1678
1946
  return response;
1679
1947
  }
1680
1948
  }
1681
- const bitbucketUsernameSignInResolver = async (info, ctx) => {
1682
- const { result } = info;
1683
- if (!result.fullProfile.username) {
1684
- throw new Error("Bitbucket profile contained no Username");
1685
- }
1686
- const entity = await ctx.catalogIdentityClient.findUser({
1687
- annotations: {
1688
- "bitbucket.org/username": result.fullProfile.username
1689
- }
1690
- });
1691
- const claims = getEntityClaims(entity);
1692
- const token = await ctx.tokenIssuer.issueToken({ claims });
1693
- return { id: entity.metadata.name, entity, token };
1694
- };
1695
- const bitbucketUserIdSignInResolver = async (info, ctx) => {
1696
- const { result } = info;
1697
- if (!result.fullProfile.id) {
1698
- throw new Error("Bitbucket profile contained no User ID");
1949
+ const oAuth2DefaultSignInResolver = async (info, ctx) => {
1950
+ const { profile } = info;
1951
+ if (!profile.email) {
1952
+ throw new Error("Profile contained no email");
1699
1953
  }
1700
- const entity = await ctx.catalogIdentityClient.findUser({
1701
- annotations: {
1702
- "bitbucket.org/user-id": result.fullProfile.id
1703
- }
1954
+ const userId = profile.email.split("@")[0];
1955
+ const token = await ctx.tokenIssuer.issueToken({
1956
+ claims: { sub: userId, ent: [`user:default/${userId}`] }
1704
1957
  });
1705
- const claims = getEntityClaims(entity);
1706
- const token = await ctx.tokenIssuer.issueToken({ claims });
1707
- return { id: entity.metadata.name, entity, token };
1958
+ return { id: userId, token };
1708
1959
  };
1709
- const createBitbucketProvider = (options) => {
1960
+ const createOidcProvider = (options) => {
1710
1961
  return ({
1711
1962
  providerId,
1712
1963
  globalConfig,
@@ -1715,26 +1966,44 @@ const createBitbucketProvider = (options) => {
1715
1966
  catalogApi,
1716
1967
  logger
1717
1968
  }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1718
- var _a;
1969
+ var _a, _b;
1719
1970
  const clientId = envConfig.getString("clientId");
1720
1971
  const clientSecret = envConfig.getString("clientSecret");
1721
1972
  const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1973
+ const metadataUrl = envConfig.getString("metadataUrl");
1974
+ const tokenSignedResponseAlg = envConfig.getOptionalString("tokenSignedResponseAlg");
1975
+ const scope = envConfig.getOptionalString("scope");
1976
+ const prompt = envConfig.getOptionalString("prompt");
1722
1977
  const catalogIdentityClient = new CatalogIdentityClient({
1723
1978
  catalogApi,
1724
1979
  tokenIssuer
1725
1980
  });
1726
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1727
- profile: makeProfileInfo(fullProfile, params.id_token)
1981
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ userinfo }) => ({
1982
+ profile: {
1983
+ displayName: userinfo.name,
1984
+ email: userinfo.email,
1985
+ picture: userinfo.picture
1986
+ }
1987
+ });
1988
+ const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : oAuth2DefaultSignInResolver;
1989
+ const signInResolver = (info) => signInResolverFn(info, {
1990
+ catalogIdentityClient,
1991
+ tokenIssuer,
1992
+ logger
1728
1993
  });
1729
- const provider = new BitbucketAuthProvider({
1994
+ const provider = new OidcAuthProvider({
1730
1995
  clientId,
1731
1996
  clientSecret,
1732
1997
  callbackUrl,
1733
- signInResolver: (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver,
1998
+ tokenSignedResponseAlg,
1999
+ metadataUrl,
2000
+ scope,
2001
+ prompt,
2002
+ signInResolver,
1734
2003
  authHandler,
2004
+ logger,
1735
2005
  tokenIssuer,
1736
- catalogIdentityClient,
1737
- logger
2006
+ catalogIdentityClient
1738
2007
  });
1739
2008
  return OAuthAdapter.fromConfig(globalConfig, provider, {
1740
2009
  disableRefresh: false,
@@ -1744,140 +2013,117 @@ const createBitbucketProvider = (options) => {
1744
2013
  });
1745
2014
  };
1746
2015
 
1747
- const defaultScopes = ["offline_access", "read:me"];
1748
- class AtlassianStrategy extends OAuth2Strategy__default["default"] {
1749
- constructor(options, verify) {
1750
- if (!options.scope) {
1751
- throw new TypeError("Atlassian requires a scope option");
1752
- }
1753
- const scopes = options.scope.split(" ");
1754
- const optionsWithURLs = {
1755
- ...options,
1756
- authorizationURL: `https://auth.atlassian.com/authorize`,
1757
- tokenURL: `https://auth.atlassian.com/oauth/token`,
1758
- scope: Array.from(/* @__PURE__ */ new Set([...defaultScopes, ...scopes]))
1759
- };
1760
- super(optionsWithURLs, verify);
1761
- this.profileURL = "https://api.atlassian.com/me";
1762
- this.name = "atlassian";
1763
- this._oauth2.useAuthorizationHeaderforGET(true);
1764
- }
1765
- authorizationParams() {
1766
- return {
1767
- audience: "api.atlassian.com",
1768
- prompt: "consent"
1769
- };
1770
- }
1771
- userProfile(accessToken, done) {
1772
- this._oauth2.get(this.profileURL, accessToken, (err, body) => {
1773
- if (err) {
1774
- return done(new OAuth2Strategy.InternalOAuthError("Failed to fetch user profile", err.statusCode));
1775
- }
1776
- if (!body) {
1777
- return done(new Error("Failed to fetch user profile, body cannot be empty"));
1778
- }
1779
- try {
1780
- const json = typeof body !== "string" ? body.toString() : body;
1781
- const profile = AtlassianStrategy.parse(json);
1782
- return done(null, profile);
1783
- } catch (e) {
1784
- return done(new Error("Failed to parse user profile"));
2016
+ class OktaAuthProvider {
2017
+ constructor(options) {
2018
+ this._store = {
2019
+ store(_req, cb) {
2020
+ cb(null, null);
2021
+ },
2022
+ verify(_req, _state, cb) {
2023
+ cb(null, true);
1785
2024
  }
1786
- });
1787
- }
1788
- static parse(json) {
1789
- const resp = JSON.parse(json);
1790
- return {
1791
- id: resp.account_id,
1792
- provider: "atlassian",
1793
- username: resp.nickname,
1794
- displayName: resp.name,
1795
- emails: [{ value: resp.email }],
1796
- photos: [{ value: resp.picture }]
1797
2025
  };
1798
- }
1799
- }
1800
-
1801
- const atlassianDefaultAuthHandler = async ({
1802
- fullProfile,
1803
- params
1804
- }) => ({
1805
- profile: makeProfileInfo(fullProfile, params.id_token)
1806
- });
1807
- class AtlassianAuthProvider {
1808
- constructor(options) {
1809
- this.catalogIdentityClient = options.catalogIdentityClient;
1810
- this.logger = options.logger;
1811
- this.tokenIssuer = options.tokenIssuer;
1812
- this.authHandler = options.authHandler;
1813
- this.signInResolver = options.signInResolver;
1814
- this._strategy = new AtlassianStrategy({
2026
+ this._signInResolver = options.signInResolver;
2027
+ this._authHandler = options.authHandler;
2028
+ this._tokenIssuer = options.tokenIssuer;
2029
+ this._catalogIdentityClient = options.catalogIdentityClient;
2030
+ this._logger = options.logger;
2031
+ this._strategy = new passportOktaOauth.Strategy({
1815
2032
  clientID: options.clientId,
1816
2033
  clientSecret: options.clientSecret,
1817
2034
  callbackURL: options.callbackUrl,
1818
- scope: options.scopes
2035
+ audience: options.audience,
2036
+ passReqToCallback: false,
2037
+ store: this._store,
2038
+ response_type: "code"
1819
2039
  }, (accessToken, refreshToken, params, fullProfile, done) => {
1820
2040
  done(void 0, {
1821
- fullProfile,
1822
2041
  accessToken,
1823
2042
  refreshToken,
1824
- params
2043
+ params,
2044
+ fullProfile
2045
+ }, {
2046
+ refreshToken
1825
2047
  });
1826
2048
  });
1827
2049
  }
1828
2050
  async start(req) {
1829
2051
  return await executeRedirectStrategy(req, this._strategy, {
2052
+ accessType: "offline",
2053
+ prompt: "consent",
2054
+ scope: req.scope,
1830
2055
  state: encodeState(req.state)
1831
2056
  });
1832
2057
  }
1833
2058
  async handler(req) {
1834
- var _a;
1835
- const { result } = await executeFrameHandlerStrategy(req, this._strategy);
2059
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
1836
2060
  return {
1837
2061
  response: await this.handleResult(result),
1838
- refreshToken: (_a = result.refreshToken) != null ? _a : ""
2062
+ refreshToken: privateInfo.refreshToken
2063
+ };
2064
+ }
2065
+ async refresh(req) {
2066
+ const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
2067
+ const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
2068
+ return {
2069
+ response: await this.handleResult({
2070
+ fullProfile,
2071
+ params,
2072
+ accessToken
2073
+ }),
2074
+ refreshToken
1839
2075
  };
1840
2076
  }
1841
2077
  async handleResult(result) {
1842
- const { profile } = await this.authHandler(result);
2078
+ const { profile } = await this._authHandler(result);
1843
2079
  const response = {
1844
2080
  providerInfo: {
1845
2081
  idToken: result.params.id_token,
1846
2082
  accessToken: result.accessToken,
1847
- refreshToken: result.refreshToken,
1848
2083
  scope: result.params.scope,
1849
2084
  expiresInSeconds: result.params.expires_in
1850
2085
  },
1851
2086
  profile
1852
2087
  };
1853
- if (this.signInResolver) {
1854
- response.backstageIdentity = await this.signInResolver({
2088
+ if (this._signInResolver) {
2089
+ response.backstageIdentity = await this._signInResolver({
1855
2090
  result,
1856
2091
  profile
1857
2092
  }, {
1858
- tokenIssuer: this.tokenIssuer,
1859
- catalogIdentityClient: this.catalogIdentityClient,
1860
- logger: this.logger
2093
+ tokenIssuer: this._tokenIssuer,
2094
+ catalogIdentityClient: this._catalogIdentityClient,
2095
+ logger: this._logger
1861
2096
  });
1862
2097
  }
1863
2098
  return response;
1864
2099
  }
1865
- async refresh(req) {
1866
- const {
1867
- accessToken,
1868
- params,
1869
- refreshToken: newRefreshToken
1870
- } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1871
- const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
1872
- return this.handleResult({
1873
- fullProfile,
1874
- params,
1875
- accessToken,
1876
- refreshToken: newRefreshToken
1877
- });
1878
- }
1879
2100
  }
1880
- const createAtlassianProvider = (options) => {
2101
+ const oktaEmailSignInResolver = async (info, ctx) => {
2102
+ const { profile } = info;
2103
+ if (!profile.email) {
2104
+ throw new Error("Okta profile contained no email");
2105
+ }
2106
+ const entity = await ctx.catalogIdentityClient.findUser({
2107
+ annotations: {
2108
+ "okta.com/email": profile.email
2109
+ }
2110
+ });
2111
+ const claims = getEntityClaims(entity);
2112
+ const token = await ctx.tokenIssuer.issueToken({ claims });
2113
+ return { id: entity.metadata.name, entity, token };
2114
+ };
2115
+ const oktaDefaultSignInResolver = async (info, ctx) => {
2116
+ const { profile } = info;
2117
+ if (!profile.email) {
2118
+ throw new Error("Okta profile contained no email");
2119
+ }
2120
+ const userId = profile.email.split("@")[0];
2121
+ const token = await ctx.tokenIssuer.issueToken({
2122
+ claims: { sub: userId, ent: [`user:default/${userId}`] }
2123
+ });
2124
+ return { id: userId, token };
2125
+ };
2126
+ const createOktaProvider = (_options) => {
1881
2127
  return ({
1882
2128
  providerId,
1883
2129
  globalConfig,
@@ -1889,158 +2135,165 @@ const createAtlassianProvider = (options) => {
1889
2135
  var _a, _b;
1890
2136
  const clientId = envConfig.getString("clientId");
1891
2137
  const clientSecret = envConfig.getString("clientSecret");
1892
- const scopes = envConfig.getString("scopes");
2138
+ const audience = envConfig.getString("audience");
1893
2139
  const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2140
+ if (!audience.startsWith("https://")) {
2141
+ throw new Error("URL for 'audience' must start with 'https://'.");
2142
+ }
1894
2143
  const catalogIdentityClient = new CatalogIdentityClient({
1895
2144
  catalogApi,
1896
2145
  tokenIssuer
1897
2146
  });
1898
- const authHandler = (_a = options == null ? void 0 : options.authHandler) != null ? _a : atlassianDefaultAuthHandler;
1899
- const provider = new AtlassianAuthProvider({
2147
+ const authHandler = (_options == null ? void 0 : _options.authHandler) ? _options.authHandler : async ({ fullProfile, params }) => ({
2148
+ profile: makeProfileInfo(fullProfile, params.id_token)
2149
+ });
2150
+ const signInResolverFn = (_b = (_a = _options == null ? void 0 : _options.signIn) == null ? void 0 : _a.resolver) != null ? _b : oktaDefaultSignInResolver;
2151
+ const signInResolver = (info) => signInResolverFn(info, {
2152
+ catalogIdentityClient,
2153
+ tokenIssuer,
2154
+ logger
2155
+ });
2156
+ const provider = new OktaAuthProvider({
2157
+ audience,
1900
2158
  clientId,
1901
2159
  clientSecret,
1902
- scopes,
1903
2160
  callbackUrl,
1904
2161
  authHandler,
1905
- signInResolver: (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver,
2162
+ signInResolver,
2163
+ tokenIssuer,
1906
2164
  catalogIdentityClient,
1907
- logger,
1908
- tokenIssuer
2165
+ logger
1909
2166
  });
1910
2167
  return OAuthAdapter.fromConfig(globalConfig, provider, {
1911
- disableRefresh: true,
2168
+ disableRefresh: false,
1912
2169
  providerId,
1913
2170
  tokenIssuer
1914
2171
  });
1915
2172
  });
1916
2173
  };
1917
2174
 
1918
- const ALB_JWT_HEADER = "x-amzn-oidc-data";
1919
- const ALB_ACCESSTOKEN_HEADER = "x-amzn-oidc-accesstoken";
1920
- const getJWTHeaders = (input) => {
1921
- const encoded = input.split(".")[0];
1922
- return JSON.parse(Buffer.from(encoded, "base64").toString("utf8"));
1923
- };
1924
- class AwsAlbAuthProvider {
2175
+ class OneLoginProvider {
1925
2176
  constructor(options) {
1926
- this.region = options.region;
1927
- this.issuer = options.issuer;
1928
- this.authHandler = options.authHandler;
1929
2177
  this.signInResolver = options.signInResolver;
2178
+ this.authHandler = options.authHandler;
1930
2179
  this.tokenIssuer = options.tokenIssuer;
1931
2180
  this.catalogIdentityClient = options.catalogIdentityClient;
1932
2181
  this.logger = options.logger;
1933
- this.keyCache = new NodeCache__default["default"]({ stdTTL: 3600 });
1934
- }
1935
- frameHandler() {
1936
- return Promise.resolve(void 0);
1937
- }
1938
- async refresh(req, res) {
1939
- try {
1940
- const result = await this.getResult(req);
1941
- const response = await this.handleResult(result);
1942
- res.json(response);
1943
- } catch (e) {
1944
- this.logger.error("Exception occurred during AWS ALB token refresh", e);
1945
- res.status(401);
1946
- res.end();
1947
- }
1948
- }
1949
- start() {
1950
- return Promise.resolve(void 0);
1951
- }
1952
- async getResult(req) {
1953
- const jwt = req.header(ALB_JWT_HEADER);
1954
- const accessToken = req.header(ALB_ACCESSTOKEN_HEADER);
1955
- if (jwt === void 0) {
1956
- throw new errors.AuthenticationError(`Missing ALB OIDC header: ${ALB_JWT_HEADER}`);
1957
- }
1958
- if (accessToken === void 0) {
1959
- throw new errors.AuthenticationError(`Missing ALB OIDC header: ${ALB_ACCESSTOKEN_HEADER}`);
1960
- }
1961
- try {
1962
- const headers = getJWTHeaders(jwt);
1963
- const key = await this.getKey(headers.kid);
1964
- const claims = jose.JWT.verify(jwt, key);
1965
- if (this.issuer && claims.iss !== this.issuer) {
1966
- throw new errors.AuthenticationError("Issuer mismatch on JWT token");
1967
- }
1968
- const fullProfile = {
1969
- provider: "unknown",
1970
- id: claims.sub,
1971
- displayName: claims.name,
1972
- username: claims.email.split("@")[0].toLowerCase(),
1973
- name: {
1974
- familyName: claims.family_name,
1975
- givenName: claims.given_name
1976
- },
1977
- emails: [{ value: claims.email.toLowerCase() }],
1978
- photos: [{ value: claims.picture }]
1979
- };
1980
- return {
2182
+ this._strategy = new passportOneloginOauth.Strategy({
2183
+ issuer: options.issuer,
2184
+ clientID: options.clientId,
2185
+ clientSecret: options.clientSecret,
2186
+ callbackURL: options.callbackUrl,
2187
+ passReqToCallback: false
2188
+ }, (accessToken, refreshToken, params, fullProfile, done) => {
2189
+ done(void 0, {
2190
+ accessToken,
2191
+ refreshToken,
2192
+ params,
2193
+ fullProfile
2194
+ }, {
2195
+ refreshToken
2196
+ });
2197
+ });
2198
+ }
2199
+ async start(req) {
2200
+ return await executeRedirectStrategy(req, this._strategy, {
2201
+ accessType: "offline",
2202
+ prompt: "consent",
2203
+ scope: "openid",
2204
+ state: encodeState(req.state)
2205
+ });
2206
+ }
2207
+ async handler(req) {
2208
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
2209
+ return {
2210
+ response: await this.handleResult(result),
2211
+ refreshToken: privateInfo.refreshToken
2212
+ };
2213
+ }
2214
+ async refresh(req) {
2215
+ const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
2216
+ const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
2217
+ return {
2218
+ response: await this.handleResult({
1981
2219
  fullProfile,
1982
- expiresInSeconds: claims.exp,
2220
+ params,
1983
2221
  accessToken
1984
- };
1985
- } catch (e) {
1986
- throw new Error(`Exception occurred during JWT processing: ${e}`);
1987
- }
2222
+ }),
2223
+ refreshToken
2224
+ };
1988
2225
  }
1989
2226
  async handleResult(result) {
1990
2227
  const { profile } = await this.authHandler(result);
1991
- const backstageIdentity = await this.signInResolver({
1992
- result,
1993
- profile
1994
- }, {
1995
- tokenIssuer: this.tokenIssuer,
1996
- catalogIdentityClient: this.catalogIdentityClient,
1997
- logger: this.logger
1998
- });
1999
- return {
2228
+ const response = {
2000
2229
  providerInfo: {
2230
+ idToken: result.params.id_token,
2001
2231
  accessToken: result.accessToken,
2002
- expiresInSeconds: result.expiresInSeconds
2232
+ scope: result.params.scope,
2233
+ expiresInSeconds: result.params.expires_in
2003
2234
  },
2004
- backstageIdentity: prepareBackstageIdentityResponse(backstageIdentity),
2005
2235
  profile
2006
2236
  };
2007
- }
2008
- async getKey(keyId) {
2009
- const optionalCacheKey = this.keyCache.get(keyId);
2010
- if (optionalCacheKey) {
2011
- return crypto__namespace.createPublicKey(optionalCacheKey);
2237
+ if (this.signInResolver) {
2238
+ response.backstageIdentity = await this.signInResolver({
2239
+ result,
2240
+ profile
2241
+ }, {
2242
+ tokenIssuer: this.tokenIssuer,
2243
+ catalogIdentityClient: this.catalogIdentityClient,
2244
+ logger: this.logger
2245
+ });
2012
2246
  }
2013
- const keyText = await fetch__default["default"](`https://public-keys.auth.elb.${this.region}.amazonaws.com/${keyId}`).then((response) => response.text());
2014
- const keyValue = crypto__namespace.createPublicKey(keyText);
2015
- this.keyCache.set(keyId, keyValue.export({ format: "pem", type: "spki" }));
2016
- return keyValue;
2247
+ return response;
2017
2248
  }
2018
2249
  }
2019
- const createAwsAlbProvider = (options) => {
2020
- return ({ config, tokenIssuer, catalogApi, logger }) => {
2021
- const region = config.getString("region");
2022
- const issuer = config.getOptionalString("iss");
2023
- if ((options == null ? void 0 : options.signIn.resolver) === void 0) {
2024
- throw new Error("SignInResolver is required to use this authentication provider");
2025
- }
2250
+ const defaultSignInResolver = async (info) => {
2251
+ const { profile } = info;
2252
+ if (!profile.email) {
2253
+ throw new Error("OIDC profile contained no email");
2254
+ }
2255
+ const id = profile.email.split("@")[0];
2256
+ return { id, token: "" };
2257
+ };
2258
+ const createOneLoginProvider = (options) => {
2259
+ return ({
2260
+ providerId,
2261
+ globalConfig,
2262
+ config,
2263
+ tokenIssuer,
2264
+ catalogApi,
2265
+ logger
2266
+ }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2267
+ var _a, _b;
2268
+ const clientId = envConfig.getString("clientId");
2269
+ const clientSecret = envConfig.getString("clientSecret");
2270
+ const issuer = envConfig.getString("issuer");
2271
+ const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2026
2272
  const catalogIdentityClient = new CatalogIdentityClient({
2027
2273
  catalogApi,
2028
2274
  tokenIssuer
2029
2275
  });
2030
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
2031
- profile: makeProfileInfo(fullProfile)
2276
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
2277
+ profile: makeProfileInfo(fullProfile, params.id_token)
2032
2278
  });
2033
- const signInResolver = options == null ? void 0 : options.signIn.resolver;
2034
- return new AwsAlbAuthProvider({
2035
- region,
2279
+ const signInResolver = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : defaultSignInResolver;
2280
+ const provider = new OneLoginProvider({
2281
+ clientId,
2282
+ clientSecret,
2283
+ callbackUrl,
2036
2284
  issuer,
2037
- signInResolver,
2038
2285
  authHandler,
2286
+ signInResolver,
2039
2287
  tokenIssuer,
2040
2288
  catalogIdentityClient,
2041
2289
  logger
2042
2290
  });
2043
- };
2291
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
2292
+ disableRefresh: false,
2293
+ providerId,
2294
+ tokenIssuer
2295
+ });
2296
+ });
2044
2297
  };
2045
2298
 
2046
2299
  class SamlAuthProvider {
@@ -2151,191 +2404,6 @@ const createSamlProvider = (options) => {
2151
2404
  };
2152
2405
  };
2153
2406
 
2154
- class Auth0Strategy extends OAuth2Strategy__default["default"] {
2155
- constructor(options, verify) {
2156
- const optionsWithURLs = {
2157
- ...options,
2158
- authorizationURL: `https://${options.domain}/authorize`,
2159
- tokenURL: `https://${options.domain}/oauth/token`,
2160
- userInfoURL: `https://${options.domain}/userinfo`,
2161
- apiUrl: `https://${options.domain}/api`
2162
- };
2163
- super(optionsWithURLs, verify);
2164
- }
2165
- }
2166
-
2167
- class Auth0AuthProvider {
2168
- constructor(options) {
2169
- this._strategy = new Auth0Strategy({
2170
- clientID: options.clientId,
2171
- clientSecret: options.clientSecret,
2172
- callbackURL: options.callbackUrl,
2173
- domain: options.domain,
2174
- passReqToCallback: false
2175
- }, (accessToken, refreshToken, params, fullProfile, done) => {
2176
- done(void 0, {
2177
- fullProfile,
2178
- accessToken,
2179
- refreshToken,
2180
- params
2181
- }, {
2182
- refreshToken
2183
- });
2184
- });
2185
- }
2186
- async start(req) {
2187
- return await executeRedirectStrategy(req, this._strategy, {
2188
- accessType: "offline",
2189
- prompt: "consent",
2190
- scope: req.scope,
2191
- state: encodeState(req.state)
2192
- });
2193
- }
2194
- async handler(req) {
2195
- const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
2196
- const profile = makeProfileInfo(result.fullProfile, result.params.id_token);
2197
- return {
2198
- response: await this.populateIdentity({
2199
- profile,
2200
- providerInfo: {
2201
- idToken: result.params.id_token,
2202
- accessToken: result.accessToken,
2203
- scope: result.params.scope,
2204
- expiresInSeconds: result.params.expires_in
2205
- }
2206
- }),
2207
- refreshToken: privateInfo.refreshToken
2208
- };
2209
- }
2210
- async refresh(req) {
2211
- const { accessToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
2212
- const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
2213
- const profile = makeProfileInfo(fullProfile, params.id_token);
2214
- return this.populateIdentity({
2215
- providerInfo: {
2216
- accessToken,
2217
- idToken: params.id_token,
2218
- expiresInSeconds: params.expires_in,
2219
- scope: params.scope
2220
- },
2221
- profile
2222
- });
2223
- }
2224
- async populateIdentity(response) {
2225
- const { profile } = response;
2226
- if (!profile.email) {
2227
- throw new Error("Profile does not contain an email");
2228
- }
2229
- const id = profile.email.split("@")[0];
2230
- return { ...response, backstageIdentity: { id, token: "" } };
2231
- }
2232
- }
2233
- const createAuth0Provider = (_options) => {
2234
- return ({ providerId, globalConfig, config, tokenIssuer }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2235
- const clientId = envConfig.getString("clientId");
2236
- const clientSecret = envConfig.getString("clientSecret");
2237
- const domain = envConfig.getString("domain");
2238
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2239
- const provider = new Auth0AuthProvider({
2240
- clientId,
2241
- clientSecret,
2242
- callbackUrl,
2243
- domain
2244
- });
2245
- return OAuthAdapter.fromConfig(globalConfig, provider, {
2246
- disableRefresh: true,
2247
- providerId,
2248
- tokenIssuer
2249
- });
2250
- });
2251
- };
2252
-
2253
- class OneLoginProvider {
2254
- constructor(options) {
2255
- this._strategy = new passportOneloginOauth.Strategy({
2256
- issuer: options.issuer,
2257
- clientID: options.clientId,
2258
- clientSecret: options.clientSecret,
2259
- callbackURL: options.callbackUrl,
2260
- passReqToCallback: false
2261
- }, (accessToken, refreshToken, params, fullProfile, done) => {
2262
- done(void 0, {
2263
- accessToken,
2264
- refreshToken,
2265
- params,
2266
- fullProfile
2267
- }, {
2268
- refreshToken
2269
- });
2270
- });
2271
- }
2272
- async start(req) {
2273
- return await executeRedirectStrategy(req, this._strategy, {
2274
- accessType: "offline",
2275
- prompt: "consent",
2276
- scope: "openid",
2277
- state: encodeState(req.state)
2278
- });
2279
- }
2280
- async handler(req) {
2281
- const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
2282
- const profile = makeProfileInfo(result.fullProfile, result.params.id_token);
2283
- return {
2284
- response: await this.populateIdentity({
2285
- profile,
2286
- providerInfo: {
2287
- idToken: result.params.id_token,
2288
- accessToken: result.accessToken,
2289
- scope: result.params.scope,
2290
- expiresInSeconds: result.params.expires_in
2291
- }
2292
- }),
2293
- refreshToken: privateInfo.refreshToken
2294
- };
2295
- }
2296
- async refresh(req) {
2297
- const { accessToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
2298
- const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
2299
- const profile = makeProfileInfo(fullProfile, params.id_token);
2300
- return this.populateIdentity({
2301
- providerInfo: {
2302
- accessToken,
2303
- idToken: params.id_token,
2304
- expiresInSeconds: params.expires_in,
2305
- scope: params.scope
2306
- },
2307
- profile
2308
- });
2309
- }
2310
- async populateIdentity(response) {
2311
- const { profile } = response;
2312
- if (!profile.email) {
2313
- throw new Error("OIDC profile contained no email");
2314
- }
2315
- const id = profile.email.split("@")[0];
2316
- return { ...response, backstageIdentity: { id, token: "" } };
2317
- }
2318
- }
2319
- const createOneLoginProvider = (_options) => {
2320
- return ({ providerId, globalConfig, config, tokenIssuer }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2321
- const clientId = envConfig.getString("clientId");
2322
- const clientSecret = envConfig.getString("clientSecret");
2323
- const issuer = envConfig.getString("issuer");
2324
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2325
- const provider = new OneLoginProvider({
2326
- clientId,
2327
- clientSecret,
2328
- callbackUrl,
2329
- issuer
2330
- });
2331
- return OAuthAdapter.fromConfig(globalConfig, provider, {
2332
- disableRefresh: false,
2333
- providerId,
2334
- tokenIssuer
2335
- });
2336
- });
2337
- };
2338
-
2339
2407
  const factories = {
2340
2408
  google: createGoogleProvider(),
2341
2409
  github: createGithubProvider(),
@@ -2801,6 +2869,7 @@ exports.OAuthEnvironmentHandler = OAuthEnvironmentHandler;
2801
2869
  exports.bitbucketUserIdSignInResolver = bitbucketUserIdSignInResolver;
2802
2870
  exports.bitbucketUsernameSignInResolver = bitbucketUsernameSignInResolver;
2803
2871
  exports.createAtlassianProvider = createAtlassianProvider;
2872
+ exports.createAuth0Provider = createAuth0Provider;
2804
2873
  exports.createAwsAlbProvider = createAwsAlbProvider;
2805
2874
  exports.createBitbucketProvider = createBitbucketProvider;
2806
2875
  exports.createGithubProvider = createGithubProvider;
@@ -2810,6 +2879,7 @@ exports.createMicrosoftProvider = createMicrosoftProvider;
2810
2879
  exports.createOAuth2Provider = createOAuth2Provider;
2811
2880
  exports.createOidcProvider = createOidcProvider;
2812
2881
  exports.createOktaProvider = createOktaProvider;
2882
+ exports.createOneLoginProvider = createOneLoginProvider;
2813
2883
  exports.createOriginFilter = createOriginFilter;
2814
2884
  exports.createRouter = createRouter;
2815
2885
  exports.createSamlProvider = createSamlProvider;