@backstage/plugin-auth-backend 0.12.3 → 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
@@ -10,7 +10,6 @@ var errors = require('@backstage/errors');
10
10
  var pickBy = require('lodash/pickBy');
11
11
  var crypto = require('crypto');
12
12
  var url = require('url');
13
- var catalogModel = require('@backstage/catalog-model');
14
13
  var jwtDecoder = require('jwt-decode');
15
14
  var fetch = require('node-fetch');
16
15
  var NodeCache = require('node-cache');
@@ -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');
@@ -255,18 +255,11 @@ function parseJwtPayload(token) {
255
255
  }
256
256
  function prepareBackstageIdentityResponse(result) {
257
257
  const { sub, ent } = parseJwtPayload(result.token);
258
- const userEntityRef = catalogModel.stringifyEntityRef(catalogModel.parseEntityRef(sub, {
259
- defaultKind: "user",
260
- defaultNamespace: catalogModel.DEFAULT_NAMESPACE
261
- }));
262
258
  return {
263
- ...{
264
- idToken: result.token,
265
- ...result
266
- },
259
+ ...result,
267
260
  identity: {
268
261
  type: "user",
269
- userEntityRef,
262
+ userEntityRef: sub,
270
263
  ownershipEntityRefs: ent != null ? ent : []
271
264
  }
272
265
  };
@@ -429,17 +422,10 @@ class OAuthAdapter {
429
422
  if (!identity) {
430
423
  return void 0;
431
424
  }
432
- if (identity.token) {
433
- return prepareBackstageIdentityResponse(identity);
425
+ if (!identity.token) {
426
+ throw new errors.InputError(`Identity response must return a token`);
434
427
  }
435
- const userEntityRef = catalogModel.stringifyEntityRef(catalogModel.parseEntityRef(identity.id, {
436
- defaultKind: "user",
437
- defaultNamespace: catalogModel.DEFAULT_NAMESPACE
438
- }));
439
- const token = await this.options.tokenIssuer.issueToken({
440
- claims: { sub: userEntityRef }
441
- });
442
- return prepareBackstageIdentityResponse({ ...identity, token });
428
+ return prepareBackstageIdentityResponse(identity);
443
429
  }
444
430
  }
445
431
 
@@ -556,75 +542,12 @@ const executeFetchUserProfileStrategy = async (providerStrategy, accessToken) =>
556
542
  });
557
543
  };
558
544
 
559
- class CatalogIdentityClient {
560
- constructor(options) {
561
- this.catalogApi = options.catalogApi;
562
- this.tokenManager = options.tokenManager;
563
- }
564
- async findUser(query) {
565
- const filter = {
566
- kind: "user"
567
- };
568
- for (const [key, value] of Object.entries(query.annotations)) {
569
- filter[`metadata.annotations.${key}`] = value;
570
- }
571
- const { token } = await this.tokenManager.getToken();
572
- const { items } = await this.catalogApi.getEntities({ filter }, { token });
573
- if (items.length !== 1) {
574
- if (items.length > 1) {
575
- throw new errors.ConflictError("User lookup resulted in multiple matches");
576
- } else {
577
- throw new errors.NotFoundError("User not found");
578
- }
579
- }
580
- return items[0];
581
- }
582
- async resolveCatalogMembership(query) {
583
- const { entityRefs, logger } = query;
584
- const resolvedEntityRefs = entityRefs.map((ref) => {
585
- try {
586
- const parsedRef = catalogModel.parseEntityRef(ref.toLocaleLowerCase("en-US"), {
587
- defaultKind: "user",
588
- defaultNamespace: "default"
589
- });
590
- return parsedRef;
591
- } catch {
592
- logger == null ? void 0 : logger.warn(`Failed to parse entityRef from ${ref}, ignoring`);
593
- return null;
594
- }
595
- }).filter((ref) => ref !== null);
596
- const filter = resolvedEntityRefs.map((ref) => ({
597
- kind: ref.kind,
598
- "metadata.namespace": ref.namespace,
599
- "metadata.name": ref.name
600
- }));
601
- const { token } = await this.tokenManager.getToken();
602
- const entities = await this.catalogApi.getEntities({ filter }, { token }).then((r) => r.items);
603
- if (entityRefs.length !== entities.length) {
604
- const foundEntityNames = entities.map(catalogModel.stringifyEntityRef);
605
- const missingEntityNames = resolvedEntityRefs.map(catalogModel.stringifyEntityRef).filter((s) => !foundEntityNames.includes(s));
606
- logger == null ? void 0 : logger.debug(`Entities not found for refs ${missingEntityNames.join()}`);
607
- }
608
- const memberOf = entities.flatMap((e) => {
609
- var _a, _b;
610
- return (_b = (_a = e.relations) == null ? void 0 : _a.filter((r) => r.type === catalogModel.RELATION_MEMBER_OF).map((r) => r.targetRef)) != null ? _b : [];
611
- });
612
- const newEntityRefs = [
613
- ...new Set(resolvedEntityRefs.map(catalogModel.stringifyEntityRef).concat(memberOf))
614
- ];
615
- logger == null ? void 0 : logger.debug(`Found catalog membership: ${newEntityRefs.join()}`);
616
- return newEntityRefs;
617
- }
618
- }
619
-
620
- function getEntityClaims(entity) {
621
- var _a, _b;
622
- const userRef = catalogModel.stringifyEntityRef(entity);
623
- 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 : [];
624
- return {
625
- sub: userRef,
626
- ent: [userRef, ...membershipRefs]
627
- };
545
+ function createAuthProviderIntegration(config) {
546
+ var _a;
547
+ return Object.freeze({
548
+ ...config,
549
+ resolvers: Object.freeze((_a = config.resolvers) != null ? _a : {})
550
+ });
628
551
  }
629
552
 
630
553
  const atlassianDefaultAuthHandler = async ({
@@ -635,9 +558,7 @@ const atlassianDefaultAuthHandler = async ({
635
558
  });
636
559
  class AtlassianAuthProvider {
637
560
  constructor(options) {
638
- this.catalogIdentityClient = options.catalogIdentityClient;
639
- this.logger = options.logger;
640
- this.tokenIssuer = options.tokenIssuer;
561
+ this.resolverContext = options.resolverContext;
641
562
  this.authHandler = options.authHandler;
642
563
  this.signInResolver = options.signInResolver;
643
564
  this._strategy = new AtlassianStrategy({
@@ -667,12 +588,7 @@ class AtlassianAuthProvider {
667
588
  };
668
589
  }
669
590
  async handleResult(result) {
670
- const context = {
671
- logger: this.logger,
672
- catalogIdentityClient: this.catalogIdentityClient,
673
- tokenIssuer: this.tokenIssuer
674
- };
675
- const { profile } = await this.authHandler(result, context);
591
+ const { profile } = await this.authHandler(result, this.resolverContext);
676
592
  const response = {
677
593
  providerInfo: {
678
594
  idToken: result.params.id_token,
@@ -686,7 +602,7 @@ class AtlassianAuthProvider {
686
602
  response.backstageIdentity = await this.signInResolver({
687
603
  result,
688
604
  profile
689
- }, context);
605
+ }, this.resolverContext);
690
606
  }
691
607
  return response;
692
608
  }
@@ -703,45 +619,33 @@ class AtlassianAuthProvider {
703
619
  };
704
620
  }
705
621
  }
706
- const createAtlassianProvider = (options) => {
707
- return ({
708
- providerId,
709
- globalConfig,
710
- config,
711
- tokenIssuer,
712
- tokenManager,
713
- catalogApi,
714
- logger
715
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
716
- var _a, _b;
717
- const clientId = envConfig.getString("clientId");
718
- const clientSecret = envConfig.getString("clientSecret");
719
- const scopes = envConfig.getString("scopes");
720
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
721
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
722
- const catalogIdentityClient = new CatalogIdentityClient({
723
- catalogApi,
724
- tokenManager
725
- });
726
- const authHandler = (_a = options == null ? void 0 : options.authHandler) != null ? _a : atlassianDefaultAuthHandler;
727
- const provider = new AtlassianAuthProvider({
728
- clientId,
729
- clientSecret,
730
- scopes,
731
- callbackUrl,
732
- authHandler,
733
- signInResolver: (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver,
734
- catalogIdentityClient,
735
- logger,
736
- tokenIssuer
737
- });
738
- return OAuthAdapter.fromConfig(globalConfig, provider, {
739
- providerId,
740
- tokenIssuer,
741
- 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
+ });
742
645
  });
743
- });
744
- };
646
+ }
647
+ });
648
+ const createAtlassianProvider = atlassian.create;
745
649
 
746
650
  class Auth0Strategy extends OAuth2Strategy__default["default"] {
747
651
  constructor(options, verify) {
@@ -760,9 +664,7 @@ class Auth0AuthProvider {
760
664
  constructor(options) {
761
665
  this.signInResolver = options.signInResolver;
762
666
  this.authHandler = options.authHandler;
763
- this.tokenIssuer = options.tokenIssuer;
764
- this.catalogIdentityClient = options.catalogIdentityClient;
765
- this.logger = options.logger;
667
+ this.resolverContext = options.resolverContext;
766
668
  this._strategy = new Auth0Strategy({
767
669
  clientID: options.clientId,
768
670
  clientSecret: options.clientSecret,
@@ -808,12 +710,7 @@ class Auth0AuthProvider {
808
710
  };
809
711
  }
810
712
  async handleResult(result) {
811
- const context = {
812
- logger: this.logger,
813
- catalogIdentityClient: this.catalogIdentityClient,
814
- tokenIssuer: this.tokenIssuer
815
- };
816
- const { profile } = await this.authHandler(result, context);
713
+ const { profile } = await this.authHandler(result, this.resolverContext);
817
714
  const response = {
818
715
  providerInfo: {
819
716
  idToken: result.params.id_token,
@@ -827,62 +724,42 @@ class Auth0AuthProvider {
827
724
  response.backstageIdentity = await this.signInResolver({
828
725
  result,
829
726
  profile
830
- }, context);
727
+ }, this.resolverContext);
831
728
  }
832
729
  return response;
833
730
  }
834
731
  }
835
- const defaultSignInResolver$1 = async (info) => {
836
- const { profile } = info;
837
- if (!profile.email) {
838
- throw new Error("Profile does not contain an email");
839
- }
840
- const id = profile.email.split("@")[0];
841
- return { id, token: "" };
842
- };
843
- const createAuth0Provider = (options) => {
844
- return ({
845
- providerId,
846
- globalConfig,
847
- config,
848
- tokenIssuer,
849
- tokenManager,
850
- catalogApi,
851
- logger
852
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
853
- var _a, _b;
854
- const clientId = envConfig.getString("clientId");
855
- const clientSecret = envConfig.getString("clientSecret");
856
- const domain = envConfig.getString("domain");
857
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
858
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
859
- const catalogIdentityClient = new CatalogIdentityClient({
860
- catalogApi,
861
- tokenManager
862
- });
863
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
864
- profile: makeProfileInfo(fullProfile, params.id_token)
865
- });
866
- const signInResolver = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : defaultSignInResolver$1;
867
- const provider = new Auth0AuthProvider({
868
- clientId,
869
- clientSecret,
870
- callbackUrl,
871
- domain,
872
- authHandler,
873
- signInResolver,
874
- tokenIssuer,
875
- catalogIdentityClient,
876
- logger
877
- });
878
- return OAuthAdapter.fromConfig(globalConfig, provider, {
879
- disableRefresh: true,
880
- providerId,
881
- tokenIssuer,
882
- 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
+ });
883
759
  });
884
- });
885
- };
760
+ }
761
+ });
762
+ const createAuth0Provider = auth0.create;
886
763
 
887
764
  const ALB_JWT_HEADER = "x-amzn-oidc-data";
888
765
  const ALB_ACCESS_TOKEN_HEADER = "x-amzn-oidc-accesstoken";
@@ -896,9 +773,7 @@ class AwsAlbAuthProvider {
896
773
  this.issuer = options.issuer;
897
774
  this.authHandler = options.authHandler;
898
775
  this.signInResolver = options.signInResolver;
899
- this.tokenIssuer = options.tokenIssuer;
900
- this.catalogIdentityClient = options.catalogIdentityClient;
901
- this.logger = options.logger;
776
+ this.resolverContext = options.resolverContext;
902
777
  this.keyCache = new NodeCache__default["default"]({ stdTTL: 3600 });
903
778
  }
904
779
  frameHandler() {
@@ -910,9 +785,7 @@ class AwsAlbAuthProvider {
910
785
  const response = await this.handleResult(result);
911
786
  res.json(response);
912
787
  } catch (e) {
913
- this.logger.error("Exception occurred during AWS ALB token refresh", e);
914
- res.status(401);
915
- res.end();
788
+ throw new errors.AuthenticationError("Exception occurred during AWS ALB token refresh", e);
916
789
  }
917
790
  }
918
791
  start() {
@@ -956,16 +829,11 @@ class AwsAlbAuthProvider {
956
829
  }
957
830
  }
958
831
  async handleResult(result) {
959
- const context = {
960
- tokenIssuer: this.tokenIssuer,
961
- catalogIdentityClient: this.catalogIdentityClient,
962
- logger: this.logger
963
- };
964
- const { profile } = await this.authHandler(result, context);
832
+ const { profile } = await this.authHandler(result, this.resolverContext);
965
833
  const backstageIdentity = await this.signInResolver({
966
834
  result,
967
835
  profile
968
- }, context);
836
+ }, this.resolverContext);
969
837
  return {
970
838
  providerInfo: {
971
839
  accessToken: result.accessToken,
@@ -980,46 +848,40 @@ class AwsAlbAuthProvider {
980
848
  if (optionalCacheKey) {
981
849
  return crypto__namespace.createPublicKey(optionalCacheKey);
982
850
  }
983
- 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());
984
852
  const keyValue = crypto__namespace.createPublicKey(keyText);
985
853
  this.keyCache.set(keyId, keyValue.export({ format: "pem", type: "spki" }));
986
854
  return keyValue;
987
855
  }
988
856
  }
989
- const createAwsAlbProvider = (options) => {
990
- return ({ config, tokenIssuer, catalogApi, logger, tokenManager }) => {
991
- const region = config.getString("region");
992
- const issuer = config.getOptionalString("iss");
993
- if ((options == null ? void 0 : options.signIn.resolver) === void 0) {
994
- throw new Error("SignInResolver is required to use this authentication provider");
995
- }
996
- const catalogIdentityClient = new CatalogIdentityClient({
997
- catalogApi,
998
- tokenManager
999
- });
1000
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
1001
- profile: makeProfileInfo(fullProfile)
1002
- });
1003
- const signInResolver = options == null ? void 0 : options.signIn.resolver;
1004
- return new AwsAlbAuthProvider({
1005
- region,
1006
- issuer,
1007
- signInResolver,
1008
- authHandler,
1009
- tokenIssuer,
1010
- catalogIdentityClient,
1011
- logger
1012
- });
1013
- };
1014
- };
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;
1015
879
 
1016
880
  class BitbucketAuthProvider {
1017
881
  constructor(options) {
1018
882
  this.signInResolver = options.signInResolver;
1019
883
  this.authHandler = options.authHandler;
1020
- this.tokenIssuer = options.tokenIssuer;
1021
- this.catalogIdentityClient = options.catalogIdentityClient;
1022
- this.logger = options.logger;
884
+ this.resolverContext = options.resolverContext;
1023
885
  this._strategy = new passportBitbucketOauth2.Strategy({
1024
886
  clientID: options.clientId,
1025
887
  clientSecret: options.clientSecret,
@@ -1065,12 +927,7 @@ class BitbucketAuthProvider {
1065
927
  }
1066
928
  async handleResult(result) {
1067
929
  result.fullProfile.avatarUrl = result.fullProfile._json.links.avatar.href;
1068
- const context = {
1069
- logger: this.logger,
1070
- catalogIdentityClient: this.catalogIdentityClient,
1071
- tokenIssuer: this.tokenIssuer
1072
- };
1073
- const { profile } = await this.authHandler(result, context);
930
+ const { profile } = await this.authHandler(result, this.resolverContext);
1074
931
  const response = {
1075
932
  providerInfo: {
1076
933
  idToken: result.params.id_token,
@@ -1084,79 +941,69 @@ class BitbucketAuthProvider {
1084
941
  response.backstageIdentity = await this.signInResolver({
1085
942
  result,
1086
943
  profile
1087
- }, context);
944
+ }, this.resolverContext);
1088
945
  }
1089
946
  return response;
1090
947
  }
1091
948
  }
1092
- const bitbucketUsernameSignInResolver = async (info, ctx) => {
1093
- const { result } = info;
1094
- if (!result.fullProfile.username) {
1095
- throw new Error("Bitbucket profile contained no Username");
1096
- }
1097
- const entity = await ctx.catalogIdentityClient.findUser({
1098
- annotations: {
1099
- "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
+ };
1100
1001
  }
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 bitbucketUserIdSignInResolver = async (info, ctx) => {
1107
- const { result } = info;
1108
- if (!result.fullProfile.id) {
1109
- throw new Error("Bitbucket profile contained no User ID");
1110
1002
  }
1111
- const entity = await ctx.catalogIdentityClient.findUser({
1112
- annotations: {
1113
- "bitbucket.org/user-id": result.fullProfile.id
1114
- }
1115
- });
1116
- const claims = getEntityClaims(entity);
1117
- const token = await ctx.tokenIssuer.issueToken({ claims });
1118
- return { id: entity.metadata.name, entity, token };
1119
- };
1120
- const createBitbucketProvider = (options) => {
1121
- return ({
1122
- providerId,
1123
- globalConfig,
1124
- config,
1125
- tokenIssuer,
1126
- tokenManager,
1127
- catalogApi,
1128
- logger
1129
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1130
- var _a;
1131
- const clientId = envConfig.getString("clientId");
1132
- const clientSecret = envConfig.getString("clientSecret");
1133
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1134
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1135
- const catalogIdentityClient = new CatalogIdentityClient({
1136
- catalogApi,
1137
- tokenManager
1138
- });
1139
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1140
- profile: makeProfileInfo(fullProfile, params.id_token)
1141
- });
1142
- const provider = new BitbucketAuthProvider({
1143
- clientId,
1144
- clientSecret,
1145
- callbackUrl,
1146
- signInResolver: (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver,
1147
- authHandler,
1148
- tokenIssuer,
1149
- catalogIdentityClient,
1150
- logger
1151
- });
1152
- return OAuthAdapter.fromConfig(globalConfig, provider, {
1153
- disableRefresh: false,
1154
- providerId,
1155
- tokenIssuer,
1156
- callbackUrl
1157
- });
1158
- });
1159
- };
1003
+ });
1004
+ const createBitbucketProvider = bitbucket.create;
1005
+ const bitbucketUsernameSignInResolver = bitbucket.resolvers.usernameMatchingUserEntityAnnotation();
1006
+ const bitbucketUserIdSignInResolver = bitbucket.resolvers.userIdMatchingUserEntityAnnotation();
1160
1007
 
1161
1008
  const ACCESS_TOKEN_PREFIX = "access-token.";
1162
1009
  const BACKSTAGE_SESSION_EXPIRATION = 3600;
@@ -1165,9 +1012,7 @@ class GithubAuthProvider {
1165
1012
  this.signInResolver = options.signInResolver;
1166
1013
  this.authHandler = options.authHandler;
1167
1014
  this.stateEncoder = options.stateEncoder;
1168
- this.tokenIssuer = options.tokenIssuer;
1169
- this.catalogIdentityClient = options.catalogIdentityClient;
1170
- this.logger = options.logger;
1015
+ this.resolverContext = options.resolverContext;
1171
1016
  this._strategy = new passportGithub2.Strategy({
1172
1017
  clientID: options.clientId,
1173
1018
  clientSecret: options.clientSecret,
@@ -1227,12 +1072,7 @@ class GithubAuthProvider {
1227
1072
  };
1228
1073
  }
1229
1074
  async handleResult(result) {
1230
- const context = {
1231
- logger: this.logger,
1232
- catalogIdentityClient: this.catalogIdentityClient,
1233
- tokenIssuer: this.tokenIssuer
1234
- };
1235
- const { profile } = await this.authHandler(result, context);
1075
+ const { profile } = await this.authHandler(result, this.resolverContext);
1236
1076
  const expiresInStr = result.params.expires_in;
1237
1077
  let expiresInSeconds = expiresInStr === void 0 ? void 0 : Number(expiresInStr);
1238
1078
  let backstageIdentity = void 0;
@@ -1240,7 +1080,7 @@ class GithubAuthProvider {
1240
1080
  backstageIdentity = await this.signInResolver({
1241
1081
  result,
1242
1082
  profile
1243
- }, context);
1083
+ }, this.resolverContext);
1244
1084
  if (expiresInSeconds) {
1245
1085
  expiresInSeconds = Math.min(expiresInSeconds, BACKSTAGE_SESSION_EXPIRATION);
1246
1086
  } else {
@@ -1258,99 +1098,58 @@ class GithubAuthProvider {
1258
1098
  };
1259
1099
  }
1260
1100
  }
1261
- const githubDefaultSignInResolver = async (info, ctx) => {
1262
- const { fullProfile } = info.result;
1263
- const userId = fullProfile.username || fullProfile.id;
1264
- const entityRef = catalogModel.stringifyEntityRef({
1265
- kind: "User",
1266
- namespace: catalogModel.DEFAULT_NAMESPACE,
1267
- name: userId
1268
- });
1269
- const token = await ctx.tokenIssuer.issueToken({
1270
- claims: {
1271
- sub: entityRef,
1272
- ent: [entityRef]
1273
- }
1274
- });
1275
- return { id: userId, token };
1276
- };
1277
- const createGithubProvider = (options) => {
1278
- return ({
1279
- providerId,
1280
- globalConfig,
1281
- config,
1282
- tokenIssuer,
1283
- tokenManager,
1284
- catalogApi,
1285
- logger
1286
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1287
- var _a, _b, _c;
1288
- const clientId = envConfig.getString("clientId");
1289
- const clientSecret = envConfig.getString("clientSecret");
1290
- const enterpriseInstanceUrl = envConfig.getOptionalString("enterpriseInstanceUrl");
1291
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1292
- const authorizationUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/login/oauth/authorize` : void 0;
1293
- const tokenUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/login/oauth/access_token` : void 0;
1294
- const userProfileUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/api/v3/user` : void 0;
1295
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1296
- const catalogIdentityClient = new CatalogIdentityClient({
1297
- catalogApi,
1298
- tokenManager
1299
- });
1300
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
1301
- profile: makeProfileInfo(fullProfile)
1302
- });
1303
- const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : githubDefaultSignInResolver;
1304
- const signInResolver = (info) => signInResolverFn(info, {
1305
- catalogIdentityClient,
1306
- tokenIssuer,
1307
- logger
1308
- });
1309
- const stateEncoder = (_c = options == null ? void 0 : options.stateEncoder) != null ? _c : async (req) => {
1310
- return { encodedState: encodeState(req.state) };
1311
- };
1312
- const provider = new GithubAuthProvider({
1313
- clientId,
1314
- clientSecret,
1315
- callbackUrl,
1316
- tokenUrl,
1317
- userProfileUrl,
1318
- authorizationUrl,
1319
- signInResolver,
1320
- authHandler,
1321
- tokenIssuer,
1322
- catalogIdentityClient,
1323
- stateEncoder,
1324
- logger
1325
- });
1326
- return OAuthAdapter.fromConfig(globalConfig, provider, {
1327
- persistScopes: true,
1328
- providerId,
1329
- tokenIssuer,
1330
- 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
+ });
1331
1136
  });
1332
- });
1333
- };
1334
-
1335
- const gitlabDefaultSignInResolver = async (info, ctx) => {
1336
- const { profile, result } = info;
1337
- let id = result.fullProfile.id;
1338
- if (profile.email) {
1339
- id = profile.email.split("@")[0];
1340
- }
1341
- const entityRef = catalogModel.stringifyEntityRef({
1342
- kind: "User",
1343
- namespace: catalogModel.DEFAULT_NAMESPACE,
1344
- name: id
1345
- });
1346
- const token = await ctx.tokenIssuer.issueToken({
1347
- claims: {
1348
- sub: entityRef,
1349
- 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
+ };
1350
1148
  }
1351
- });
1352
- return { id, token };
1353
- };
1149
+ }
1150
+ });
1151
+ const createGithubProvider = github.create;
1152
+
1354
1153
  const gitlabDefaultAuthHandler = async ({
1355
1154
  fullProfile,
1356
1155
  params
@@ -1359,9 +1158,7 @@ const gitlabDefaultAuthHandler = async ({
1359
1158
  });
1360
1159
  class GitlabAuthProvider {
1361
1160
  constructor(options) {
1362
- this.catalogIdentityClient = options.catalogIdentityClient;
1363
- this.logger = options.logger;
1364
- this.tokenIssuer = options.tokenIssuer;
1161
+ this.resolverContext = options.resolverContext;
1365
1162
  this.authHandler = options.authHandler;
1366
1163
  this.signInResolver = options.signInResolver;
1367
1164
  this._strategy = new passportGitlab2.Strategy({
@@ -1401,12 +1198,7 @@ class GitlabAuthProvider {
1401
1198
  };
1402
1199
  }
1403
1200
  async handleResult(result) {
1404
- const context = {
1405
- logger: this.logger,
1406
- catalogIdentityClient: this.catalogIdentityClient,
1407
- tokenIssuer: this.tokenIssuer
1408
- };
1409
- const { profile } = await this.authHandler(result, context);
1201
+ const { profile } = await this.authHandler(result, this.resolverContext);
1410
1202
  const response = {
1411
1203
  providerInfo: {
1412
1204
  idToken: result.params.id_token,
@@ -1420,67 +1212,58 @@ class GitlabAuthProvider {
1420
1212
  response.backstageIdentity = await this.signInResolver({
1421
1213
  result,
1422
1214
  profile
1423
- }, context);
1215
+ }, this.resolverContext);
1424
1216
  }
1425
1217
  return response;
1426
1218
  }
1427
1219
  }
1428
- const createGitlabProvider = (options) => {
1429
- return ({
1430
- providerId,
1431
- globalConfig,
1432
- config,
1433
- tokenIssuer,
1434
- tokenManager,
1435
- catalogApi,
1436
- logger
1437
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1438
- var _a, _b, _c;
1439
- const clientId = envConfig.getString("clientId");
1440
- const clientSecret = envConfig.getString("clientSecret");
1441
- const audience = envConfig.getOptionalString("audience");
1442
- const baseUrl = audience || "https://gitlab.com";
1443
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1444
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1445
- const catalogIdentityClient = new CatalogIdentityClient({
1446
- catalogApi,
1447
- tokenManager
1448
- });
1449
- const authHandler = (_a = options == null ? void 0 : options.authHandler) != null ? _a : gitlabDefaultAuthHandler;
1450
- const signInResolverFn = (_c = (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver) != null ? _c : gitlabDefaultSignInResolver;
1451
- const signInResolver = (info) => signInResolverFn(info, {
1452
- catalogIdentityClient,
1453
- tokenIssuer,
1454
- logger
1455
- });
1456
- const provider = new GitlabAuthProvider({
1457
- clientId,
1458
- clientSecret,
1459
- callbackUrl,
1460
- baseUrl,
1461
- authHandler,
1462
- signInResolver,
1463
- catalogIdentityClient,
1464
- logger,
1465
- tokenIssuer
1466
- });
1467
- return OAuthAdapter.fromConfig(globalConfig, provider, {
1468
- disableRefresh: false,
1469
- providerId,
1470
- tokenIssuer,
1471
- 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
+ });
1472
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 }
1473
1258
  });
1474
1259
  };
1475
1260
 
1476
1261
  class GoogleAuthProvider {
1477
1262
  constructor(options) {
1478
- this.signInResolver = options.signInResolver;
1479
1263
  this.authHandler = options.authHandler;
1480
- this.tokenIssuer = options.tokenIssuer;
1481
- this.catalogIdentityClient = options.catalogIdentityClient;
1482
- this.logger = options.logger;
1483
- this._strategy = new passportGoogleOauth20.Strategy({
1264
+ this.signInResolver = options.signInResolver;
1265
+ this.resolverContext = options.resolverContext;
1266
+ this.strategy = new passportGoogleOauth20.Strategy({
1484
1267
  clientID: options.clientId,
1485
1268
  clientSecret: options.clientSecret,
1486
1269
  callbackURL: options.callbackUrl,
@@ -1497,7 +1280,7 @@ class GoogleAuthProvider {
1497
1280
  });
1498
1281
  }
1499
1282
  async start(req) {
1500
- return await executeRedirectStrategy(req, this._strategy, {
1283
+ return await executeRedirectStrategy(req, this.strategy, {
1501
1284
  accessType: "offline",
1502
1285
  prompt: "consent",
1503
1286
  scope: req.scope,
@@ -1505,15 +1288,15 @@ class GoogleAuthProvider {
1505
1288
  });
1506
1289
  }
1507
1290
  async handler(req) {
1508
- const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
1291
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this.strategy);
1509
1292
  return {
1510
1293
  response: await this.handleResult(result),
1511
1294
  refreshToken: privateInfo.refreshToken
1512
1295
  };
1513
1296
  }
1514
1297
  async refresh(req) {
1515
- const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1516
- 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);
1517
1300
  return {
1518
1301
  response: await this.handleResult({
1519
1302
  fullProfile,
@@ -1524,12 +1307,7 @@ class GoogleAuthProvider {
1524
1307
  };
1525
1308
  }
1526
1309
  async handleResult(result) {
1527
- const context = {
1528
- logger: this.logger,
1529
- catalogIdentityClient: this.catalogIdentityClient,
1530
- tokenIssuer: this.tokenIssuer
1531
- };
1532
- const { profile } = await this.authHandler(result, context);
1310
+ const { profile } = await this.authHandler(result, this.resolverContext);
1533
1311
  const response = {
1534
1312
  providerInfo: {
1535
1313
  idToken: result.params.id_token,
@@ -1543,109 +1321,63 @@ class GoogleAuthProvider {
1543
1321
  response.backstageIdentity = await this.signInResolver({
1544
1322
  result,
1545
1323
  profile
1546
- }, context);
1324
+ }, this.resolverContext);
1547
1325
  }
1548
1326
  return response;
1549
1327
  }
1550
1328
  }
1551
- const googleEmailSignInResolver = async (info, ctx) => {
1552
- const { profile } = info;
1553
- if (!profile.email) {
1554
- throw new Error("Google profile contained no email");
1555
- }
1556
- const entity = await ctx.catalogIdentityClient.findUser({
1557
- annotations: {
1558
- "google.com/email": profile.email
1559
- }
1560
- });
1561
- const claims = getEntityClaims(entity);
1562
- const token = await ctx.tokenIssuer.issueToken({ claims });
1563
- return { id: entity.metadata.name, entity, token };
1564
- };
1565
- const googleDefaultSignInResolver = async (info, ctx) => {
1566
- const { profile } = info;
1567
- if (!profile.email) {
1568
- throw new Error("Google profile contained no email");
1569
- }
1570
- let userId;
1571
- try {
1572
- const entity = await ctx.catalogIdentityClient.findUser({
1573
- annotations: {
1574
- "google.com/email": profile.email
1575
- }
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
+ });
1576
1353
  });
1577
- userId = entity.metadata.name;
1578
- } catch (error) {
1579
- 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`);
1580
- userId = profile.email.split("@")[0];
1581
- }
1582
- const entityRef = catalogModel.stringifyEntityRef({
1583
- kind: "User",
1584
- namespace: catalogModel.DEFAULT_NAMESPACE,
1585
- name: userId
1586
- });
1587
- const token = await ctx.tokenIssuer.issueToken({
1588
- claims: {
1589
- sub: entityRef,
1590
- 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
+ };
1591
1369
  }
1592
- });
1593
- return { id: userId, token };
1594
- };
1595
- const createGoogleProvider = (options) => {
1596
- return ({
1597
- providerId,
1598
- globalConfig,
1599
- config,
1600
- tokenIssuer,
1601
- tokenManager,
1602
- catalogApi,
1603
- logger
1604
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1605
- var _a, _b;
1606
- const clientId = envConfig.getString("clientId");
1607
- const clientSecret = envConfig.getString("clientSecret");
1608
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1609
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1610
- const catalogIdentityClient = new CatalogIdentityClient({
1611
- catalogApi,
1612
- tokenManager
1613
- });
1614
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1615
- profile: makeProfileInfo(fullProfile, params.id_token)
1616
- });
1617
- const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : googleDefaultSignInResolver;
1618
- const signInResolver = (info) => signInResolverFn(info, {
1619
- catalogIdentityClient,
1620
- tokenIssuer,
1621
- logger
1622
- });
1623
- const provider = new GoogleAuthProvider({
1624
- clientId,
1625
- clientSecret,
1626
- callbackUrl,
1627
- signInResolver,
1628
- authHandler,
1629
- tokenIssuer,
1630
- catalogIdentityClient,
1631
- logger
1632
- });
1633
- return OAuthAdapter.fromConfig(globalConfig, provider, {
1634
- disableRefresh: false,
1635
- providerId,
1636
- tokenIssuer,
1637
- callbackUrl
1638
- });
1639
- });
1640
- };
1370
+ }
1371
+ });
1372
+ const createGoogleProvider = google.create;
1373
+ const googleEmailSignInResolver = google.resolvers.emailMatchingUserEntityAnnotation();
1641
1374
 
1642
1375
  class MicrosoftAuthProvider {
1643
1376
  constructor(options) {
1644
1377
  this.signInResolver = options.signInResolver;
1645
1378
  this.authHandler = options.authHandler;
1646
- this.tokenIssuer = options.tokenIssuer;
1647
1379
  this.logger = options.logger;
1648
- this.catalogIdentityClient = options.catalogIdentityClient;
1380
+ this.resolverContext = options.resolverContext;
1649
1381
  this._strategy = new passportMicrosoft.Strategy({
1650
1382
  clientID: options.clientId,
1651
1383
  clientSecret: options.clientSecret,
@@ -1685,12 +1417,7 @@ class MicrosoftAuthProvider {
1685
1417
  async handleResult(result) {
1686
1418
  const photo = await this.getUserPhoto(result.accessToken);
1687
1419
  result.fullProfile.photos = photo ? [{ value: photo }] : void 0;
1688
- const context = {
1689
- logger: this.logger,
1690
- catalogIdentityClient: this.catalogIdentityClient,
1691
- tokenIssuer: this.tokenIssuer
1692
- };
1693
- const { profile } = await this.authHandler(result, context);
1420
+ const { profile } = await this.authHandler(result, this.resolverContext);
1694
1421
  const response = {
1695
1422
  providerInfo: {
1696
1423
  idToken: result.params.id_token,
@@ -1704,118 +1431,81 @@ class MicrosoftAuthProvider {
1704
1431
  response.backstageIdentity = await this.signInResolver({
1705
1432
  result,
1706
1433
  profile
1707
- }, context);
1434
+ }, this.resolverContext);
1708
1435
  }
1709
1436
  return response;
1710
1437
  }
1711
- getUserPhoto(accessToken) {
1712
- return new Promise((resolve) => {
1713
- 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", {
1714
1441
  headers: {
1715
1442
  Authorization: `Bearer ${accessToken}`
1716
1443
  }
1717
- }).then((response) => response.arrayBuffer()).then((arrayBuffer) => {
1718
- const imageUrl = `data:image/jpeg;base64,${Buffer.from(arrayBuffer).toString("base64")}`;
1719
- resolve(imageUrl);
1720
- }).catch((error) => {
1721
- this.logger.warn(`Could not retrieve user profile photo from Microsoft Graph API: ${error}`);
1722
- resolve(void 0);
1723
1444
  });
1724
- });
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;
1450
+ }
1725
1451
  }
1726
1452
  }
1727
- const microsoftEmailSignInResolver = async (info, ctx) => {
1728
- const { profile } = info;
1729
- if (!profile.email) {
1730
- throw new Error("Microsoft profile contained no email");
1731
- }
1732
- const entity = await ctx.catalogIdentityClient.findUser({
1733
- annotations: {
1734
- "microsoft.com/email": profile.email
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
+ });
1483
+ });
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
+ };
1735
1498
  }
1736
- });
1737
- const claims = getEntityClaims(entity);
1738
- const token = await ctx.tokenIssuer.issueToken({ claims });
1739
- return { id: entity.metadata.name, entity, token };
1740
- };
1741
- const microsoftDefaultSignInResolver = async (info, ctx) => {
1742
- const { profile } = info;
1743
- if (!profile.email) {
1744
- throw new Error("Profile contained no email");
1745
1499
  }
1746
- const userId = profile.email.split("@")[0];
1747
- const entityRef = catalogModel.stringifyEntityRef({
1748
- kind: "User",
1749
- namespace: catalogModel.DEFAULT_NAMESPACE,
1750
- name: userId
1751
- });
1752
- const token = await ctx.tokenIssuer.issueToken({
1753
- claims: {
1754
- sub: entityRef,
1755
- ent: [entityRef]
1756
- }
1757
- });
1758
- return { id: userId, token };
1759
- };
1760
- const createMicrosoftProvider = (options) => {
1761
- return ({
1762
- providerId,
1763
- globalConfig,
1764
- config,
1765
- tokenIssuer,
1766
- tokenManager,
1767
- catalogApi,
1768
- logger
1769
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1770
- var _a, _b;
1771
- const clientId = envConfig.getString("clientId");
1772
- const clientSecret = envConfig.getString("clientSecret");
1773
- const tenantId = envConfig.getString("tenantId");
1774
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1775
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1776
- const authorizationUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`;
1777
- const tokenUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
1778
- const catalogIdentityClient = new CatalogIdentityClient({
1779
- catalogApi,
1780
- tokenManager
1781
- });
1782
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1783
- profile: makeProfileInfo(fullProfile, params.id_token)
1784
- });
1785
- const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : microsoftDefaultSignInResolver;
1786
- const signInResolver = (info) => signInResolverFn(info, {
1787
- catalogIdentityClient,
1788
- tokenIssuer,
1789
- logger
1790
- });
1791
- const provider = new MicrosoftAuthProvider({
1792
- clientId,
1793
- clientSecret,
1794
- callbackUrl,
1795
- authorizationUrl,
1796
- tokenUrl,
1797
- authHandler,
1798
- signInResolver,
1799
- catalogIdentityClient,
1800
- logger,
1801
- tokenIssuer
1802
- });
1803
- return OAuthAdapter.fromConfig(globalConfig, provider, {
1804
- disableRefresh: false,
1805
- providerId,
1806
- tokenIssuer,
1807
- callbackUrl
1808
- });
1809
- });
1810
- };
1500
+ });
1501
+ const createMicrosoftProvider = microsoft.create;
1502
+ const microsoftEmailSignInResolver = microsoft.resolvers.emailMatchingUserEntityAnnotation();
1811
1503
 
1812
1504
  class OAuth2AuthProvider {
1813
1505
  constructor(options) {
1814
1506
  this.signInResolver = options.signInResolver;
1815
1507
  this.authHandler = options.authHandler;
1816
- this.tokenIssuer = options.tokenIssuer;
1817
- this.catalogIdentityClient = options.catalogIdentityClient;
1818
- this.logger = options.logger;
1508
+ this.resolverContext = options.resolverContext;
1819
1509
  this._strategy = new OAuth2Strategy.Strategy({
1820
1510
  clientID: options.clientId,
1821
1511
  clientSecret: options.clientSecret,
@@ -1867,12 +1557,7 @@ class OAuth2AuthProvider {
1867
1557
  };
1868
1558
  }
1869
1559
  async handleResult(result) {
1870
- const context = {
1871
- logger: this.logger,
1872
- catalogIdentityClient: this.catalogIdentityClient,
1873
- tokenIssuer: this.tokenIssuer
1874
- };
1875
- const { profile } = await this.authHandler(result, context);
1560
+ const { profile } = await this.authHandler(result, this.resolverContext);
1876
1561
  const response = {
1877
1562
  providerInfo: {
1878
1563
  idToken: result.params.id_token,
@@ -1886,7 +1571,7 @@ class OAuth2AuthProvider {
1886
1571
  response.backstageIdentity = await this.signInResolver({
1887
1572
  result,
1888
1573
  profile
1889
- }, context);
1574
+ }, this.resolverContext);
1890
1575
  }
1891
1576
  return response;
1892
1577
  }
@@ -1894,87 +1579,48 @@ class OAuth2AuthProvider {
1894
1579
  return Buffer.from(`${clientID}:${clientSecret}`).toString("base64");
1895
1580
  }
1896
1581
  }
1897
- const oAuth2DefaultSignInResolver = async (info, ctx) => {
1898
- const { profile } = info;
1899
- if (!profile.email) {
1900
- throw new Error("Profile contained no email");
1901
- }
1902
- const userId = profile.email.split("@")[0];
1903
- const entityRef = catalogModel.stringifyEntityRef({
1904
- kind: "User",
1905
- namespace: catalogModel.DEFAULT_NAMESPACE,
1906
- name: userId
1907
- });
1908
- const token = await ctx.tokenIssuer.issueToken({
1909
- claims: {
1910
- sub: entityRef,
1911
- ent: [entityRef]
1912
- }
1913
- });
1914
- return { id: userId, token };
1915
- };
1916
- const createOAuth2Provider = (options) => {
1917
- return ({
1918
- providerId,
1919
- globalConfig,
1920
- config,
1921
- tokenIssuer,
1922
- tokenManager,
1923
- catalogApi,
1924
- logger
1925
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1926
- var _a, _b, _c;
1927
- const clientId = envConfig.getString("clientId");
1928
- const clientSecret = envConfig.getString("clientSecret");
1929
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
1930
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1931
- const authorizationUrl = envConfig.getString("authorizationUrl");
1932
- const tokenUrl = envConfig.getString("tokenUrl");
1933
- const scope = envConfig.getOptionalString("scope");
1934
- const includeBasicAuth = envConfig.getOptionalBoolean("includeBasicAuth");
1935
- const disableRefresh = (_a = envConfig.getOptionalBoolean("disableRefresh")) != null ? _a : false;
1936
- const catalogIdentityClient = new CatalogIdentityClient({
1937
- catalogApi,
1938
- tokenManager
1939
- });
1940
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1941
- profile: makeProfileInfo(fullProfile, params.id_token)
1942
- });
1943
- const signInResolverFn = (_c = (_b = options == null ? void 0 : options.signIn) == null ? void 0 : _b.resolver) != null ? _c : oAuth2DefaultSignInResolver;
1944
- const signInResolver = (info) => signInResolverFn(info, {
1945
- catalogIdentityClient,
1946
- tokenIssuer,
1947
- logger
1948
- });
1949
- const provider = new OAuth2AuthProvider({
1950
- clientId,
1951
- clientSecret,
1952
- tokenIssuer,
1953
- catalogIdentityClient,
1954
- callbackUrl,
1955
- signInResolver,
1956
- authHandler,
1957
- authorizationUrl,
1958
- tokenUrl,
1959
- scope,
1960
- logger,
1961
- includeBasicAuth
1962
- });
1963
- return OAuthAdapter.fromConfig(globalConfig, provider, {
1964
- disableRefresh,
1965
- providerId,
1966
- tokenIssuer,
1967
- 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
+ });
1968
1615
  });
1969
- });
1970
- };
1616
+ }
1617
+ });
1618
+ const createOAuth2Provider = oauth2.create;
1971
1619
 
1972
1620
  const OAUTH2_PROXY_JWT_HEADER = "X-OAUTH2-PROXY-ID-TOKEN";
1973
1621
  class Oauth2ProxyAuthProvider {
1974
1622
  constructor(options) {
1975
- this.catalogIdentityClient = options.catalogIdentityClient;
1976
- this.logger = options.logger;
1977
- this.tokenIssuer = options.tokenIssuer;
1623
+ this.resolverContext = options.resolverContext;
1978
1624
  this.signInResolver = options.signInResolver;
1979
1625
  this.authHandler = options.authHandler;
1980
1626
  }
@@ -1987,25 +1633,18 @@ class Oauth2ProxyAuthProvider {
1987
1633
  const response = await this.handleResult(result);
1988
1634
  res.json(response);
1989
1635
  } catch (e) {
1990
- this.logger.error(`Exception occurred during ${OAUTH2_PROXY_JWT_HEADER} refresh`, e);
1991
- res.status(401);
1992
- res.end();
1636
+ throw new errors.AuthenticationError("Refresh failed", e);
1993
1637
  }
1994
1638
  }
1995
1639
  start() {
1996
1640
  return Promise.resolve(void 0);
1997
1641
  }
1998
1642
  async handleResult(result) {
1999
- const ctx = {
2000
- logger: this.logger,
2001
- tokenIssuer: this.tokenIssuer,
2002
- catalogIdentityClient: this.catalogIdentityClient
2003
- };
2004
- const { profile } = await this.authHandler(result, ctx);
1643
+ const { profile } = await this.authHandler(result, this.resolverContext);
2005
1644
  const backstageSignInResult = await this.signInResolver({
2006
1645
  result,
2007
1646
  profile
2008
- }, ctx);
1647
+ }, this.resolverContext);
2009
1648
  return {
2010
1649
  providerInfo: {
2011
1650
  accessToken: result.accessToken
@@ -2027,21 +1666,20 @@ class Oauth2ProxyAuthProvider {
2027
1666
  };
2028
1667
  }
2029
1668
  }
2030
- const createOauth2ProxyProvider = (options) => ({ catalogApi, logger, tokenIssuer, tokenManager }) => {
2031
- const signInResolver = options.signIn.resolver;
2032
- const authHandler = options.authHandler;
2033
- const catalogIdentityClient = new CatalogIdentityClient({
2034
- catalogApi,
2035
- tokenManager
2036
- });
2037
- return new Oauth2ProxyAuthProvider({
2038
- logger,
2039
- signInResolver,
2040
- authHandler,
2041
- tokenIssuer,
2042
- catalogIdentityClient
2043
- });
2044
- };
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;
2045
1683
 
2046
1684
  class OidcAuthProvider {
2047
1685
  constructor(options) {
@@ -2050,9 +1688,7 @@ class OidcAuthProvider {
2050
1688
  this.prompt = options.prompt;
2051
1689
  this.signInResolver = options.signInResolver;
2052
1690
  this.authHandler = options.authHandler;
2053
- this.tokenIssuer = options.tokenIssuer;
2054
- this.catalogIdentityClient = options.catalogIdentityClient;
2055
- this.logger = options.logger;
1691
+ this.resolverContext = options.resolverContext;
2056
1692
  }
2057
1693
  async start(req) {
2058
1694
  const { strategy } = await this.implementation;
@@ -2112,12 +1748,7 @@ class OidcAuthProvider {
2112
1748
  return { strategy, client };
2113
1749
  }
2114
1750
  async handleResult(result) {
2115
- const context = {
2116
- logger: this.logger,
2117
- catalogIdentityClient: this.catalogIdentityClient,
2118
- tokenIssuer: this.tokenIssuer
2119
- };
2120
- const { profile } = await this.authHandler(result, context);
1751
+ const { profile } = await this.authHandler(result, this.resolverContext);
2121
1752
  const response = {
2122
1753
  providerInfo: {
2123
1754
  idToken: result.tokenset.id_token,
@@ -2131,92 +1762,55 @@ class OidcAuthProvider {
2131
1762
  response.backstageIdentity = await this.signInResolver({
2132
1763
  result,
2133
1764
  profile
2134
- }, context);
1765
+ }, this.resolverContext);
2135
1766
  }
2136
1767
  return response;
2137
1768
  }
2138
1769
  }
2139
- const oidcDefaultSignInResolver = async (info, ctx) => {
2140
- const { profile } = info;
2141
- if (!profile.email) {
2142
- throw new Error("Profile contained no email");
2143
- }
2144
- const userId = profile.email.split("@")[0];
2145
- const entityRef = catalogModel.stringifyEntityRef({
2146
- kind: "User",
2147
- namespace: catalogModel.DEFAULT_NAMESPACE,
2148
- name: userId
2149
- });
2150
- const token = await ctx.tokenIssuer.issueToken({
2151
- claims: {
2152
- sub: entityRef,
2153
- ent: [entityRef]
2154
- }
2155
- });
2156
- return { id: userId, token };
2157
- };
2158
- const createOidcProvider = (options) => {
2159
- return ({
2160
- providerId,
2161
- globalConfig,
2162
- config,
2163
- tokenIssuer,
2164
- tokenManager,
2165
- catalogApi,
2166
- logger
2167
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2168
- var _a, _b;
2169
- const clientId = envConfig.getString("clientId");
2170
- const clientSecret = envConfig.getString("clientSecret");
2171
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
2172
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2173
- const metadataUrl = envConfig.getString("metadataUrl");
2174
- const tokenSignedResponseAlg = envConfig.getOptionalString("tokenSignedResponseAlg");
2175
- const scope = envConfig.getOptionalString("scope");
2176
- const prompt = envConfig.getOptionalString("prompt");
2177
- const catalogIdentityClient = new CatalogIdentityClient({
2178
- catalogApi,
2179
- tokenManager
2180
- });
2181
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ userinfo }) => ({
2182
- profile: {
2183
- displayName: userinfo.name,
2184
- email: userinfo.email,
2185
- picture: userinfo.picture
2186
- }
2187
- });
2188
- const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : oidcDefaultSignInResolver;
2189
- const signInResolver = (info) => signInResolverFn(info, {
2190
- catalogIdentityClient,
2191
- tokenIssuer,
2192
- logger
2193
- });
2194
- const provider = new OidcAuthProvider({
2195
- clientId,
2196
- clientSecret,
2197
- callbackUrl,
2198
- tokenSignedResponseAlg,
2199
- metadataUrl,
2200
- scope,
2201
- prompt,
2202
- signInResolver,
2203
- authHandler,
2204
- logger,
2205
- tokenIssuer,
2206
- catalogIdentityClient
2207
- });
2208
- return OAuthAdapter.fromConfig(globalConfig, provider, {
2209
- disableRefresh: false,
2210
- providerId,
2211
- tokenIssuer,
2212
- 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
+ });
2213
1806
  });
2214
- });
2215
- };
1807
+ }
1808
+ });
1809
+ const createOidcProvider = oidc.create;
2216
1810
 
2217
1811
  class OktaAuthProvider {
2218
1812
  constructor(options) {
2219
- this._store = {
1813
+ this.store = {
2220
1814
  store(_req, cb) {
2221
1815
  cb(null, null);
2222
1816
  },
@@ -2224,18 +1818,16 @@ class OktaAuthProvider {
2224
1818
  cb(null, true);
2225
1819
  }
2226
1820
  };
2227
- this._signInResolver = options.signInResolver;
2228
- this._authHandler = options.authHandler;
2229
- this._tokenIssuer = options.tokenIssuer;
2230
- this._catalogIdentityClient = options.catalogIdentityClient;
2231
- this._logger = options.logger;
2232
- 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({
2233
1825
  clientID: options.clientId,
2234
1826
  clientSecret: options.clientSecret,
2235
1827
  callbackURL: options.callbackUrl,
2236
1828
  audience: options.audience,
2237
1829
  passReqToCallback: false,
2238
- store: this._store,
1830
+ store: this.store,
2239
1831
  response_type: "code"
2240
1832
  }, (accessToken, refreshToken, params, fullProfile, done) => {
2241
1833
  done(void 0, {
@@ -2249,7 +1841,7 @@ class OktaAuthProvider {
2249
1841
  });
2250
1842
  }
2251
1843
  async start(req) {
2252
- return await executeRedirectStrategy(req, this._strategy, {
1844
+ return await executeRedirectStrategy(req, this.strategy, {
2253
1845
  accessType: "offline",
2254
1846
  prompt: "consent",
2255
1847
  scope: req.scope,
@@ -2257,15 +1849,15 @@ class OktaAuthProvider {
2257
1849
  });
2258
1850
  }
2259
1851
  async handler(req) {
2260
- const { result, privateInfo } = await executeFrameHandlerStrategy(req, this._strategy);
1852
+ const { result, privateInfo } = await executeFrameHandlerStrategy(req, this.strategy);
2261
1853
  return {
2262
1854
  response: await this.handleResult(result),
2263
1855
  refreshToken: privateInfo.refreshToken
2264
1856
  };
2265
1857
  }
2266
1858
  async refresh(req) {
2267
- const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
2268
- 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);
2269
1861
  return {
2270
1862
  response: await this.handleResult({
2271
1863
  fullProfile,
@@ -2276,12 +1868,7 @@ class OktaAuthProvider {
2276
1868
  };
2277
1869
  }
2278
1870
  async handleResult(result) {
2279
- const context = {
2280
- logger: this._logger,
2281
- catalogIdentityClient: this._catalogIdentityClient,
2282
- tokenIssuer: this._tokenIssuer
2283
- };
2284
- const { profile } = await this._authHandler(result, context);
1871
+ const { profile } = await this.authHandler(result, this.resolverContext);
2285
1872
  const response = {
2286
1873
  providerInfo: {
2287
1874
  idToken: result.params.id_token,
@@ -2291,107 +1878,70 @@ class OktaAuthProvider {
2291
1878
  },
2292
1879
  profile
2293
1880
  };
2294
- if (this._signInResolver) {
2295
- response.backstageIdentity = await this._signInResolver({
1881
+ if (this.signInResolver) {
1882
+ response.backstageIdentity = await this.signInResolver({
2296
1883
  result,
2297
1884
  profile
2298
- }, context);
1885
+ }, this.resolverContext);
2299
1886
  }
2300
1887
  return response;
2301
1888
  }
2302
1889
  }
2303
- const oktaEmailSignInResolver = async (info, ctx) => {
2304
- const { profile } = info;
2305
- if (!profile.email) {
2306
- throw new Error("Okta profile contained no email");
2307
- }
2308
- const entity = await ctx.catalogIdentityClient.findUser({
2309
- annotations: {
2310
- "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
+ };
2311
1934
  }
2312
- });
2313
- const claims = getEntityClaims(entity);
2314
- const token = await ctx.tokenIssuer.issueToken({ claims });
2315
- return { id: entity.metadata.name, entity, token };
2316
- };
2317
- const oktaDefaultSignInResolver = async (info, ctx) => {
2318
- const { profile } = info;
2319
- if (!profile.email) {
2320
- throw new Error("Okta profile contained no email");
2321
1935
  }
2322
- const userId = profile.email.split("@")[0];
2323
- const entityRef = catalogModel.stringifyEntityRef({
2324
- kind: "User",
2325
- namespace: catalogModel.DEFAULT_NAMESPACE,
2326
- name: userId
2327
- });
2328
- const token = await ctx.tokenIssuer.issueToken({
2329
- claims: {
2330
- sub: entityRef,
2331
- ent: [entityRef]
2332
- }
2333
- });
2334
- return { id: userId, token };
2335
- };
2336
- const createOktaProvider = (_options) => {
2337
- return ({
2338
- providerId,
2339
- globalConfig,
2340
- config,
2341
- tokenIssuer,
2342
- tokenManager,
2343
- catalogApi,
2344
- logger
2345
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2346
- var _a, _b;
2347
- const clientId = envConfig.getString("clientId");
2348
- const clientSecret = envConfig.getString("clientSecret");
2349
- const audience = envConfig.getString("audience");
2350
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
2351
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2352
- if (!audience.startsWith("https://")) {
2353
- throw new Error("URL for 'audience' must start with 'https://'.");
2354
- }
2355
- const catalogIdentityClient = new CatalogIdentityClient({
2356
- catalogApi,
2357
- tokenManager
2358
- });
2359
- const authHandler = (_options == null ? void 0 : _options.authHandler) ? _options.authHandler : async ({ fullProfile, params }) => ({
2360
- profile: makeProfileInfo(fullProfile, params.id_token)
2361
- });
2362
- const signInResolverFn = (_b = (_a = _options == null ? void 0 : _options.signIn) == null ? void 0 : _a.resolver) != null ? _b : oktaDefaultSignInResolver;
2363
- const signInResolver = (info) => signInResolverFn(info, {
2364
- catalogIdentityClient,
2365
- tokenIssuer,
2366
- logger
2367
- });
2368
- const provider = new OktaAuthProvider({
2369
- audience,
2370
- clientId,
2371
- clientSecret,
2372
- callbackUrl,
2373
- authHandler,
2374
- signInResolver,
2375
- tokenIssuer,
2376
- catalogIdentityClient,
2377
- logger
2378
- });
2379
- return OAuthAdapter.fromConfig(globalConfig, provider, {
2380
- disableRefresh: false,
2381
- providerId,
2382
- tokenIssuer,
2383
- callbackUrl
2384
- });
2385
- });
2386
- };
1936
+ });
1937
+ const createOktaProvider = okta.create;
1938
+ const oktaEmailSignInResolver = okta.resolvers.emailMatchingUserEntityAnnotation();
2387
1939
 
2388
1940
  class OneLoginProvider {
2389
1941
  constructor(options) {
2390
1942
  this.signInResolver = options.signInResolver;
2391
1943
  this.authHandler = options.authHandler;
2392
- this.tokenIssuer = options.tokenIssuer;
2393
- this.catalogIdentityClient = options.catalogIdentityClient;
2394
- this.logger = options.logger;
1944
+ this.resolverContext = options.resolverContext;
2395
1945
  this._strategy = new passportOneloginOauth.Strategy({
2396
1946
  issuer: options.issuer,
2397
1947
  clientID: options.clientId,
@@ -2437,12 +1987,7 @@ class OneLoginProvider {
2437
1987
  };
2438
1988
  }
2439
1989
  async handleResult(result) {
2440
- const context = {
2441
- logger: this.logger,
2442
- catalogIdentityClient: this.catalogIdentityClient,
2443
- tokenIssuer: this.tokenIssuer
2444
- };
2445
- const { profile } = await this.authHandler(result, context);
1990
+ const { profile } = await this.authHandler(result, this.resolverContext);
2446
1991
  const response = {
2447
1992
  providerInfo: {
2448
1993
  idToken: result.params.id_token,
@@ -2456,71 +2001,48 @@ class OneLoginProvider {
2456
2001
  response.backstageIdentity = await this.signInResolver({
2457
2002
  result,
2458
2003
  profile
2459
- }, context);
2004
+ }, this.resolverContext);
2460
2005
  }
2461
2006
  return response;
2462
2007
  }
2463
2008
  }
2464
- const defaultSignInResolver = async (info) => {
2465
- const { profile } = info;
2466
- if (!profile.email) {
2467
- throw new Error("OIDC profile contained no email");
2468
- }
2469
- const id = profile.email.split("@")[0];
2470
- return { id, token: "" };
2471
- };
2472
- const createOneLoginProvider = (options) => {
2473
- return ({
2474
- providerId,
2475
- globalConfig,
2476
- config,
2477
- tokenIssuer,
2478
- tokenManager,
2479
- catalogApi,
2480
- logger
2481
- }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
2482
- var _a, _b;
2483
- const clientId = envConfig.getString("clientId");
2484
- const clientSecret = envConfig.getString("clientSecret");
2485
- const issuer = envConfig.getString("issuer");
2486
- const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
2487
- const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
2488
- const catalogIdentityClient = new CatalogIdentityClient({
2489
- catalogApi,
2490
- tokenManager
2491
- });
2492
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
2493
- profile: makeProfileInfo(fullProfile, params.id_token)
2494
- });
2495
- const signInResolver = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : defaultSignInResolver;
2496
- const provider = new OneLoginProvider({
2497
- clientId,
2498
- clientSecret,
2499
- callbackUrl,
2500
- issuer,
2501
- authHandler,
2502
- signInResolver,
2503
- tokenIssuer,
2504
- catalogIdentityClient,
2505
- logger
2506
- });
2507
- return OAuthAdapter.fromConfig(globalConfig, provider, {
2508
- disableRefresh: false,
2509
- providerId,
2510
- tokenIssuer,
2511
- 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
+ });
2512
2035
  });
2513
- });
2514
- };
2036
+ }
2037
+ });
2038
+ const createOneLoginProvider = onelogin.create;
2515
2039
 
2516
2040
  class SamlAuthProvider {
2517
2041
  constructor(options) {
2518
2042
  this.appUrl = options.appUrl;
2519
2043
  this.signInResolver = options.signInResolver;
2520
2044
  this.authHandler = options.authHandler;
2521
- this.tokenIssuer = options.tokenIssuer;
2522
- this.catalogIdentityClient = options.catalogIdentityClient;
2523
- this.logger = options.logger;
2045
+ this.resolverContext = options.resolverContext;
2524
2046
  this.strategy = new passportSaml.Strategy({ ...options }, (fullProfile, done) => {
2525
2047
  done(void 0, { fullProfile });
2526
2048
  });
@@ -2531,13 +2053,8 @@ class SamlAuthProvider {
2531
2053
  }
2532
2054
  async frameHandler(req, res) {
2533
2055
  try {
2534
- const context = {
2535
- logger: this.logger,
2536
- catalogIdentityClient: this.catalogIdentityClient,
2537
- tokenIssuer: this.tokenIssuer
2538
- };
2539
2056
  const { result } = await executeFrameHandlerStrategy(req, this.strategy);
2540
- const { profile } = await this.authHandler(result, context);
2057
+ const { profile } = await this.authHandler(result, this.resolverContext);
2541
2058
  const response = {
2542
2059
  profile,
2543
2060
  providerInfo: {}
@@ -2546,7 +2063,7 @@ class SamlAuthProvider {
2546
2063
  const signInResponse = await this.signInResolver({
2547
2064
  result,
2548
2065
  profile
2549
- }, context);
2066
+ }, this.resolverContext);
2550
2067
  response.backstageIdentity = prepareBackstageIdentityResponse(signInResponse);
2551
2068
  }
2552
2069
  return postMessageResponse(res, this.appUrl, {
@@ -2565,71 +2082,53 @@ class SamlAuthProvider {
2565
2082
  res.end();
2566
2083
  }
2567
2084
  }
2568
- const samlDefaultSignInResolver = async (info, ctx) => {
2569
- const id = info.result.fullProfile.nameID;
2570
- const entityRef = catalogModel.stringifyEntityRef({
2571
- kind: "User",
2572
- namespace: catalogModel.DEFAULT_NAMESPACE,
2573
- name: id
2574
- });
2575
- const token = await ctx.tokenIssuer.issueToken({
2576
- claims: {
2577
- sub: entityRef,
2578
- 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
+ };
2579
2127
  }
2580
- });
2581
- return { id, token };
2582
- };
2583
- const createSamlProvider = (options) => {
2584
- return ({
2585
- providerId,
2586
- globalConfig,
2587
- config,
2588
- tokenIssuer,
2589
- tokenManager,
2590
- catalogApi,
2591
- logger
2592
- }) => {
2593
- var _a, _b;
2594
- const catalogIdentityClient = new CatalogIdentityClient({
2595
- catalogApi,
2596
- tokenManager
2597
- });
2598
- const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
2599
- profile: {
2600
- email: fullProfile.email,
2601
- displayName: fullProfile.displayName
2602
- }
2603
- });
2604
- const signInResolverFn = (_b = (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver) != null ? _b : samlDefaultSignInResolver;
2605
- const signInResolver = (info) => signInResolverFn(info, {
2606
- catalogIdentityClient,
2607
- tokenIssuer,
2608
- logger
2609
- });
2610
- return new SamlAuthProvider({
2611
- callbackUrl: `${globalConfig.baseUrl}/${providerId}/handler/frame`,
2612
- entryPoint: config.getString("entryPoint"),
2613
- logoutUrl: config.getOptionalString("logoutUrl"),
2614
- audience: config.getOptionalString("audience"),
2615
- issuer: config.getString("issuer"),
2616
- cert: config.getString("cert"),
2617
- privateKey: config.getOptionalString("privateKey"),
2618
- authnContext: config.getOptionalStringArray("authnContext"),
2619
- identifierFormat: config.getOptionalString("identifierFormat"),
2620
- decryptionPvk: config.getOptionalString("decryptionPvk"),
2621
- signatureAlgorithm: config.getOptionalString("signatureAlgorithm"),
2622
- digestAlgorithm: config.getOptionalString("digestAlgorithm"),
2623
- acceptedClockSkewMs: config.getOptionalNumber("acceptedClockSkewMs"),
2624
- tokenIssuer,
2625
- appUrl: globalConfig.appUrl,
2626
- authHandler,
2627
- signInResolver,
2628
- logger,
2629
- catalogIdentityClient
2630
- });
2631
- };
2632
- };
2128
+ }
2129
+ });
2130
+ const createSamlProvider = saml.create;
2131
+ const samlNameIdEntityNameSignInResolver = saml.resolvers.nameIdMatchingUserEntityName();
2633
2132
 
2634
2133
  const IAP_JWT_HEADER = "x-goog-iap-jwt-assertion";
2635
2134
 
@@ -2675,9 +2174,7 @@ class GcpIapProvider {
2675
2174
  this.authHandler = options.authHandler;
2676
2175
  this.signInResolver = options.signInResolver;
2677
2176
  this.tokenValidator = options.tokenValidator;
2678
- this.tokenIssuer = options.tokenIssuer;
2679
- this.catalogIdentityClient = options.catalogIdentityClient;
2680
- this.logger = options.logger;
2177
+ this.resolverContext = options.resolverContext;
2681
2178
  }
2682
2179
  async start() {
2683
2180
  }
@@ -2685,13 +2182,8 @@ class GcpIapProvider {
2685
2182
  }
2686
2183
  async refresh(req, res) {
2687
2184
  const result = await parseRequestToken(req.header(IAP_JWT_HEADER), this.tokenValidator);
2688
- const context = {
2689
- logger: this.logger,
2690
- catalogIdentityClient: this.catalogIdentityClient,
2691
- tokenIssuer: this.tokenIssuer
2692
- };
2693
- const { profile } = await this.authHandler(result, context);
2694
- 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);
2695
2187
  const response = {
2696
2188
  providerInfo: { iapToken: result.iapToken },
2697
2189
  profile,
@@ -2700,27 +2192,42 @@ class GcpIapProvider {
2700
2192
  res.json(response);
2701
2193
  }
2702
2194
  }
2703
- function createGcpIapProvider(options) {
2704
- return ({ config, tokenIssuer, catalogApi, logger, tokenManager }) => {
2705
- var _a;
2706
- const audience = config.getString("audience");
2707
- const authHandler = (_a = options.authHandler) != null ? _a : defaultAuthHandler;
2708
- const signInResolver = options.signIn.resolver;
2709
- const tokenValidator = createTokenValidator(audience);
2710
- const catalogIdentityClient = new CatalogIdentityClient({
2711
- catalogApi,
2712
- tokenManager
2713
- });
2714
- return new GcpIapProvider({
2715
- authHandler,
2716
- signInResolver,
2717
- tokenValidator,
2718
- tokenIssuer,
2719
- catalogIdentityClient,
2720
- logger
2721
- });
2722
- };
2723
- }
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
+ });
2724
2231
 
2725
2232
  const factories = {
2726
2233
  google: createGoogleProvider(),
@@ -3008,6 +2515,149 @@ class KeyStores {
3008
2515
  }
3009
2516
  }
3010
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
+
3011
2661
  async function createRouter(options) {
3012
2662
  const {
3013
2663
  logger,
@@ -3069,7 +2719,13 @@ async function createRouter(options) {
3069
2719
  tokenManager,
3070
2720
  tokenIssuer,
3071
2721
  discovery,
3072
- catalogApi
2722
+ catalogApi,
2723
+ resolverContext: CatalogAuthResolverContext.create({
2724
+ logger,
2725
+ catalogApi,
2726
+ tokenIssuer,
2727
+ tokenManager
2728
+ })
3073
2729
  });
3074
2730
  const r = Router__default["default"]();
3075
2731
  r.get("/start", provider.start.bind(provider));
@@ -3147,12 +2803,15 @@ exports.createSamlProvider = createSamlProvider;
3147
2803
  exports.defaultAuthProviderFactories = factories;
3148
2804
  exports.encodeState = encodeState;
3149
2805
  exports.ensuresXRequestedWith = ensuresXRequestedWith;
2806
+ exports.getDefaultOwnershipEntityRefs = getDefaultOwnershipEntityRefs;
3150
2807
  exports.getEntityClaims = getEntityClaims;
3151
2808
  exports.googleEmailSignInResolver = googleEmailSignInResolver;
3152
2809
  exports.microsoftEmailSignInResolver = microsoftEmailSignInResolver;
3153
2810
  exports.oktaEmailSignInResolver = oktaEmailSignInResolver;
3154
2811
  exports.postMessageResponse = postMessageResponse;
3155
2812
  exports.prepareBackstageIdentityResponse = prepareBackstageIdentityResponse;
2813
+ exports.providers = providers;
3156
2814
  exports.readState = readState;
2815
+ exports.samlNameIdEntityNameSignInResolver = samlNameIdEntityNameSignInResolver;
3157
2816
  exports.verifyNonce = verifyNonce;
3158
2817
  //# sourceMappingURL=index.cjs.js.map