@backstage/plugin-auth-backend 0.13.0-next.1 → 0.13.0-next.2

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
@@ -11,7 +11,6 @@ var pickBy = require('lodash/pickBy');
11
11
  var crypto = require('crypto');
12
12
  var url = require('url');
13
13
  var jwtDecoder = require('jwt-decode');
14
- var catalogModel = require('@backstage/catalog-model');
15
14
  var fetch = require('node-fetch');
16
15
  var NodeCache = require('node-cache');
17
16
  var jose = require('jose');
@@ -29,6 +28,7 @@ var googleAuthLibrary = require('google-auth-library');
29
28
  var catalogClient = require('@backstage/catalog-client');
30
29
  var uuid = require('uuid');
31
30
  var luxon = require('luxon');
31
+ var catalogModel = require('@backstage/catalog-model');
32
32
  var backendCommon = require('@backstage/backend-common');
33
33
  var firestore = require('@google-cloud/firestore');
34
34
  var lodash = require('lodash');
@@ -542,75 +542,12 @@ const executeFetchUserProfileStrategy = async (providerStrategy, accessToken) =>
542
542
  });
543
543
  };
544
544
 
545
- class CatalogIdentityClient {
546
- constructor(options) {
547
- this.catalogApi = options.catalogApi;
548
- this.tokenManager = options.tokenManager;
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.tokenManager.getToken();
558
- const { items } = await this.catalogApi.getEntities({ filter }, { token });
559
- if (items.length !== 1) {
560
- if (items.length > 1) {
561
- throw new errors.ConflictError("User lookup resulted in multiple matches");
562
- } else {
563
- throw new errors.NotFoundError("User not found");
564
- }
565
- }
566
- return items[0];
567
- }
568
- async resolveCatalogMembership(query) {
569
- const { entityRefs, logger } = query;
570
- const resolvedEntityRefs = entityRefs.map((ref) => {
571
- try {
572
- const parsedRef = catalogModel.parseEntityRef(ref.toLocaleLowerCase("en-US"), {
573
- defaultKind: "user",
574
- defaultNamespace: "default"
575
- });
576
- return parsedRef;
577
- } catch {
578
- logger == null ? void 0 : logger.warn(`Failed to parse entityRef from ${ref}, ignoring`);
579
- return null;
580
- }
581
- }).filter((ref) => ref !== null);
582
- const filter = resolvedEntityRefs.map((ref) => ({
583
- kind: ref.kind,
584
- "metadata.namespace": ref.namespace,
585
- "metadata.name": ref.name
586
- }));
587
- const { token } = await this.tokenManager.getToken();
588
- const entities = await this.catalogApi.getEntities({ filter }, { token }).then((r) => r.items);
589
- if (entityRefs.length !== entities.length) {
590
- const foundEntityNames = entities.map(catalogModel.stringifyEntityRef);
591
- const missingEntityNames = resolvedEntityRefs.map(catalogModel.stringifyEntityRef).filter((s) => !foundEntityNames.includes(s));
592
- logger == null ? void 0 : logger.debug(`Entities not found for refs ${missingEntityNames.join()}`);
593
- }
594
- const memberOf = entities.flatMap((e) => {
595
- var _a, _b;
596
- return (_b = (_a = e.relations) == null ? void 0 : _a.filter((r) => r.type === catalogModel.RELATION_MEMBER_OF).map((r) => r.targetRef)) != null ? _b : [];
597
- });
598
- const newEntityRefs = [
599
- ...new Set(resolvedEntityRefs.map(catalogModel.stringifyEntityRef).concat(memberOf))
600
- ];
601
- logger == null ? void 0 : logger.debug(`Found catalog membership: ${newEntityRefs.join()}`);
602
- return newEntityRefs;
603
- }
604
- }
605
-
606
- function getEntityClaims(entity) {
607
- var _a, _b;
608
- const userRef = catalogModel.stringifyEntityRef(entity);
609
- const membershipRefs = (_b = (_a = entity.relations) == null ? void 0 : _a.filter((r) => r.type === catalogModel.RELATION_MEMBER_OF && r.targetRef.startsWith("group:")).map((r) => r.targetRef)) != null ? _b : [];
610
- return {
611
- sub: userRef,
612
- ent: [userRef, ...membershipRefs]
613
- };
545
+ function createAuthProviderIntegration(config) {
546
+ var _a;
547
+ return Object.freeze({
548
+ ...config,
549
+ resolvers: Object.freeze((_a = config.resolvers) != null ? _a : {})
550
+ });
614
551
  }
615
552
 
616
553
  const atlassianDefaultAuthHandler = async ({
@@ -621,9 +558,7 @@ const atlassianDefaultAuthHandler = async ({
621
558
  });
622
559
  class AtlassianAuthProvider {
623
560
  constructor(options) {
624
- this.catalogIdentityClient = options.catalogIdentityClient;
625
- this.logger = options.logger;
626
- this.tokenIssuer = options.tokenIssuer;
561
+ this.resolverContext = options.resolverContext;
627
562
  this.authHandler = options.authHandler;
628
563
  this.signInResolver = options.signInResolver;
629
564
  this._strategy = new AtlassianStrategy({
@@ -653,12 +588,7 @@ class AtlassianAuthProvider {
653
588
  };
654
589
  }
655
590
  async handleResult(result) {
656
- const context = {
657
- logger: this.logger,
658
- catalogIdentityClient: this.catalogIdentityClient,
659
- tokenIssuer: this.tokenIssuer
660
- };
661
- const { profile } = await this.authHandler(result, context);
591
+ const { profile } = await this.authHandler(result, this.resolverContext);
662
592
  const response = {
663
593
  providerInfo: {
664
594
  idToken: result.params.id_token,
@@ -672,7 +602,7 @@ class AtlassianAuthProvider {
672
602
  response.backstageIdentity = await this.signInResolver({
673
603
  result,
674
604
  profile
675
- }, context);
605
+ }, this.resolverContext);
676
606
  }
677
607
  return response;
678
608
  }
@@ -689,45 +619,33 @@ class AtlassianAuthProvider {
689
619
  };
690
620
  }
691
621
  }
692
- const createAtlassianProvider = (options) => {
693
- return ({
694
- providerId,
695
- globalConfig,
696
- config,
697
- tokenIssuer,
698
- tokenManager,
699
- catalogApi,
700
- logger
701
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
702
- var _a, _b;
703
- const clientId = envConfig.getString("clientId");
704
- const clientSecret = envConfig.getString("clientSecret");
705
- const scopes = envConfig.getString("scopes");
706
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
707
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
708
- const catalogIdentityClient = new CatalogIdentityClient({
709
- catalogApi,
710
- tokenManager
711
- });
712
- const authHandler = (_a = options == null ? void 0 : options.authHandler) != null ? _a : atlassianDefaultAuthHandler;
713
- const provider = new AtlassianAuthProvider({
714
- clientId,
715
- clientSecret,
716
- scopes,
717
- callbackUrl,
718
- authHandler,
719
- signInResolver: (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver,
720
- catalogIdentityClient,
721
- logger,
722
- tokenIssuer
723
- });
724
- return OAuthAdapter.fromConfig(globalConfig, provider, {
725
- providerId,
726
- tokenIssuer,
727
- callbackUrl
622
+ const atlassian = createAuthProviderIntegration({
623
+ create(options) {
624
+ return ({ providerId, globalConfig, config, resolverContext }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
625
+ var _a, _b;
626
+ const clientId = envConfig.getString("clientId");
627
+ const clientSecret = envConfig.getString("clientSecret");
628
+ const scopes = envConfig.getString("scopes");
629
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
630
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
631
+ const authHandler = (_a = options == null ? void 0 : options.authHandler) != null ? _a : atlassianDefaultAuthHandler;
632
+ const provider = new AtlassianAuthProvider({
633
+ clientId,
634
+ clientSecret,
635
+ scopes,
636
+ callbackUrl,
637
+ authHandler,
638
+ signInResolver: (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver,
639
+ resolverContext
640
+ });
641
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
642
+ providerId,
643
+ callbackUrl
644
+ });
728
645
  });
729
- });
730
- };
646
+ }
647
+ });
648
+ const createAtlassianProvider = atlassian.create;
731
649
 
732
650
  class Auth0Strategy extends OAuth2Strategy__default["default"] {
733
651
  constructor(options, verify) {
@@ -746,9 +664,7 @@ class Auth0AuthProvider {
746
664
  constructor(options) {
747
665
  this.signInResolver = options.signInResolver;
748
666
  this.authHandler = options.authHandler;
749
- this.tokenIssuer = options.tokenIssuer;
750
- this.catalogIdentityClient = options.catalogIdentityClient;
751
- this.logger = options.logger;
667
+ this.resolverContext = options.resolverContext;
752
668
  this._strategy = new Auth0Strategy({
753
669
  clientID: options.clientId,
754
670
  clientSecret: options.clientSecret,
@@ -794,12 +710,7 @@ class Auth0AuthProvider {
794
710
  };
795
711
  }
796
712
  async handleResult(result) {
797
- const context = {
798
- logger: this.logger,
799
- catalogIdentityClient: this.catalogIdentityClient,
800
- tokenIssuer: this.tokenIssuer
801
- };
802
- const { profile } = await this.authHandler(result, context);
713
+ const { profile } = await this.authHandler(result, this.resolverContext);
803
714
  const response = {
804
715
  providerInfo: {
805
716
  idToken: result.params.id_token,
@@ -813,62 +724,42 @@ class Auth0AuthProvider {
813
724
  response.backstageIdentity = await this.signInResolver({
814
725
  result,
815
726
  profile
816
- }, context);
727
+ }, this.resolverContext);
817
728
  }
818
729
  return response;
819
730
  }
820
731
  }
821
- const defaultSignInResolver$1 = async (info) => {
822
- const { profile } = info;
823
- if (!profile.email) {
824
- throw new Error("Profile does not contain an email");
825
- }
826
- const id = profile.email.split("@")[0];
827
- return { id, token: "" };
828
- };
829
- const createAuth0Provider = (options) => {
830
- return ({
831
- providerId,
832
- globalConfig,
833
- config,
834
- tokenIssuer,
835
- tokenManager,
836
- catalogApi,
837
- logger
838
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
839
- var _a, _b;
840
- const clientId = envConfig.getString("clientId");
841
- const clientSecret = envConfig.getString("clientSecret");
842
- const domain = envConfig.getString("domain");
843
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
844
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
845
- const catalogIdentityClient = new CatalogIdentityClient({
846
- catalogApi,
847
- tokenManager
848
- });
849
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
850
- profile: makeProfileInfo(fullProfile, params.id_token)
851
- });
852
- const signInResolver = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : defaultSignInResolver$1;
853
- const provider = new Auth0AuthProvider({
854
- clientId,
855
- clientSecret,
856
- callbackUrl,
857
- domain,
858
- authHandler,
859
- signInResolver,
860
- tokenIssuer,
861
- catalogIdentityClient,
862
- logger
863
- });
864
- return OAuthAdapter.fromConfig(globalConfig, provider, {
865
- disableRefresh: true,
866
- providerId,
867
- tokenIssuer,
868
- callbackUrl
732
+ const auth0 = createAuthProviderIntegration({
733
+ create(options) {
734
+ return ({ providerId, globalConfig, config, resolverContext }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
735
+ var _a;
736
+ const clientId = envConfig.getString("clientId");
737
+ const clientSecret = envConfig.getString("clientSecret");
738
+ const domain = envConfig.getString("domain");
739
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
740
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
741
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
742
+ profile: makeProfileInfo(fullProfile, params.id_token)
743
+ });
744
+ const signInResolver = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver;
745
+ const provider = new Auth0AuthProvider({
746
+ clientId,
747
+ clientSecret,
748
+ callbackUrl,
749
+ domain,
750
+ authHandler,
751
+ signInResolver,
752
+ resolverContext
753
+ });
754
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
755
+ disableRefresh: true,
756
+ providerId,
757
+ callbackUrl
758
+ });
869
759
  });
870
- });
871
- };
760
+ }
761
+ });
762
+ const createAuth0Provider = auth0.create;
872
763
 
873
764
  const ALB_JWT_HEADER = "x-amzn-oidc-data";
874
765
  const ALB_ACCESS_TOKEN_HEADER = "x-amzn-oidc-accesstoken";
@@ -882,9 +773,7 @@ class AwsAlbAuthProvider {
882
773
  this.issuer = options.issuer;
883
774
  this.authHandler = options.authHandler;
884
775
  this.signInResolver = options.signInResolver;
885
- this.tokenIssuer = options.tokenIssuer;
886
- this.catalogIdentityClient = options.catalogIdentityClient;
887
- this.logger = options.logger;
776
+ this.resolverContext = options.resolverContext;
888
777
  this.keyCache = new NodeCache__default["default"]({ stdTTL: 3600 });
889
778
  }
890
779
  frameHandler() {
@@ -896,9 +785,7 @@ class AwsAlbAuthProvider {
896
785
  const response = await this.handleResult(result);
897
786
  res.json(response);
898
787
  } catch (e) {
899
- this.logger.error("Exception occurred during AWS ALB token refresh", e);
900
- res.status(401);
901
- res.end();
788
+ throw new errors.AuthenticationError("Exception occurred during AWS ALB token refresh", e);
902
789
  }
903
790
  }
904
791
  start() {
@@ -942,16 +829,11 @@ class AwsAlbAuthProvider {
942
829
  }
943
830
  }
944
831
  async handleResult(result) {
945
- const context = {
946
- tokenIssuer: this.tokenIssuer,
947
- catalogIdentityClient: this.catalogIdentityClient,
948
- logger: this.logger
949
- };
950
- const { profile } = await this.authHandler(result, context);
832
+ const { profile } = await this.authHandler(result, this.resolverContext);
951
833
  const backstageIdentity = await this.signInResolver({
952
834
  result,
953
835
  profile
954
- }, context);
836
+ }, this.resolverContext);
955
837
  return {
956
838
  providerInfo: {
957
839
  accessToken: result.accessToken,
@@ -966,46 +848,40 @@ class AwsAlbAuthProvider {
966
848
  if (optionalCacheKey) {
967
849
  return crypto__namespace.createPublicKey(optionalCacheKey);
968
850
  }
969
- const keyText = await fetch__default["default"](`https://public-keys.auth.elb.${this.region}.amazonaws.com/${keyId}`).then((response) => response.text());
851
+ const keyText = await fetch__default["default"](`https://public-keys.auth.elb.${encodeURIComponent(this.region)}.amazonaws.com/${encodeURIComponent(keyId)}`).then((response) => response.text());
970
852
  const keyValue = crypto__namespace.createPublicKey(keyText);
971
853
  this.keyCache.set(keyId, keyValue.export({ format: "pem", type: "spki" }));
972
854
  return keyValue;
973
855
  }
974
856
  }
975
- const createAwsAlbProvider = (options) => {
976
- return ({ config, tokenIssuer, catalogApi, logger, tokenManager }) => {
977
- const region = config.getString("region");
978
- const issuer = config.getOptionalString("iss");
979
- if ((options == null ? void 0 : options.signIn.resolver) === void 0) {
980
- throw new Error("SignInResolver is required to use this authentication provider");
981
- }
982
- const catalogIdentityClient = new CatalogIdentityClient({
983
- catalogApi,
984
- tokenManager
985
- });
986
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
987
- profile: makeProfileInfo(fullProfile)
988
- });
989
- const signInResolver = options == null ? void 0 : options.signIn.resolver;
990
- return new AwsAlbAuthProvider({
991
- region,
992
- issuer,
993
- signInResolver,
994
- authHandler,
995
- tokenIssuer,
996
- catalogIdentityClient,
997
- logger
998
- });
999
- };
1000
- };
857
+ const awsAlb = createAuthProviderIntegration({
858
+ create(options) {
859
+ return ({ config, resolverContext }) => {
860
+ const region = config.getString("region");
861
+ const issuer = config.getOptionalString("iss");
862
+ if ((options == null ? void 0 : options.signIn.resolver) === void 0) {
863
+ throw new Error("SignInResolver is required to use this authentication provider");
864
+ }
865
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
866
+ profile: makeProfileInfo(fullProfile)
867
+ });
868
+ return new AwsAlbAuthProvider({
869
+ region,
870
+ issuer,
871
+ signInResolver: options == null ? void 0 : options.signIn.resolver,
872
+ authHandler,
873
+ resolverContext
874
+ });
875
+ };
876
+ }
877
+ });
878
+ const createAwsAlbProvider = awsAlb.create;
1001
879
 
1002
880
  class BitbucketAuthProvider {
1003
881
  constructor(options) {
1004
882
  this.signInResolver = options.signInResolver;
1005
883
  this.authHandler = options.authHandler;
1006
- this.tokenIssuer = options.tokenIssuer;
1007
- this.catalogIdentityClient = options.catalogIdentityClient;
1008
- this.logger = options.logger;
884
+ this.resolverContext = options.resolverContext;
1009
885
  this._strategy = new passportBitbucketOauth2.Strategy({
1010
886
  clientID: options.clientId,
1011
887
  clientSecret: options.clientSecret,
@@ -1051,12 +927,7 @@ class BitbucketAuthProvider {
1051
927
  }
1052
928
  async handleResult(result) {
1053
929
  result.fullProfile.avatarUrl = result.fullProfile._json.links.avatar.href;
1054
- const context = {
1055
- logger: this.logger,
1056
- catalogIdentityClient: this.catalogIdentityClient,
1057
- tokenIssuer: this.tokenIssuer
1058
- };
1059
- const { profile } = await this.authHandler(result, context);
930
+ const { profile } = await this.authHandler(result, this.resolverContext);
1060
931
  const response = {
1061
932
  providerInfo: {
1062
933
  idToken: result.params.id_token,
@@ -1070,79 +941,69 @@ class BitbucketAuthProvider {
1070
941
  response.backstageIdentity = await this.signInResolver({
1071
942
  result,
1072
943
  profile
1073
- }, context);
944
+ }, this.resolverContext);
1074
945
  }
1075
946
  return response;
1076
947
  }
1077
948
  }
1078
- const bitbucketUsernameSignInResolver = async (info, ctx) => {
1079
- const { result } = info;
1080
- if (!result.fullProfile.username) {
1081
- throw new Error("Bitbucket profile contained no Username");
1082
- }
1083
- const entity = await ctx.catalogIdentityClient.findUser({
1084
- annotations: {
1085
- "bitbucket.org/username": result.fullProfile.username
949
+ const bitbucket = createAuthProviderIntegration({
950
+ create(options) {
951
+ return ({ providerId, globalConfig, config, resolverContext }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
952
+ var _a;
953
+ const clientId = envConfig.getString("clientId");
954
+ const clientSecret = envConfig.getString("clientSecret");
955
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
956
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
957
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
958
+ profile: makeProfileInfo(fullProfile, params.id_token)
959
+ });
960
+ const provider = new BitbucketAuthProvider({
961
+ clientId,
962
+ clientSecret,
963
+ callbackUrl,
964
+ signInResolver: (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver,
965
+ authHandler,
966
+ resolverContext
967
+ });
968
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
969
+ disableRefresh: false,
970
+ providerId,
971
+ callbackUrl
972
+ });
973
+ });
974
+ },
975
+ resolvers: {
976
+ usernameMatchingUserEntityAnnotation() {
977
+ return async (info, ctx) => {
978
+ const { result } = info;
979
+ if (!result.fullProfile.username) {
980
+ throw new Error("Bitbucket profile contained no Username");
981
+ }
982
+ return ctx.signInWithCatalogUser({
983
+ annotations: {
984
+ "bitbucket.org/username": result.fullProfile.username
985
+ }
986
+ });
987
+ };
988
+ },
989
+ userIdMatchingUserEntityAnnotation() {
990
+ return async (info, ctx) => {
991
+ const { result } = info;
992
+ if (!result.fullProfile.id) {
993
+ throw new Error("Bitbucket profile contained no User ID");
994
+ }
995
+ return ctx.signInWithCatalogUser({
996
+ annotations: {
997
+ "bitbucket.org/user-id": result.fullProfile.id
998
+ }
999
+ });
1000
+ };
1086
1001
  }
1087
- });
1088
- const claims = getEntityClaims(entity);
1089
- const token = await ctx.tokenIssuer.issueToken({ claims });
1090
- return { id: entity.metadata.name, entity, token };
1091
- };
1092
- const bitbucketUserIdSignInResolver = async (info, ctx) => {
1093
- const { result } = info;
1094
- if (!result.fullProfile.id) {
1095
- throw new Error("Bitbucket profile contained no User ID");
1096
1002
  }
1097
- const entity = await ctx.catalogIdentityClient.findUser({
1098
- annotations: {
1099
- "bitbucket.org/user-id": result.fullProfile.id
1100
- }
1101
- });
1102
- const claims = getEntityClaims(entity);
1103
- const token = await ctx.tokenIssuer.issueToken({ claims });
1104
- return { id: entity.metadata.name, entity, token };
1105
- };
1106
- const createBitbucketProvider = (options) => {
1107
- return ({
1108
- providerId,
1109
- globalConfig,
1110
- config,
1111
- tokenIssuer,
1112
- tokenManager,
1113
- catalogApi,
1114
- logger
1115
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1116
- var _a;
1117
- const clientId = envConfig.getString("clientId");
1118
- const clientSecret = envConfig.getString("clientSecret");
1119
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1120
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1121
- const catalogIdentityClient = new CatalogIdentityClient({
1122
- catalogApi,
1123
- tokenManager
1124
- });
1125
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1126
- profile: makeProfileInfo(fullProfile, params.id_token)
1127
- });
1128
- const provider = new BitbucketAuthProvider({
1129
- clientId,
1130
- clientSecret,
1131
- callbackUrl,
1132
- signInResolver: (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver,
1133
- authHandler,
1134
- tokenIssuer,
1135
- catalogIdentityClient,
1136
- logger
1137
- });
1138
- return OAuthAdapter.fromConfig(globalConfig, provider, {
1139
- disableRefresh: false,
1140
- providerId,
1141
- tokenIssuer,
1142
- callbackUrl
1143
- });
1144
- });
1145
- };
1003
+ });
1004
+ const createBitbucketProvider = bitbucket.create;
1005
+ const bitbucketUsernameSignInResolver = bitbucket.resolvers.usernameMatchingUserEntityAnnotation();
1006
+ const bitbucketUserIdSignInResolver = bitbucket.resolvers.userIdMatchingUserEntityAnnotation();
1146
1007
 
1147
1008
  const ACCESS_TOKEN_PREFIX = "access-token.";
1148
1009
  const BACKSTAGE_SESSION_EXPIRATION = 3600;
@@ -1151,9 +1012,7 @@ class GithubAuthProvider {
1151
1012
  this.signInResolver = options.signInResolver;
1152
1013
  this.authHandler = options.authHandler;
1153
1014
  this.stateEncoder = options.stateEncoder;
1154
- this.tokenIssuer = options.tokenIssuer;
1155
- this.catalogIdentityClient = options.catalogIdentityClient;
1156
- this.logger = options.logger;
1015
+ this.resolverContext = options.resolverContext;
1157
1016
  this._strategy = new passportGithub2.Strategy({
1158
1017
  clientID: options.clientId,
1159
1018
  clientSecret: options.clientSecret,
@@ -1213,12 +1072,7 @@ class GithubAuthProvider {
1213
1072
  };
1214
1073
  }
1215
1074
  async handleResult(result) {
1216
- const context = {
1217
- logger: this.logger,
1218
- catalogIdentityClient: this.catalogIdentityClient,
1219
- tokenIssuer: this.tokenIssuer
1220
- };
1221
- const { profile } = await this.authHandler(result, context);
1075
+ const { profile } = await this.authHandler(result, this.resolverContext);
1222
1076
  const expiresInStr = result.params.expires_in;
1223
1077
  let expiresInSeconds = expiresInStr === void 0 ? void 0 : Number(expiresInStr);
1224
1078
  let backstageIdentity = void 0;
@@ -1226,7 +1080,7 @@ class GithubAuthProvider {
1226
1080
  backstageIdentity = await this.signInResolver({
1227
1081
  result,
1228
1082
  profile
1229
- }, context);
1083
+ }, this.resolverContext);
1230
1084
  if (expiresInSeconds) {
1231
1085
  expiresInSeconds = Math.min(expiresInSeconds, BACKSTAGE_SESSION_EXPIRATION);
1232
1086
  } else {
@@ -1244,99 +1098,58 @@ class GithubAuthProvider {
1244
1098
  };
1245
1099
  }
1246
1100
  }
1247
- const githubDefaultSignInResolver = async (info, ctx) => {
1248
- const { fullProfile } = info.result;
1249
- const userId = fullProfile.username || fullProfile.id;
1250
- const entityRef = catalogModel.stringifyEntityRef({
1251
- kind: "User",
1252
- namespace: catalogModel.DEFAULT_NAMESPACE,
1253
- name: userId
1254
- });
1255
- const token = await ctx.tokenIssuer.issueToken({
1256
- claims: {
1257
- sub: entityRef,
1258
- ent: [entityRef]
1259
- }
1260
- });
1261
- return { id: userId, token };
1262
- };
1263
- const createGithubProvider = (options) => {
1264
- return ({
1265
- providerId,
1266
- globalConfig,
1267
- config,
1268
- tokenIssuer,
1269
- tokenManager,
1270
- catalogApi,
1271
- logger
1272
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1273
- var _a, _b, _c, _d;
1274
- const clientId = envConfig.getString("clientId");
1275
- const clientSecret = envConfig.getString("clientSecret");
1276
- const enterpriseInstanceUrl = (_a = envConfig.getOptionalString("enterpriseInstanceUrl")) == null ? void 0 : _a.replace(/\/$/, "");
1277
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1278
- const authorizationUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/login/oauth/authorize` : void 0;
1279
- const tokenUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/login/oauth/access_token` : void 0;
1280
- const userProfileUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/api/v3/user` : void 0;
1281
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1282
- const catalogIdentityClient = new CatalogIdentityClient({
1283
- catalogApi,
1284
- tokenManager
1285
- });
1286
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
1287
- profile: makeProfileInfo(fullProfile)
1288
- });
1289
- const signInResolverFn = (_c = (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver) != null ? _c : githubDefaultSignInResolver;
1290
- const signInResolver = (info) => signInResolverFn(info, {
1291
- catalogIdentityClient,
1292
- tokenIssuer,
1293
- logger
1294
- });
1295
- const stateEncoder = (_d = options == null ? void 0 : options.stateEncoder) != null ? _d : async (req) => {
1296
- return { encodedState: encodeState(req.state) };
1297
- };
1298
- const provider = new GithubAuthProvider({
1299
- clientId,
1300
- clientSecret,
1301
- callbackUrl,
1302
- tokenUrl,
1303
- userProfileUrl,
1304
- authorizationUrl,
1305
- signInResolver,
1306
- authHandler,
1307
- tokenIssuer,
1308
- catalogIdentityClient,
1309
- stateEncoder,
1310
- logger
1311
- });
1312
- return OAuthAdapter.fromConfig(globalConfig, provider, {
1313
- persistScopes: true,
1314
- providerId,
1315
- tokenIssuer,
1316
- callbackUrl
1101
+ const github = createAuthProviderIntegration({
1102
+ create(options) {
1103
+ return ({ providerId, globalConfig, config, resolverContext }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1104
+ var _a, _b, _c;
1105
+ const clientId = envConfig.getString("clientId");
1106
+ const clientSecret = envConfig.getString("clientSecret");
1107
+ const enterpriseInstanceUrl = (_a = envConfig.getOptionalString("enterpriseInstanceUrl")) == null ? void 0 : _a.replace(/\/$/, "");
1108
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1109
+ const authorizationUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/login/oauth/authorize` : void 0;
1110
+ const tokenUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/login/oauth/access_token` : void 0;
1111
+ const userProfileUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/api/v3/user` : void 0;
1112
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1113
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
1114
+ profile: makeProfileInfo(fullProfile)
1115
+ });
1116
+ const stateEncoder = (_b = options == null ? void 0 : options.stateEncoder) != null ? _b : async (req) => {
1117
+ return { encodedState: encodeState(req.state) };
1118
+ };
1119
+ const provider = new GithubAuthProvider({
1120
+ clientId,
1121
+ clientSecret,
1122
+ callbackUrl,
1123
+ tokenUrl,
1124
+ userProfileUrl,
1125
+ authorizationUrl,
1126
+ signInResolver: (_c = options == null ? void 0 : options.signIn) == null ? void 0 : _c.resolver,
1127
+ authHandler,
1128
+ stateEncoder,
1129
+ resolverContext
1130
+ });
1131
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
1132
+ persistScopes: true,
1133
+ providerId,
1134
+ callbackUrl
1135
+ });
1317
1136
  });
1318
- });
1319
- };
1320
-
1321
- const gitlabDefaultSignInResolver = async (info, ctx) => {
1322
- const { profile, result } = info;
1323
- let id = result.fullProfile.id;
1324
- if (profile.email) {
1325
- id = profile.email.split("@")[0];
1326
- }
1327
- const entityRef = catalogModel.stringifyEntityRef({
1328
- kind: "User",
1329
- namespace: catalogModel.DEFAULT_NAMESPACE,
1330
- name: id
1331
- });
1332
- const token = await ctx.tokenIssuer.issueToken({
1333
- claims: {
1334
- sub: entityRef,
1335
- ent: [entityRef]
1137
+ },
1138
+ resolvers: {
1139
+ usernameMatchingUserEntityName: () => {
1140
+ return async (info, ctx) => {
1141
+ const { fullProfile } = info.result;
1142
+ const userId = fullProfile.username;
1143
+ if (!userId) {
1144
+ throw new Error(`GitHub user profile does not contain a username`);
1145
+ }
1146
+ return ctx.signInWithCatalogUser({ entityRef: { name: userId } });
1147
+ };
1336
1148
  }
1337
- });
1338
- return { id, token };
1339
- };
1149
+ }
1150
+ });
1151
+ const createGithubProvider = github.create;
1152
+
1340
1153
  const gitlabDefaultAuthHandler = async ({
1341
1154
  fullProfile,
1342
1155
  params
@@ -1345,9 +1158,7 @@ const gitlabDefaultAuthHandler = async ({
1345
1158
  });
1346
1159
  class GitlabAuthProvider {
1347
1160
  constructor(options) {
1348
- this.catalogIdentityClient = options.catalogIdentityClient;
1349
- this.logger = options.logger;
1350
- this.tokenIssuer = options.tokenIssuer;
1161
+ this.resolverContext = options.resolverContext;
1351
1162
  this.authHandler = options.authHandler;
1352
1163
  this.signInResolver = options.signInResolver;
1353
1164
  this._strategy = new passportGitlab2.Strategy({
@@ -1387,12 +1198,7 @@ class GitlabAuthProvider {
1387
1198
  };
1388
1199
  }
1389
1200
  async handleResult(result) {
1390
- const context = {
1391
- logger: this.logger,
1392
- catalogIdentityClient: this.catalogIdentityClient,
1393
- tokenIssuer: this.tokenIssuer
1394
- };
1395
- const { profile } = await this.authHandler(result, context);
1201
+ const { profile } = await this.authHandler(result, this.resolverContext);
1396
1202
  const response = {
1397
1203
  providerInfo: {
1398
1204
  idToken: result.params.id_token,
@@ -1406,67 +1212,58 @@ class GitlabAuthProvider {
1406
1212
  response.backstageIdentity = await this.signInResolver({
1407
1213
  result,
1408
1214
  profile
1409
- }, context);
1215
+ }, this.resolverContext);
1410
1216
  }
1411
1217
  return response;
1412
1218
  }
1413
1219
  }
1414
- const createGitlabProvider = (options) => {
1415
- return ({
1416
- providerId,
1417
- globalConfig,
1418
- config,
1419
- tokenIssuer,
1420
- tokenManager,
1421
- catalogApi,
1422
- logger
1423
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1424
- var _a, _b, _c;
1425
- const clientId = envConfig.getString("clientId");
1426
- const clientSecret = envConfig.getString("clientSecret");
1427
- const audience = envConfig.getOptionalString("audience");
1428
- const baseUrl = audience || "https://gitlab.com";
1429
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1430
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1431
- const catalogIdentityClient = new CatalogIdentityClient({
1432
- catalogApi,
1433
- tokenManager
1434
- });
1435
- const authHandler = (_a = options == null ? void 0 : options.authHandler) != null ? _a : gitlabDefaultAuthHandler;
1436
- const signInResolverFn = (_c = (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver) != null ? _c : gitlabDefaultSignInResolver;
1437
- const signInResolver = (info) => signInResolverFn(info, {
1438
- catalogIdentityClient,
1439
- tokenIssuer,
1440
- logger
1441
- });
1442
- const provider = new GitlabAuthProvider({
1443
- clientId,
1444
- clientSecret,
1445
- callbackUrl,
1446
- baseUrl,
1447
- authHandler,
1448
- signInResolver,
1449
- catalogIdentityClient,
1450
- logger,
1451
- tokenIssuer
1452
- });
1453
- return OAuthAdapter.fromConfig(globalConfig, provider, {
1454
- disableRefresh: false,
1455
- providerId,
1456
- tokenIssuer,
1457
- callbackUrl
1220
+ const gitlab = createAuthProviderIntegration({
1221
+ create(options) {
1222
+ return ({ providerId, globalConfig, config, resolverContext }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1223
+ var _a, _b;
1224
+ const clientId = envConfig.getString("clientId");
1225
+ const clientSecret = envConfig.getString("clientSecret");
1226
+ const audience = envConfig.getOptionalString("audience");
1227
+ const baseUrl = audience || "https://gitlab.com";
1228
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1229
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1230
+ const authHandler = (_a = options == null ? void 0 : options.authHandler) != null ? _a : gitlabDefaultAuthHandler;
1231
+ const provider = new GitlabAuthProvider({
1232
+ clientId,
1233
+ clientSecret,
1234
+ callbackUrl,
1235
+ baseUrl,
1236
+ authHandler,
1237
+ signInResolver: (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver,
1238
+ resolverContext
1239
+ });
1240
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
1241
+ disableRefresh: false,
1242
+ providerId,
1243
+ callbackUrl
1244
+ });
1458
1245
  });
1246
+ }
1247
+ });
1248
+ const createGitlabProvider = gitlab.create;
1249
+
1250
+ const commonByEmailLocalPartResolver = async (info, ctx) => {
1251
+ const { profile } = info;
1252
+ if (!profile.email) {
1253
+ throw new Error("Login failed, user profile does not contain an email");
1254
+ }
1255
+ const [localPart] = profile.email.split("@");
1256
+ return ctx.signInWithCatalogUser({
1257
+ entityRef: { name: localPart }
1459
1258
  });
1460
1259
  };
1461
1260
 
1462
1261
  class GoogleAuthProvider {
1463
1262
  constructor(options) {
1464
- this.signInResolver = options.signInResolver;
1465
1263
  this.authHandler = options.authHandler;
1466
- this.tokenIssuer = options.tokenIssuer;
1467
- this.catalogIdentityClient = options.catalogIdentityClient;
1468
- this.logger = options.logger;
1469
- this._strategy = new passportGoogleOauth20.Strategy({
1264
+ this.signInResolver = options.signInResolver;
1265
+ this.resolverContext = options.resolverContext;
1266
+ this.strategy = new passportGoogleOauth20.Strategy({
1470
1267
  clientID: options.clientId,
1471
1268
  clientSecret: options.clientSecret,
1472
1269
  callbackURL: options.callbackUrl,
@@ -1483,7 +1280,7 @@ class GoogleAuthProvider {
1483
1280
  });
1484
1281
  }
1485
1282
  async start(req) {
1486
- return await executeRedirectStrategy(req, this._strategy, {
1283
+ return await executeRedirectStrategy(req, this.strategy, {
1487
1284
  accessType: "offline",
1488
1285
  prompt: "consent",
1489
1286
  scope: req.scope,
@@ -1491,15 +1288,15 @@ class GoogleAuthProvider {
1491
1288
  });
1492
1289
  }
1493
1290
  async handler(req) {
1494
- const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
1291
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this.strategy);
1495
1292
  return {
1496
1293
  response: await this.handleResult(result),
1497
1294
  refreshToken: privateInfo.refreshToken
1498
1295
  };
1499
1296
  }
1500
1297
  async refresh(req) {
1501
- const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1502
- const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
1298
+ const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this.strategy, req.refreshToken, req.scope);
1299
+ const fullProfile = await executeFetchUserProfileStrategy(this.strategy, accessToken);
1503
1300
  return {
1504
1301
  response: await this.handleResult({
1505
1302
  fullProfile,
@@ -1510,12 +1307,7 @@ class GoogleAuthProvider {
1510
1307
  };
1511
1308
  }
1512
1309
  async handleResult(result) {
1513
- const context = {
1514
- logger: this.logger,
1515
- catalogIdentityClient: this.catalogIdentityClient,
1516
- tokenIssuer: this.tokenIssuer
1517
- };
1518
- const { profile } = await this.authHandler(result, context);
1310
+ const { profile } = await this.authHandler(result, this.resolverContext);
1519
1311
  const response = {
1520
1312
  providerInfo: {
1521
1313
  idToken: result.params.id_token,
@@ -1529,109 +1321,63 @@ class GoogleAuthProvider {
1529
1321
  response.backstageIdentity = await this.signInResolver({
1530
1322
  result,
1531
1323
  profile
1532
- }, context);
1324
+ }, this.resolverContext);
1533
1325
  }
1534
1326
  return response;
1535
1327
  }
1536
1328
  }
1537
- const googleEmailSignInResolver = async (info, ctx) => {
1538
- const { profile } = info;
1539
- if (!profile.email) {
1540
- throw new Error("Google profile contained no email");
1541
- }
1542
- const entity = await ctx.catalogIdentityClient.findUser({
1543
- annotations: {
1544
- "google.com/email": profile.email
1545
- }
1546
- });
1547
- const claims = getEntityClaims(entity);
1548
- const token = await ctx.tokenIssuer.issueToken({ claims });
1549
- return { id: entity.metadata.name, entity, token };
1550
- };
1551
- const googleDefaultSignInResolver = async (info, ctx) => {
1552
- const { profile } = info;
1553
- if (!profile.email) {
1554
- throw new Error("Google profile contained no email");
1555
- }
1556
- let userId;
1557
- try {
1558
- const entity = await ctx.catalogIdentityClient.findUser({
1559
- annotations: {
1560
- "google.com/email": profile.email
1561
- }
1329
+ const google = createAuthProviderIntegration({
1330
+ create(options) {
1331
+ return ({ providerId, globalConfig, config, resolverContext }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1332
+ var _a;
1333
+ const clientId = envConfig.getString("clientId");
1334
+ const clientSecret = envConfig.getString("clientSecret");
1335
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1336
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1337
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1338
+ profile: makeProfileInfo(fullProfile, params.id_token)
1339
+ });
1340
+ const provider = new GoogleAuthProvider({
1341
+ clientId,
1342
+ clientSecret,
1343
+ callbackUrl,
1344
+ signInResolver: (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver,
1345
+ authHandler,
1346
+ resolverContext
1347
+ });
1348
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
1349
+ disableRefresh: false,
1350
+ providerId,
1351
+ callbackUrl
1352
+ });
1562
1353
  });
1563
- userId = entity.metadata.name;
1564
- } catch (error) {
1565
- 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`);
1566
- userId = profile.email.split("@")[0];
1567
- }
1568
- const entityRef = catalogModel.stringifyEntityRef({
1569
- kind: "User",
1570
- namespace: catalogModel.DEFAULT_NAMESPACE,
1571
- name: userId
1572
- });
1573
- const token = await ctx.tokenIssuer.issueToken({
1574
- claims: {
1575
- sub: entityRef,
1576
- ent: [entityRef]
1354
+ },
1355
+ resolvers: {
1356
+ emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver,
1357
+ emailMatchingUserEntityAnnotation() {
1358
+ return async (info, ctx) => {
1359
+ const { profile } = info;
1360
+ if (!profile.email) {
1361
+ throw new Error("Google profile contained no email");
1362
+ }
1363
+ return ctx.signInWithCatalogUser({
1364
+ annotations: {
1365
+ "google.com/email": profile.email
1366
+ }
1367
+ });
1368
+ };
1577
1369
  }
1578
- });
1579
- return { id: userId, token };
1580
- };
1581
- const createGoogleProvider = (options) => {
1582
- return ({
1583
- providerId,
1584
- globalConfig,
1585
- config,
1586
- tokenIssuer,
1587
- tokenManager,
1588
- catalogApi,
1589
- logger
1590
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1591
- var _a, _b;
1592
- const clientId = envConfig.getString("clientId");
1593
- const clientSecret = envConfig.getString("clientSecret");
1594
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1595
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1596
- const catalogIdentityClient = new CatalogIdentityClient({
1597
- catalogApi,
1598
- tokenManager
1599
- });
1600
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1601
- profile: makeProfileInfo(fullProfile, params.id_token)
1602
- });
1603
- const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : googleDefaultSignInResolver;
1604
- const signInResolver = (info) => signInResolverFn(info, {
1605
- catalogIdentityClient,
1606
- tokenIssuer,
1607
- logger
1608
- });
1609
- const provider = new GoogleAuthProvider({
1610
- clientId,
1611
- clientSecret,
1612
- callbackUrl,
1613
- signInResolver,
1614
- authHandler,
1615
- tokenIssuer,
1616
- catalogIdentityClient,
1617
- logger
1618
- });
1619
- return OAuthAdapter.fromConfig(globalConfig, provider, {
1620
- disableRefresh: false,
1621
- providerId,
1622
- tokenIssuer,
1623
- callbackUrl
1624
- });
1625
- });
1626
- };
1370
+ }
1371
+ });
1372
+ const createGoogleProvider = google.create;
1373
+ const googleEmailSignInResolver = google.resolvers.emailMatchingUserEntityAnnotation();
1627
1374
 
1628
1375
  class MicrosoftAuthProvider {
1629
1376
  constructor(options) {
1630
1377
  this.signInResolver = options.signInResolver;
1631
1378
  this.authHandler = options.authHandler;
1632
- this.tokenIssuer = options.tokenIssuer;
1633
1379
  this.logger = options.logger;
1634
- this.catalogIdentityClient = options.catalogIdentityClient;
1380
+ this.resolverContext = options.resolverContext;
1635
1381
  this._strategy = new passportMicrosoft.Strategy({
1636
1382
  clientID: options.clientId,
1637
1383
  clientSecret: options.clientSecret,
@@ -1671,12 +1417,7 @@ class MicrosoftAuthProvider {
1671
1417
  async handleResult(result) {
1672
1418
  const photo = await this.getUserPhoto(result.accessToken);
1673
1419
  result.fullProfile.photos = photo ? [{ value: photo }] : void 0;
1674
- const context = {
1675
- logger: this.logger,
1676
- catalogIdentityClient: this.catalogIdentityClient,
1677
- tokenIssuer: this.tokenIssuer
1678
- };
1679
- const { profile } = await this.authHandler(result, context);
1420
+ const { profile } = await this.authHandler(result, this.resolverContext);
1680
1421
  const response = {
1681
1422
  providerInfo: {
1682
1423
  idToken: result.params.id_token,
@@ -1690,118 +1431,81 @@ class MicrosoftAuthProvider {
1690
1431
  response.backstageIdentity = await this.signInResolver({
1691
1432
  result,
1692
1433
  profile
1693
- }, context);
1434
+ }, this.resolverContext);
1694
1435
  }
1695
1436
  return response;
1696
1437
  }
1697
- getUserPhoto(accessToken) {
1698
- return new Promise((resolve) => {
1699
- fetch__default["default"]("https://graph.microsoft.com/v1.0/me/photos/48x48/$value", {
1438
+ async getUserPhoto(accessToken) {
1439
+ try {
1440
+ const res = await fetch__default["default"]("https://graph.microsoft.com/v1.0/me/photos/48x48/$value", {
1700
1441
  headers: {
1701
1442
  Authorization: `Bearer ${accessToken}`
1702
1443
  }
1703
- }).then((response) => response.arrayBuffer()).then((arrayBuffer) => {
1704
- const imageUrl = `data:image/jpeg;base64,${Buffer.from(arrayBuffer).toString("base64")}`;
1705
- resolve(imageUrl);
1706
- }).catch((error) => {
1707
- this.logger.warn(`Could not retrieve user profile photo from Microsoft Graph API: ${error}`);
1708
- resolve(void 0);
1709
1444
  });
1710
- });
1711
- }
1712
- }
1713
- const microsoftEmailSignInResolver = async (info, ctx) => {
1714
- const { profile } = info;
1715
- if (!profile.email) {
1716
- throw new Error("Microsoft profile contained no email");
1717
- }
1718
- const entity = await ctx.catalogIdentityClient.findUser({
1719
- annotations: {
1720
- "microsoft.com/email": profile.email
1445
+ const data = await res.buffer();
1446
+ return `data:image/jpeg;base64,${data.toString("base64")}`;
1447
+ } catch (error) {
1448
+ this.logger.warn(`Could not retrieve user profile photo from Microsoft Graph API: ${error}`);
1449
+ return void 0;
1721
1450
  }
1722
- });
1723
- const claims = getEntityClaims(entity);
1724
- const token = await ctx.tokenIssuer.issueToken({ claims });
1725
- return { id: entity.metadata.name, entity, token };
1726
- };
1727
- const microsoftDefaultSignInResolver = async (info, ctx) => {
1728
- const { profile } = info;
1729
- if (!profile.email) {
1730
- throw new Error("Profile contained no email");
1731
1451
  }
1732
- const userId = profile.email.split("@")[0];
1733
- const entityRef = catalogModel.stringifyEntityRef({
1734
- kind: "User",
1735
- namespace: catalogModel.DEFAULT_NAMESPACE,
1736
- name: userId
1737
- });
1738
- const token = await ctx.tokenIssuer.issueToken({
1739
- claims: {
1740
- sub: entityRef,
1741
- ent: [entityRef]
1742
- }
1743
- });
1744
- return { id: userId, token };
1745
- };
1746
- const createMicrosoftProvider = (options) => {
1747
- return ({
1748
- providerId,
1749
- globalConfig,
1750
- config,
1751
- tokenIssuer,
1752
- tokenManager,
1753
- catalogApi,
1754
- logger
1755
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1756
- var _a, _b;
1757
- const clientId = envConfig.getString("clientId");
1758
- const clientSecret = envConfig.getString("clientSecret");
1759
- const tenantId = envConfig.getString("tenantId");
1760
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1761
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1762
- const authorizationUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`;
1763
- const tokenUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
1764
- const catalogIdentityClient = new CatalogIdentityClient({
1765
- catalogApi,
1766
- tokenManager
1767
- });
1768
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1769
- profile: makeProfileInfo(fullProfile, params.id_token)
1770
- });
1771
- const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : microsoftDefaultSignInResolver;
1772
- const signInResolver = (info) => signInResolverFn(info, {
1773
- catalogIdentityClient,
1774
- tokenIssuer,
1775
- logger
1776
- });
1777
- const provider = new MicrosoftAuthProvider({
1778
- clientId,
1779
- clientSecret,
1780
- callbackUrl,
1781
- authorizationUrl,
1782
- tokenUrl,
1783
- authHandler,
1784
- signInResolver,
1785
- catalogIdentityClient,
1786
- logger,
1787
- tokenIssuer
1788
- });
1789
- return OAuthAdapter.fromConfig(globalConfig, provider, {
1790
- disableRefresh: false,
1791
- providerId,
1792
- tokenIssuer,
1793
- callbackUrl
1452
+ }
1453
+ const microsoft = createAuthProviderIntegration({
1454
+ create(options) {
1455
+ return ({ providerId, globalConfig, config, logger, resolverContext }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1456
+ var _a;
1457
+ const clientId = envConfig.getString("clientId");
1458
+ const clientSecret = envConfig.getString("clientSecret");
1459
+ const tenantId = envConfig.getString("tenantId");
1460
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1461
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1462
+ const authorizationUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`;
1463
+ const tokenUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
1464
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1465
+ profile: makeProfileInfo(fullProfile, params.id_token)
1466
+ });
1467
+ const provider = new MicrosoftAuthProvider({
1468
+ clientId,
1469
+ clientSecret,
1470
+ callbackUrl,
1471
+ authorizationUrl,
1472
+ tokenUrl,
1473
+ authHandler,
1474
+ signInResolver: (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver,
1475
+ logger,
1476
+ resolverContext
1477
+ });
1478
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
1479
+ disableRefresh: false,
1480
+ providerId,
1481
+ callbackUrl
1482
+ });
1794
1483
  });
1795
- });
1796
- };
1484
+ },
1485
+ resolvers: {
1486
+ emailMatchingUserEntityAnnotation() {
1487
+ return async (info, ctx) => {
1488
+ const { profile } = info;
1489
+ if (!profile.email) {
1490
+ throw new Error("Microsoft profile contained no email");
1491
+ }
1492
+ return ctx.signInWithCatalogUser({
1493
+ annotations: {
1494
+ "microsoft.com/email": profile.email
1495
+ }
1496
+ });
1497
+ };
1498
+ }
1499
+ }
1500
+ });
1501
+ const createMicrosoftProvider = microsoft.create;
1502
+ const microsoftEmailSignInResolver = microsoft.resolvers.emailMatchingUserEntityAnnotation();
1797
1503
 
1798
1504
  class OAuth2AuthProvider {
1799
1505
  constructor(options) {
1800
1506
  this.signInResolver = options.signInResolver;
1801
1507
  this.authHandler = options.authHandler;
1802
- this.tokenIssuer = options.tokenIssuer;
1803
- this.catalogIdentityClient = options.catalogIdentityClient;
1804
- this.logger = options.logger;
1508
+ this.resolverContext = options.resolverContext;
1805
1509
  this._strategy = new OAuth2Strategy.Strategy({
1806
1510
  clientID: options.clientId,
1807
1511
  clientSecret: options.clientSecret,
@@ -1853,12 +1557,7 @@ class OAuth2AuthProvider {
1853
1557
  };
1854
1558
  }
1855
1559
  async handleResult(result) {
1856
- const context = {
1857
- logger: this.logger,
1858
- catalogIdentityClient: this.catalogIdentityClient,
1859
- tokenIssuer: this.tokenIssuer
1860
- };
1861
- const { profile } = await this.authHandler(result, context);
1560
+ const { profile } = await this.authHandler(result, this.resolverContext);
1862
1561
  const response = {
1863
1562
  providerInfo: {
1864
1563
  idToken: result.params.id_token,
@@ -1872,7 +1571,7 @@ class OAuth2AuthProvider {
1872
1571
  response.backstageIdentity = await this.signInResolver({
1873
1572
  result,
1874
1573
  profile
1875
- }, context);
1574
+ }, this.resolverContext);
1876
1575
  }
1877
1576
  return response;
1878
1577
  }
@@ -1880,87 +1579,48 @@ class OAuth2AuthProvider {
1880
1579
  return Buffer.from(`${clientID}:${clientSecret}`).toString("base64");
1881
1580
  }
1882
1581
  }
1883
- const oAuth2DefaultSignInResolver = async (info, ctx) => {
1884
- const { profile } = info;
1885
- if (!profile.email) {
1886
- throw new Error("Profile contained no email");
1887
- }
1888
- const userId = profile.email.split("@")[0];
1889
- const entityRef = catalogModel.stringifyEntityRef({
1890
- kind: "User",
1891
- namespace: catalogModel.DEFAULT_NAMESPACE,
1892
- name: userId
1893
- });
1894
- const token = await ctx.tokenIssuer.issueToken({
1895
- claims: {
1896
- sub: entityRef,
1897
- ent: [entityRef]
1898
- }
1899
- });
1900
- return { id: userId, token };
1901
- };
1902
- const createOAuth2Provider = (options) => {
1903
- return ({
1904
- providerId,
1905
- globalConfig,
1906
- config,
1907
- tokenIssuer,
1908
- tokenManager,
1909
- catalogApi,
1910
- logger
1911
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1912
- var _a, _b, _c;
1913
- const clientId = envConfig.getString("clientId");
1914
- const clientSecret = envConfig.getString("clientSecret");
1915
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1916
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1917
- const authorizationUrl = envConfig.getString("authorizationUrl");
1918
- const tokenUrl = envConfig.getString("tokenUrl");
1919
- const scope = envConfig.getOptionalString("scope");
1920
- const includeBasicAuth = envConfig.getOptionalBoolean("includeBasicAuth");
1921
- const disableRefresh = (_a = envConfig.getOptionalBoolean("disableRefresh")) != null ? _a : false;
1922
- const catalogIdentityClient = new CatalogIdentityClient({
1923
- catalogApi,
1924
- tokenManager
1925
- });
1926
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1927
- profile: makeProfileInfo(fullProfile, params.id_token)
1928
- });
1929
- const signInResolverFn = (_c = (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver) != null ? _c : oAuth2DefaultSignInResolver;
1930
- const signInResolver = (info) => signInResolverFn(info, {
1931
- catalogIdentityClient,
1932
- tokenIssuer,
1933
- logger
1934
- });
1935
- const provider = new OAuth2AuthProvider({
1936
- clientId,
1937
- clientSecret,
1938
- tokenIssuer,
1939
- catalogIdentityClient,
1940
- callbackUrl,
1941
- signInResolver,
1942
- authHandler,
1943
- authorizationUrl,
1944
- tokenUrl,
1945
- scope,
1946
- logger,
1947
- includeBasicAuth
1948
- });
1949
- return OAuthAdapter.fromConfig(globalConfig, provider, {
1950
- disableRefresh,
1951
- providerId,
1952
- tokenIssuer,
1953
- callbackUrl
1582
+ const oauth2 = createAuthProviderIntegration({
1583
+ create(options) {
1584
+ return ({ providerId, globalConfig, config, resolverContext }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1585
+ var _a, _b;
1586
+ const clientId = envConfig.getString("clientId");
1587
+ const clientSecret = envConfig.getString("clientSecret");
1588
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1589
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1590
+ const authorizationUrl = envConfig.getString("authorizationUrl");
1591
+ const tokenUrl = envConfig.getString("tokenUrl");
1592
+ const scope = envConfig.getOptionalString("scope");
1593
+ const includeBasicAuth = envConfig.getOptionalBoolean("includeBasicAuth");
1594
+ const disableRefresh = (_a = envConfig.getOptionalBoolean("disableRefresh")) != null ? _a : false;
1595
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1596
+ profile: makeProfileInfo(fullProfile, params.id_token)
1597
+ });
1598
+ const provider = new OAuth2AuthProvider({
1599
+ clientId,
1600
+ clientSecret,
1601
+ callbackUrl,
1602
+ signInResolver: (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver,
1603
+ authHandler,
1604
+ authorizationUrl,
1605
+ tokenUrl,
1606
+ scope,
1607
+ includeBasicAuth,
1608
+ resolverContext
1609
+ });
1610
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
1611
+ disableRefresh,
1612
+ providerId,
1613
+ callbackUrl
1614
+ });
1954
1615
  });
1955
- });
1956
- };
1616
+ }
1617
+ });
1618
+ const createOAuth2Provider = oauth2.create;
1957
1619
 
1958
1620
  const OAUTH2_PROXY_JWT_HEADER = "X-OAUTH2-PROXY-ID-TOKEN";
1959
1621
  class Oauth2ProxyAuthProvider {
1960
1622
  constructor(options) {
1961
- this.catalogIdentityClient = options.catalogIdentityClient;
1962
- this.logger = options.logger;
1963
- this.tokenIssuer = options.tokenIssuer;
1623
+ this.resolverContext = options.resolverContext;
1964
1624
  this.signInResolver = options.signInResolver;
1965
1625
  this.authHandler = options.authHandler;
1966
1626
  }
@@ -1973,25 +1633,18 @@ class Oauth2ProxyAuthProvider {
1973
1633
  const response = await this.handleResult(result);
1974
1634
  res.json(response);
1975
1635
  } catch (e) {
1976
- this.logger.error(`Exception occurred during ${OAUTH2_PROXY_JWT_HEADER} refresh`, e);
1977
- res.status(401);
1978
- res.end();
1636
+ throw new errors.AuthenticationError("Refresh failed", e);
1979
1637
  }
1980
1638
  }
1981
1639
  start() {
1982
1640
  return Promise.resolve(void 0);
1983
1641
  }
1984
1642
  async handleResult(result) {
1985
- const ctx = {
1986
- logger: this.logger,
1987
- tokenIssuer: this.tokenIssuer,
1988
- catalogIdentityClient: this.catalogIdentityClient
1989
- };
1990
- const { profile } = await this.authHandler(result, ctx);
1643
+ const { profile } = await this.authHandler(result, this.resolverContext);
1991
1644
  const backstageSignInResult = await this.signInResolver({
1992
1645
  result,
1993
1646
  profile
1994
- }, ctx);
1647
+ }, this.resolverContext);
1995
1648
  return {
1996
1649
  providerInfo: {
1997
1650
  accessToken: result.accessToken
@@ -2013,21 +1666,20 @@ class Oauth2ProxyAuthProvider {
2013
1666
  };
2014
1667
  }
2015
1668
  }
2016
- const createOauth2ProxyProvider = (options) => ({ catalogApi, logger, tokenIssuer, tokenManager }) => {
2017
- const signInResolver = options.signIn.resolver;
2018
- const authHandler = options.authHandler;
2019
- const catalogIdentityClient = new CatalogIdentityClient({
2020
- catalogApi,
2021
- tokenManager
2022
- });
2023
- return new Oauth2ProxyAuthProvider({
2024
- logger,
2025
- signInResolver,
2026
- authHandler,
2027
- tokenIssuer,
2028
- catalogIdentityClient
2029
- });
2030
- };
1669
+ const oauth2Proxy = createAuthProviderIntegration({
1670
+ create(options) {
1671
+ return ({ resolverContext }) => {
1672
+ const signInResolver = options.signIn.resolver;
1673
+ const authHandler = options.authHandler;
1674
+ return new Oauth2ProxyAuthProvider({
1675
+ resolverContext,
1676
+ signInResolver,
1677
+ authHandler
1678
+ });
1679
+ };
1680
+ }
1681
+ });
1682
+ const createOauth2ProxyProvider = oauth2Proxy.create;
2031
1683
 
2032
1684
  class OidcAuthProvider {
2033
1685
  constructor(options) {
@@ -2036,9 +1688,7 @@ class OidcAuthProvider {
2036
1688
  this.prompt = options.prompt;
2037
1689
  this.signInResolver = options.signInResolver;
2038
1690
  this.authHandler = options.authHandler;
2039
- this.tokenIssuer = options.tokenIssuer;
2040
- this.catalogIdentityClient = options.catalogIdentityClient;
2041
- this.logger = options.logger;
1691
+ this.resolverContext = options.resolverContext;
2042
1692
  }
2043
1693
  async start(req) {
2044
1694
  const { strategy } = await this.implementation;
@@ -2098,12 +1748,7 @@ class OidcAuthProvider {
2098
1748
  return { strategy, client };
2099
1749
  }
2100
1750
  async handleResult(result) {
2101
- const context = {
2102
- logger: this.logger,
2103
- catalogIdentityClient: this.catalogIdentityClient,
2104
- tokenIssuer: this.tokenIssuer
2105
- };
2106
- const { profile } = await this.authHandler(result, context);
1751
+ const { profile } = await this.authHandler(result, this.resolverContext);
2107
1752
  const response = {
2108
1753
  providerInfo: {
2109
1754
  idToken: result.tokenset.id_token,
@@ -2117,92 +1762,55 @@ class OidcAuthProvider {
2117
1762
  response.backstageIdentity = await this.signInResolver({
2118
1763
  result,
2119
1764
  profile
2120
- }, context);
1765
+ }, this.resolverContext);
2121
1766
  }
2122
1767
  return response;
2123
1768
  }
2124
1769
  }
2125
- const oidcDefaultSignInResolver = async (info, ctx) => {
2126
- const { profile } = info;
2127
- if (!profile.email) {
2128
- throw new Error("Profile contained no email");
2129
- }
2130
- const userId = profile.email.split("@")[0];
2131
- const entityRef = catalogModel.stringifyEntityRef({
2132
- kind: "User",
2133
- namespace: catalogModel.DEFAULT_NAMESPACE,
2134
- name: userId
2135
- });
2136
- const token = await ctx.tokenIssuer.issueToken({
2137
- claims: {
2138
- sub: entityRef,
2139
- ent: [entityRef]
2140
- }
2141
- });
2142
- return { id: userId, token };
2143
- };
2144
- const createOidcProvider = (options) => {
2145
- return ({
2146
- providerId,
2147
- globalConfig,
2148
- config,
2149
- tokenIssuer,
2150
- tokenManager,
2151
- catalogApi,
2152
- logger
2153
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2154
- var _a, _b;
2155
- const clientId = envConfig.getString("clientId");
2156
- const clientSecret = envConfig.getString("clientSecret");
2157
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
2158
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2159
- const metadataUrl = envConfig.getString("metadataUrl");
2160
- const tokenSignedResponseAlg = envConfig.getOptionalString("tokenSignedResponseAlg");
2161
- const scope = envConfig.getOptionalString("scope");
2162
- const prompt = envConfig.getOptionalString("prompt");
2163
- const catalogIdentityClient = new CatalogIdentityClient({
2164
- catalogApi,
2165
- tokenManager
2166
- });
2167
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ userinfo }) => ({
2168
- profile: {
2169
- displayName: userinfo.name,
2170
- email: userinfo.email,
2171
- picture: userinfo.picture
2172
- }
2173
- });
2174
- const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : oidcDefaultSignInResolver;
2175
- const signInResolver = (info) => signInResolverFn(info, {
2176
- catalogIdentityClient,
2177
- tokenIssuer,
2178
- logger
2179
- });
2180
- const provider = new OidcAuthProvider({
2181
- clientId,
2182
- clientSecret,
2183
- callbackUrl,
2184
- tokenSignedResponseAlg,
2185
- metadataUrl,
2186
- scope,
2187
- prompt,
2188
- signInResolver,
2189
- authHandler,
2190
- logger,
2191
- tokenIssuer,
2192
- catalogIdentityClient
2193
- });
2194
- return OAuthAdapter.fromConfig(globalConfig, provider, {
2195
- disableRefresh: false,
2196
- providerId,
2197
- tokenIssuer,
2198
- callbackUrl
1770
+ const oidc = createAuthProviderIntegration({
1771
+ create(options) {
1772
+ return ({ providerId, globalConfig, config, resolverContext }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1773
+ var _a;
1774
+ const clientId = envConfig.getString("clientId");
1775
+ const clientSecret = envConfig.getString("clientSecret");
1776
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1777
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1778
+ const metadataUrl = envConfig.getString("metadataUrl");
1779
+ const tokenSignedResponseAlg = envConfig.getOptionalString("tokenSignedResponseAlg");
1780
+ const scope = envConfig.getOptionalString("scope");
1781
+ const prompt = envConfig.getOptionalString("prompt");
1782
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ userinfo }) => ({
1783
+ profile: {
1784
+ displayName: userinfo.name,
1785
+ email: userinfo.email,
1786
+ picture: userinfo.picture
1787
+ }
1788
+ });
1789
+ const provider = new OidcAuthProvider({
1790
+ clientId,
1791
+ clientSecret,
1792
+ callbackUrl,
1793
+ tokenSignedResponseAlg,
1794
+ metadataUrl,
1795
+ scope,
1796
+ prompt,
1797
+ signInResolver: (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver,
1798
+ authHandler,
1799
+ resolverContext
1800
+ });
1801
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
1802
+ disableRefresh: false,
1803
+ providerId,
1804
+ callbackUrl
1805
+ });
2199
1806
  });
2200
- });
2201
- };
1807
+ }
1808
+ });
1809
+ const createOidcProvider = oidc.create;
2202
1810
 
2203
1811
  class OktaAuthProvider {
2204
1812
  constructor(options) {
2205
- this._store = {
1813
+ this.store = {
2206
1814
  store(_req, cb) {
2207
1815
  cb(null, null);
2208
1816
  },
@@ -2210,18 +1818,16 @@ class OktaAuthProvider {
2210
1818
  cb(null, true);
2211
1819
  }
2212
1820
  };
2213
- this._signInResolver = options.signInResolver;
2214
- this._authHandler = options.authHandler;
2215
- this._tokenIssuer = options.tokenIssuer;
2216
- this._catalogIdentityClient = options.catalogIdentityClient;
2217
- this._logger = options.logger;
2218
- this._strategy = new passportOktaOauth.Strategy({
1821
+ this.signInResolver = options.signInResolver;
1822
+ this.authHandler = options.authHandler;
1823
+ this.resolverContext = options.resolverContext;
1824
+ this.strategy = new passportOktaOauth.Strategy({
2219
1825
  clientID: options.clientId,
2220
1826
  clientSecret: options.clientSecret,
2221
1827
  callbackURL: options.callbackUrl,
2222
1828
  audience: options.audience,
2223
1829
  passReqToCallback: false,
2224
- store: this._store,
1830
+ store: this.store,
2225
1831
  response_type: "code"
2226
1832
  }, (accessToken, refreshToken, params, fullProfile, done) => {
2227
1833
  done(void 0, {
@@ -2235,7 +1841,7 @@ class OktaAuthProvider {
2235
1841
  });
2236
1842
  }
2237
1843
  async start(req) {
2238
- return await executeRedirectStrategy(req, this._strategy, {
1844
+ return await executeRedirectStrategy(req, this.strategy, {
2239
1845
  accessType: "offline",
2240
1846
  prompt: "consent",
2241
1847
  scope: req.scope,
@@ -2243,15 +1849,15 @@ class OktaAuthProvider {
2243
1849
  });
2244
1850
  }
2245
1851
  async handler(req) {
2246
- const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
1852
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this.strategy);
2247
1853
  return {
2248
1854
  response: await this.handleResult(result),
2249
1855
  refreshToken: privateInfo.refreshToken
2250
1856
  };
2251
1857
  }
2252
1858
  async refresh(req) {
2253
- const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
2254
- const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
1859
+ const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this.strategy, req.refreshToken, req.scope);
1860
+ const fullProfile = await executeFetchUserProfileStrategy(this.strategy, accessToken);
2255
1861
  return {
2256
1862
  response: await this.handleResult({
2257
1863
  fullProfile,
@@ -2262,12 +1868,7 @@ class OktaAuthProvider {
2262
1868
  };
2263
1869
  }
2264
1870
  async handleResult(result) {
2265
- const context = {
2266
- logger: this._logger,
2267
- catalogIdentityClient: this._catalogIdentityClient,
2268
- tokenIssuer: this._tokenIssuer
2269
- };
2270
- const { profile } = await this._authHandler(result, context);
1871
+ const { profile } = await this.authHandler(result, this.resolverContext);
2271
1872
  const response = {
2272
1873
  providerInfo: {
2273
1874
  idToken: result.params.id_token,
@@ -2277,107 +1878,70 @@ class OktaAuthProvider {
2277
1878
  },
2278
1879
  profile
2279
1880
  };
2280
- if (this._signInResolver) {
2281
- response.backstageIdentity = await this._signInResolver({
1881
+ if (this.signInResolver) {
1882
+ response.backstageIdentity = await this.signInResolver({
2282
1883
  result,
2283
1884
  profile
2284
- }, context);
1885
+ }, this.resolverContext);
2285
1886
  }
2286
1887
  return response;
2287
1888
  }
2288
1889
  }
2289
- const oktaEmailSignInResolver = async (info, ctx) => {
2290
- const { profile } = info;
2291
- if (!profile.email) {
2292
- throw new Error("Okta profile contained no email");
2293
- }
2294
- const entity = await ctx.catalogIdentityClient.findUser({
2295
- annotations: {
2296
- "okta.com/email": profile.email
1890
+ const okta = createAuthProviderIntegration({
1891
+ create(options) {
1892
+ return ({ providerId, globalConfig, config, resolverContext }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1893
+ var _a;
1894
+ const clientId = envConfig.getString("clientId");
1895
+ const clientSecret = envConfig.getString("clientSecret");
1896
+ const audience = envConfig.getString("audience");
1897
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1898
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1899
+ if (!audience.startsWith("https://")) {
1900
+ throw new Error("URL for 'audience' must start with 'https://'.");
1901
+ }
1902
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1903
+ profile: makeProfileInfo(fullProfile, params.id_token)
1904
+ });
1905
+ const provider = new OktaAuthProvider({
1906
+ audience,
1907
+ clientId,
1908
+ clientSecret,
1909
+ callbackUrl,
1910
+ authHandler,
1911
+ signInResolver: (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver,
1912
+ resolverContext
1913
+ });
1914
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
1915
+ disableRefresh: false,
1916
+ providerId,
1917
+ callbackUrl
1918
+ });
1919
+ });
1920
+ },
1921
+ resolvers: {
1922
+ emailMatchingUserEntityAnnotation() {
1923
+ return async (info, ctx) => {
1924
+ const { profile } = info;
1925
+ if (!profile.email) {
1926
+ throw new Error("Okta profile contained no email");
1927
+ }
1928
+ return ctx.signInWithCatalogUser({
1929
+ annotations: {
1930
+ "okta.com/email": profile.email
1931
+ }
1932
+ });
1933
+ };
2297
1934
  }
2298
- });
2299
- const claims = getEntityClaims(entity);
2300
- const token = await ctx.tokenIssuer.issueToken({ claims });
2301
- return { id: entity.metadata.name, entity, token };
2302
- };
2303
- const oktaDefaultSignInResolver = async (info, ctx) => {
2304
- const { profile } = info;
2305
- if (!profile.email) {
2306
- throw new Error("Okta profile contained no email");
2307
1935
  }
2308
- const userId = profile.email.split("@")[0];
2309
- const entityRef = catalogModel.stringifyEntityRef({
2310
- kind: "User",
2311
- namespace: catalogModel.DEFAULT_NAMESPACE,
2312
- name: userId
2313
- });
2314
- const token = await ctx.tokenIssuer.issueToken({
2315
- claims: {
2316
- sub: entityRef,
2317
- ent: [entityRef]
2318
- }
2319
- });
2320
- return { id: userId, token };
2321
- };
2322
- const createOktaProvider = (_options) => {
2323
- return ({
2324
- providerId,
2325
- globalConfig,
2326
- config,
2327
- tokenIssuer,
2328
- tokenManager,
2329
- catalogApi,
2330
- logger
2331
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2332
- var _a, _b;
2333
- const clientId = envConfig.getString("clientId");
2334
- const clientSecret = envConfig.getString("clientSecret");
2335
- const audience = envConfig.getString("audience");
2336
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
2337
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2338
- if (!audience.startsWith("https://")) {
2339
- throw new Error("URL for 'audience' must start with 'https://'.");
2340
- }
2341
- const catalogIdentityClient = new CatalogIdentityClient({
2342
- catalogApi,
2343
- tokenManager
2344
- });
2345
- const authHandler = (_options == null ? void 0 : _options.authHandler) ? _options.authHandler : async ({ fullProfile, params }) => ({
2346
- profile: makeProfileInfo(fullProfile, params.id_token)
2347
- });
2348
- const signInResolverFn = (_b = (_a = _options == null ? void 0 : _options.signIn) == null ? void 0 : _a.resolver) != null ? _b : oktaDefaultSignInResolver;
2349
- const signInResolver = (info) => signInResolverFn(info, {
2350
- catalogIdentityClient,
2351
- tokenIssuer,
2352
- logger
2353
- });
2354
- const provider = new OktaAuthProvider({
2355
- audience,
2356
- clientId,
2357
- clientSecret,
2358
- callbackUrl,
2359
- authHandler,
2360
- signInResolver,
2361
- tokenIssuer,
2362
- catalogIdentityClient,
2363
- logger
2364
- });
2365
- return OAuthAdapter.fromConfig(globalConfig, provider, {
2366
- disableRefresh: false,
2367
- providerId,
2368
- tokenIssuer,
2369
- callbackUrl
2370
- });
2371
- });
2372
- };
1936
+ });
1937
+ const createOktaProvider = okta.create;
1938
+ const oktaEmailSignInResolver = okta.resolvers.emailMatchingUserEntityAnnotation();
2373
1939
 
2374
1940
  class OneLoginProvider {
2375
1941
  constructor(options) {
2376
1942
  this.signInResolver = options.signInResolver;
2377
1943
  this.authHandler = options.authHandler;
2378
- this.tokenIssuer = options.tokenIssuer;
2379
- this.catalogIdentityClient = options.catalogIdentityClient;
2380
- this.logger = options.logger;
1944
+ this.resolverContext = options.resolverContext;
2381
1945
  this._strategy = new passportOneloginOauth.Strategy({
2382
1946
  issuer: options.issuer,
2383
1947
  clientID: options.clientId,
@@ -2423,12 +1987,7 @@ class OneLoginProvider {
2423
1987
  };
2424
1988
  }
2425
1989
  async handleResult(result) {
2426
- const context = {
2427
- logger: this.logger,
2428
- catalogIdentityClient: this.catalogIdentityClient,
2429
- tokenIssuer: this.tokenIssuer
2430
- };
2431
- const { profile } = await this.authHandler(result, context);
1990
+ const { profile } = await this.authHandler(result, this.resolverContext);
2432
1991
  const response = {
2433
1992
  providerInfo: {
2434
1993
  idToken: result.params.id_token,
@@ -2442,71 +2001,48 @@ class OneLoginProvider {
2442
2001
  response.backstageIdentity = await this.signInResolver({
2443
2002
  result,
2444
2003
  profile
2445
- }, context);
2004
+ }, this.resolverContext);
2446
2005
  }
2447
2006
  return response;
2448
2007
  }
2449
2008
  }
2450
- const defaultSignInResolver = async (info) => {
2451
- const { profile } = info;
2452
- if (!profile.email) {
2453
- throw new Error("OIDC profile contained no email");
2454
- }
2455
- const id = profile.email.split("@")[0];
2456
- return { id, token: "" };
2457
- };
2458
- const createOneLoginProvider = (options) => {
2459
- return ({
2460
- providerId,
2461
- globalConfig,
2462
- config,
2463
- tokenIssuer,
2464
- tokenManager,
2465
- catalogApi,
2466
- logger
2467
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2468
- var _a, _b;
2469
- const clientId = envConfig.getString("clientId");
2470
- const clientSecret = envConfig.getString("clientSecret");
2471
- const issuer = envConfig.getString("issuer");
2472
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
2473
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2474
- const catalogIdentityClient = new CatalogIdentityClient({
2475
- catalogApi,
2476
- tokenManager
2477
- });
2478
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
2479
- profile: makeProfileInfo(fullProfile, params.id_token)
2480
- });
2481
- const signInResolver = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : defaultSignInResolver;
2482
- const provider = new OneLoginProvider({
2483
- clientId,
2484
- clientSecret,
2485
- callbackUrl,
2486
- issuer,
2487
- authHandler,
2488
- signInResolver,
2489
- tokenIssuer,
2490
- catalogIdentityClient,
2491
- logger
2492
- });
2493
- return OAuthAdapter.fromConfig(globalConfig, provider, {
2494
- disableRefresh: false,
2495
- providerId,
2496
- tokenIssuer,
2497
- callbackUrl
2009
+ const onelogin = createAuthProviderIntegration({
2010
+ create(options) {
2011
+ return ({ providerId, globalConfig, config, resolverContext }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2012
+ var _a;
2013
+ const clientId = envConfig.getString("clientId");
2014
+ const clientSecret = envConfig.getString("clientSecret");
2015
+ const issuer = envConfig.getString("issuer");
2016
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
2017
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2018
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
2019
+ profile: makeProfileInfo(fullProfile, params.id_token)
2020
+ });
2021
+ const provider = new OneLoginProvider({
2022
+ clientId,
2023
+ clientSecret,
2024
+ callbackUrl,
2025
+ issuer,
2026
+ authHandler,
2027
+ signInResolver: (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver,
2028
+ resolverContext
2029
+ });
2030
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
2031
+ disableRefresh: false,
2032
+ providerId,
2033
+ callbackUrl
2034
+ });
2498
2035
  });
2499
- });
2500
- };
2036
+ }
2037
+ });
2038
+ const createOneLoginProvider = onelogin.create;
2501
2039
 
2502
2040
  class SamlAuthProvider {
2503
2041
  constructor(options) {
2504
2042
  this.appUrl = options.appUrl;
2505
2043
  this.signInResolver = options.signInResolver;
2506
2044
  this.authHandler = options.authHandler;
2507
- this.tokenIssuer = options.tokenIssuer;
2508
- this.catalogIdentityClient = options.catalogIdentityClient;
2509
- this.logger = options.logger;
2045
+ this.resolverContext = options.resolverContext;
2510
2046
  this.strategy = new passportSaml.Strategy({ ...options }, (fullProfile, done) => {
2511
2047
  done(void 0, { fullProfile });
2512
2048
  });
@@ -2517,13 +2053,8 @@ class SamlAuthProvider {
2517
2053
  }
2518
2054
  async frameHandler(req, res) {
2519
2055
  try {
2520
- const context = {
2521
- logger: this.logger,
2522
- catalogIdentityClient: this.catalogIdentityClient,
2523
- tokenIssuer: this.tokenIssuer
2524
- };
2525
2056
  const { result } = await executeFrameHandlerStrategy(req, this.strategy);
2526
- const { profile } = await this.authHandler(result, context);
2057
+ const { profile } = await this.authHandler(result, this.resolverContext);
2527
2058
  const response = {
2528
2059
  profile,
2529
2060
  providerInfo: {}
@@ -2532,7 +2063,7 @@ class SamlAuthProvider {
2532
2063
  const signInResponse = await this.signInResolver({
2533
2064
  result,
2534
2065
  profile
2535
- }, context);
2066
+ }, this.resolverContext);
2536
2067
  response.backstageIdentity = prepareBackstageIdentityResponse(signInResponse);
2537
2068
  }
2538
2069
  return postMessageResponse(res, this.appUrl, {
@@ -2551,71 +2082,53 @@ class SamlAuthProvider {
2551
2082
  res.end();
2552
2083
  }
2553
2084
  }
2554
- const samlDefaultSignInResolver = async (info, ctx) => {
2555
- const id = info.result.fullProfile.nameID;
2556
- const entityRef = catalogModel.stringifyEntityRef({
2557
- kind: "User",
2558
- namespace: catalogModel.DEFAULT_NAMESPACE,
2559
- name: id
2560
- });
2561
- const token = await ctx.tokenIssuer.issueToken({
2562
- claims: {
2563
- sub: entityRef,
2564
- ent: [entityRef]
2085
+ const saml = createAuthProviderIntegration({
2086
+ create(options) {
2087
+ return ({ providerId, globalConfig, config, resolverContext }) => {
2088
+ var _a;
2089
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
2090
+ profile: {
2091
+ email: fullProfile.email,
2092
+ displayName: fullProfile.displayName
2093
+ }
2094
+ });
2095
+ return new SamlAuthProvider({
2096
+ callbackUrl: `${globalConfig.baseUrl}/${providerId}/handler/frame`,
2097
+ entryPoint: config.getString("entryPoint"),
2098
+ logoutUrl: config.getOptionalString("logoutUrl"),
2099
+ audience: config.getOptionalString("audience"),
2100
+ issuer: config.getString("issuer"),
2101
+ cert: config.getString("cert"),
2102
+ privateKey: config.getOptionalString("privateKey"),
2103
+ authnContext: config.getOptionalStringArray("authnContext"),
2104
+ identifierFormat: config.getOptionalString("identifierFormat"),
2105
+ decryptionPvk: config.getOptionalString("decryptionPvk"),
2106
+ signatureAlgorithm: config.getOptionalString("signatureAlgorithm"),
2107
+ digestAlgorithm: config.getOptionalString("digestAlgorithm"),
2108
+ acceptedClockSkewMs: config.getOptionalNumber("acceptedClockSkewMs"),
2109
+ appUrl: globalConfig.appUrl,
2110
+ authHandler,
2111
+ signInResolver: (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver,
2112
+ resolverContext
2113
+ });
2114
+ };
2115
+ },
2116
+ resolvers: {
2117
+ nameIdMatchingUserEntityName() {
2118
+ return async (info, ctx) => {
2119
+ const id = info.result.fullProfile.nameID;
2120
+ if (!id) {
2121
+ throw new errors.AuthenticationError("No nameID found in SAML response");
2122
+ }
2123
+ return ctx.signInWithCatalogUser({
2124
+ entityRef: { name: id }
2125
+ });
2126
+ };
2565
2127
  }
2566
- });
2567
- return { id, token };
2568
- };
2569
- const createSamlProvider = (options) => {
2570
- return ({
2571
- providerId,
2572
- globalConfig,
2573
- config,
2574
- tokenIssuer,
2575
- tokenManager,
2576
- catalogApi,
2577
- logger
2578
- }) => {
2579
- var _a, _b;
2580
- const catalogIdentityClient = new CatalogIdentityClient({
2581
- catalogApi,
2582
- tokenManager
2583
- });
2584
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
2585
- profile: {
2586
- email: fullProfile.email,
2587
- displayName: fullProfile.displayName
2588
- }
2589
- });
2590
- const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : samlDefaultSignInResolver;
2591
- const signInResolver = (info) => signInResolverFn(info, {
2592
- catalogIdentityClient,
2593
- tokenIssuer,
2594
- logger
2595
- });
2596
- return new SamlAuthProvider({
2597
- callbackUrl: `${globalConfig.baseUrl}/${providerId}/handler/frame`,
2598
- entryPoint: config.getString("entryPoint"),
2599
- logoutUrl: config.getOptionalString("logoutUrl"),
2600
- audience: config.getOptionalString("audience"),
2601
- issuer: config.getString("issuer"),
2602
- cert: config.getString("cert"),
2603
- privateKey: config.getOptionalString("privateKey"),
2604
- authnContext: config.getOptionalStringArray("authnContext"),
2605
- identifierFormat: config.getOptionalString("identifierFormat"),
2606
- decryptionPvk: config.getOptionalString("decryptionPvk"),
2607
- signatureAlgorithm: config.getOptionalString("signatureAlgorithm"),
2608
- digestAlgorithm: config.getOptionalString("digestAlgorithm"),
2609
- acceptedClockSkewMs: config.getOptionalNumber("acceptedClockSkewMs"),
2610
- tokenIssuer,
2611
- appUrl: globalConfig.appUrl,
2612
- authHandler,
2613
- signInResolver,
2614
- logger,
2615
- catalogIdentityClient
2616
- });
2617
- };
2618
- };
2128
+ }
2129
+ });
2130
+ const createSamlProvider = saml.create;
2131
+ const samlNameIdEntityNameSignInResolver = saml.resolvers.nameIdMatchingUserEntityName();
2619
2132
 
2620
2133
  const IAP_JWT_HEADER = "x-goog-iap-jwt-assertion";
2621
2134
 
@@ -2661,9 +2174,7 @@ class GcpIapProvider {
2661
2174
  this.authHandler = options.authHandler;
2662
2175
  this.signInResolver = options.signInResolver;
2663
2176
  this.tokenValidator = options.tokenValidator;
2664
- this.tokenIssuer = options.tokenIssuer;
2665
- this.catalogIdentityClient = options.catalogIdentityClient;
2666
- this.logger = options.logger;
2177
+ this.resolverContext = options.resolverContext;
2667
2178
  }
2668
2179
  async start() {
2669
2180
  }
@@ -2671,13 +2182,8 @@ class GcpIapProvider {
2671
2182
  }
2672
2183
  async refresh(req, res) {
2673
2184
  const result = await parseRequestToken(req.header(IAP_JWT_HEADER), this.tokenValidator);
2674
- const context = {
2675
- logger: this.logger,
2676
- catalogIdentityClient: this.catalogIdentityClient,
2677
- tokenIssuer: this.tokenIssuer
2678
- };
2679
- const { profile } = await this.authHandler(result, context);
2680
- const backstageIdentity = await this.signInResolver({ profile, result }, context);
2185
+ const { profile } = await this.authHandler(result, this.resolverContext);
2186
+ const backstageIdentity = await this.signInResolver({ profile, result }, this.resolverContext);
2681
2187
  const response = {
2682
2188
  providerInfo: { iapToken: result.iapToken },
2683
2189
  profile,
@@ -2686,27 +2192,42 @@ class GcpIapProvider {
2686
2192
  res.json(response);
2687
2193
  }
2688
2194
  }
2689
- function createGcpIapProvider(options) {
2690
- return ({ config, tokenIssuer, catalogApi, logger, tokenManager }) => {
2691
- var _a;
2692
- const audience = config.getString("audience");
2693
- const authHandler = (_a = options.authHandler) != null ? _a : defaultAuthHandler;
2694
- const signInResolver = options.signIn.resolver;
2695
- const tokenValidator = createTokenValidator(audience);
2696
- const catalogIdentityClient = new CatalogIdentityClient({
2697
- catalogApi,
2698
- tokenManager
2699
- });
2700
- return new GcpIapProvider({
2701
- authHandler,
2702
- signInResolver,
2703
- tokenValidator,
2704
- tokenIssuer,
2705
- catalogIdentityClient,
2706
- logger
2707
- });
2708
- };
2709
- }
2195
+ const gcpIap = createAuthProviderIntegration({
2196
+ create(options) {
2197
+ return ({ config, resolverContext }) => {
2198
+ var _a;
2199
+ const audience = config.getString("audience");
2200
+ const authHandler = (_a = options.authHandler) != null ? _a : defaultAuthHandler;
2201
+ const signInResolver = options.signIn.resolver;
2202
+ const tokenValidator = createTokenValidator(audience);
2203
+ return new GcpIapProvider({
2204
+ authHandler,
2205
+ signInResolver,
2206
+ tokenValidator,
2207
+ resolverContext
2208
+ });
2209
+ };
2210
+ }
2211
+ });
2212
+ const createGcpIapProvider = gcpIap.create;
2213
+
2214
+ const providers = Object.freeze({
2215
+ atlassian,
2216
+ auth0,
2217
+ awsAlb,
2218
+ bitbucket,
2219
+ gcpIap,
2220
+ github,
2221
+ gitlab,
2222
+ google,
2223
+ microsoft,
2224
+ oauth2,
2225
+ oauth2Proxy,
2226
+ oidc,
2227
+ okta,
2228
+ onelogin,
2229
+ saml
2230
+ });
2710
2231
 
2711
2232
  const factories = {
2712
2233
  google: createGoogleProvider(),
@@ -2994,6 +2515,149 @@ class KeyStores {
2994
2515
  }
2995
2516
  }
2996
2517
 
2518
+ class CatalogIdentityClient {
2519
+ constructor(options) {
2520
+ this.catalogApi = options.catalogApi;
2521
+ this.tokenManager = options.tokenManager;
2522
+ }
2523
+ async findUser(query) {
2524
+ const filter = {
2525
+ kind: "user"
2526
+ };
2527
+ for (const [key, value] of Object.entries(query.annotations)) {
2528
+ filter[`metadata.annotations.${key}`] = value;
2529
+ }
2530
+ const { token } = await this.tokenManager.getToken();
2531
+ const { items } = await this.catalogApi.getEntities({ filter }, { token });
2532
+ if (items.length !== 1) {
2533
+ if (items.length > 1) {
2534
+ throw new errors.ConflictError("User lookup resulted in multiple matches");
2535
+ } else {
2536
+ throw new errors.NotFoundError("User not found");
2537
+ }
2538
+ }
2539
+ return items[0];
2540
+ }
2541
+ async resolveCatalogMembership(query) {
2542
+ const { entityRefs, logger } = query;
2543
+ const resolvedEntityRefs = entityRefs.map((ref) => {
2544
+ try {
2545
+ const parsedRef = catalogModel.parseEntityRef(ref.toLocaleLowerCase("en-US"), {
2546
+ defaultKind: "user",
2547
+ defaultNamespace: "default"
2548
+ });
2549
+ return parsedRef;
2550
+ } catch {
2551
+ logger == null ? void 0 : logger.warn(`Failed to parse entityRef from ${ref}, ignoring`);
2552
+ return null;
2553
+ }
2554
+ }).filter((ref) => ref !== null);
2555
+ const filter = resolvedEntityRefs.map((ref) => ({
2556
+ kind: ref.kind,
2557
+ "metadata.namespace": ref.namespace,
2558
+ "metadata.name": ref.name
2559
+ }));
2560
+ const { token } = await this.tokenManager.getToken();
2561
+ const entities = await this.catalogApi.getEntities({ filter }, { token }).then((r) => r.items);
2562
+ if (entityRefs.length !== entities.length) {
2563
+ const foundEntityNames = entities.map(catalogModel.stringifyEntityRef);
2564
+ const missingEntityNames = resolvedEntityRefs.map(catalogModel.stringifyEntityRef).filter((s) => !foundEntityNames.includes(s));
2565
+ logger == null ? void 0 : logger.debug(`Entities not found for refs ${missingEntityNames.join()}`);
2566
+ }
2567
+ const memberOf = entities.flatMap((e) => {
2568
+ var _a, _b;
2569
+ return (_b = (_a = e.relations) == null ? void 0 : _a.filter((r) => r.type === catalogModel.RELATION_MEMBER_OF).map((r) => r.targetRef)) != null ? _b : [];
2570
+ });
2571
+ const newEntityRefs = [
2572
+ ...new Set(resolvedEntityRefs.map(catalogModel.stringifyEntityRef).concat(memberOf))
2573
+ ];
2574
+ logger == null ? void 0 : logger.debug(`Found catalog membership: ${newEntityRefs.join()}`);
2575
+ return newEntityRefs;
2576
+ }
2577
+ }
2578
+
2579
+ function getEntityClaims(entity) {
2580
+ var _a, _b;
2581
+ const userRef = catalogModel.stringifyEntityRef(entity);
2582
+ const membershipRefs = (_b = (_a = entity.relations) == null ? void 0 : _a.filter((r) => r.type === catalogModel.RELATION_MEMBER_OF && r.targetRef.startsWith("group:")).map((r) => r.targetRef)) != null ? _b : [];
2583
+ return {
2584
+ sub: userRef,
2585
+ ent: [userRef, ...membershipRefs]
2586
+ };
2587
+ }
2588
+
2589
+ function getDefaultOwnershipEntityRefs(entity) {
2590
+ var _a, _b;
2591
+ const membershipRefs = (_b = (_a = entity.relations) == null ? void 0 : _a.filter((r) => r.type === catalogModel.RELATION_MEMBER_OF && r.targetRef.startsWith("group:")).map((r) => r.targetRef)) != null ? _b : [];
2592
+ return Array.from(/* @__PURE__ */ new Set([catalogModel.stringifyEntityRef(entity), ...membershipRefs]));
2593
+ }
2594
+ class CatalogAuthResolverContext {
2595
+ constructor(logger, tokenIssuer, catalogIdentityClient, catalogApi, tokenManager) {
2596
+ this.logger = logger;
2597
+ this.tokenIssuer = tokenIssuer;
2598
+ this.catalogIdentityClient = catalogIdentityClient;
2599
+ this.catalogApi = catalogApi;
2600
+ this.tokenManager = tokenManager;
2601
+ }
2602
+ static create(options) {
2603
+ const catalogIdentityClient = new CatalogIdentityClient({
2604
+ catalogApi: options.catalogApi,
2605
+ tokenManager: options.tokenManager
2606
+ });
2607
+ return new CatalogAuthResolverContext(options.logger, options.tokenIssuer, catalogIdentityClient, options.catalogApi, options.tokenManager);
2608
+ }
2609
+ async issueToken(params) {
2610
+ const token = await this.tokenIssuer.issueToken(params);
2611
+ return { token };
2612
+ }
2613
+ async findCatalogUser(query) {
2614
+ let result = void 0;
2615
+ const { token } = await this.tokenManager.getToken();
2616
+ if ("entityRef" in query) {
2617
+ const entityRef = catalogModel.parseEntityRef(query.entityRef, {
2618
+ defaultKind: "User",
2619
+ defaultNamespace: catalogModel.DEFAULT_NAMESPACE
2620
+ });
2621
+ result = await this.catalogApi.getEntityByRef(entityRef, { token });
2622
+ } else if ("annotations" in query) {
2623
+ const filter = {
2624
+ kind: "user"
2625
+ };
2626
+ for (const [key, value] of Object.entries(query.annotations)) {
2627
+ filter[`metadata.annotations.${key}`] = value;
2628
+ }
2629
+ const res = await this.catalogApi.getEntities({ filter }, { token });
2630
+ result = res.items;
2631
+ } else if ("filter" in query) {
2632
+ const res = await this.catalogApi.getEntities({ filter: query.filter }, { token });
2633
+ result = res.items;
2634
+ } else {
2635
+ throw new errors.InputError("Invalid user lookup query");
2636
+ }
2637
+ if (Array.isArray(result)) {
2638
+ if (result.length > 1) {
2639
+ throw new errors.ConflictError("User lookup resulted in multiple matches");
2640
+ }
2641
+ result = result[0];
2642
+ }
2643
+ if (!result) {
2644
+ throw new errors.NotFoundError("User not found");
2645
+ }
2646
+ return { entity: result };
2647
+ }
2648
+ async signInWithCatalogUser(query) {
2649
+ const { entity } = await this.findCatalogUser(query);
2650
+ const ownershipRefs = getDefaultOwnershipEntityRefs(entity);
2651
+ const token = await this.tokenIssuer.issueToken({
2652
+ claims: {
2653
+ sub: catalogModel.stringifyEntityRef(entity),
2654
+ ent: ownershipRefs
2655
+ }
2656
+ });
2657
+ return { token };
2658
+ }
2659
+ }
2660
+
2997
2661
  async function createRouter(options) {
2998
2662
  const {
2999
2663
  logger,
@@ -3055,7 +2719,13 @@ async function createRouter(options) {
3055
2719
  tokenManager,
3056
2720
  tokenIssuer,
3057
2721
  discovery,
3058
- catalogApi
2722
+ catalogApi,
2723
+ resolverContext: CatalogAuthResolverContext.create({
2724
+ logger,
2725
+ catalogApi,
2726
+ tokenIssuer,
2727
+ tokenManager
2728
+ })
3059
2729
  });
3060
2730
  const r = Router__default["default"]();
3061
2731
  r.get("/start", provider.start.bind(provider));
@@ -3133,12 +2803,15 @@ exports.createSamlProvider = createSamlProvider;
3133
2803
  exports.defaultAuthProviderFactories = factories;
3134
2804
  exports.encodeState = encodeState;
3135
2805
  exports.ensuresXRequestedWith = ensuresXRequestedWith;
2806
+ exports.getDefaultOwnershipEntityRefs = getDefaultOwnershipEntityRefs;
3136
2807
  exports.getEntityClaims = getEntityClaims;
3137
2808
  exports.googleEmailSignInResolver = googleEmailSignInResolver;
3138
2809
  exports.microsoftEmailSignInResolver = microsoftEmailSignInResolver;
3139
2810
  exports.oktaEmailSignInResolver = oktaEmailSignInResolver;
3140
2811
  exports.postMessageResponse = postMessageResponse;
3141
2812
  exports.prepareBackstageIdentityResponse = prepareBackstageIdentityResponse;
2813
+ exports.providers = providers;
3142
2814
  exports.readState = readState;
2815
+ exports.samlNameIdEntityNameSignInResolver = samlNameIdEntityNameSignInResolver;
3143
2816
  exports.verifyNonce = verifyNonce;
3144
2817
  //# sourceMappingURL=index.cjs.js.map