@backstage/plugin-auth-backend 0.15.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/index.cjs.js +728 -379
- package/dist/index.cjs.js.map +1 -1
- package/package.json +7 -7
package/dist/index.cjs.js
CHANGED
|
@@ -96,10 +96,17 @@ class AtlassianStrategy extends OAuth2Strategy__default["default"] {
|
|
|
96
96
|
userProfile(accessToken, done) {
|
|
97
97
|
this._oauth2.get(this.profileURL, accessToken, (err, body) => {
|
|
98
98
|
if (err) {
|
|
99
|
-
return done(
|
|
99
|
+
return done(
|
|
100
|
+
new OAuth2Strategy.InternalOAuthError(
|
|
101
|
+
"Failed to fetch user profile",
|
|
102
|
+
err.statusCode
|
|
103
|
+
)
|
|
104
|
+
);
|
|
100
105
|
}
|
|
101
106
|
if (!body) {
|
|
102
|
-
return done(
|
|
107
|
+
return done(
|
|
108
|
+
new Error("Failed to fetch user profile, body cannot be empty")
|
|
109
|
+
);
|
|
103
110
|
}
|
|
104
111
|
try {
|
|
105
112
|
const json = typeof body !== "string" ? body.toString() : body;
|
|
@@ -125,14 +132,18 @@ class AtlassianStrategy extends OAuth2Strategy__default["default"] {
|
|
|
125
132
|
|
|
126
133
|
const readState = (stateString) => {
|
|
127
134
|
var _a, _b;
|
|
128
|
-
const state = Object.fromEntries(
|
|
135
|
+
const state = Object.fromEntries(
|
|
136
|
+
new URLSearchParams(Buffer.from(stateString, "hex").toString("utf-8"))
|
|
137
|
+
);
|
|
129
138
|
if (!state.nonce || !state.env || ((_a = state.nonce) == null ? void 0 : _a.length) === 0 || ((_b = state.env) == null ? void 0 : _b.length) === 0) {
|
|
130
139
|
throw Error(`Invalid state passed via request`);
|
|
131
140
|
}
|
|
132
141
|
return state;
|
|
133
142
|
};
|
|
134
143
|
const encodeState = (state) => {
|
|
135
|
-
const stateString = new URLSearchParams(
|
|
144
|
+
const stateString = new URLSearchParams(
|
|
145
|
+
pickBy__default["default"](state, (value) => value !== void 0)
|
|
146
|
+
).toString();
|
|
136
147
|
return Buffer.from(stateString, "utf-8").toString("hex");
|
|
137
148
|
};
|
|
138
149
|
const verifyNonce = (req, providerId) => {
|
|
@@ -212,7 +223,9 @@ class OAuthEnvironmentHandler {
|
|
|
212
223
|
}
|
|
213
224
|
const handler = this.handlers.get(env);
|
|
214
225
|
if (!handler) {
|
|
215
|
-
throw new errors.NotFoundError(
|
|
226
|
+
throw new errors.NotFoundError(
|
|
227
|
+
`No configuration available for the '${env}' environment of this provider.`
|
|
228
|
+
);
|
|
216
229
|
}
|
|
217
230
|
return handler;
|
|
218
231
|
}
|
|
@@ -340,7 +353,9 @@ class OAuthAdapter {
|
|
|
340
353
|
state.scope = scope;
|
|
341
354
|
}
|
|
342
355
|
const forwardReq = Object.assign(req, { scope, state });
|
|
343
|
-
const { url, status } = await this.handlers.start(
|
|
356
|
+
const { url, status } = await this.handlers.start(
|
|
357
|
+
forwardReq
|
|
358
|
+
);
|
|
344
359
|
res.statusCode = status || 302;
|
|
345
360
|
res.setHeader("Location", url);
|
|
346
361
|
res.setHeader("Content-Length", "0");
|
|
@@ -396,7 +411,9 @@ class OAuthAdapter {
|
|
|
396
411
|
throw new errors.AuthenticationError("Invalid X-Requested-With header");
|
|
397
412
|
}
|
|
398
413
|
if (!this.handlers.refresh) {
|
|
399
|
-
throw new errors.InputError(
|
|
414
|
+
throw new errors.InputError(
|
|
415
|
+
`Refresh token is not supported for provider ${this.options.providerId}`
|
|
416
|
+
);
|
|
400
417
|
}
|
|
401
418
|
try {
|
|
402
419
|
const refreshToken = req.cookies[`${this.options.providerId}-refresh-token`];
|
|
@@ -409,7 +426,9 @@ class OAuthAdapter {
|
|
|
409
426
|
}
|
|
410
427
|
const forwardReq = Object.assign(req, { scope, refreshToken });
|
|
411
428
|
const { response, refreshToken: newRefreshToken } = await this.handlers.refresh(forwardReq);
|
|
412
|
-
const backstageIdentity = await this.populateIdentity(
|
|
429
|
+
const backstageIdentity = await this.populateIdentity(
|
|
430
|
+
response.backstageIdentity
|
|
431
|
+
);
|
|
413
432
|
if (newRefreshToken && newRefreshToken !== refreshToken) {
|
|
414
433
|
this.setRefreshTokenCookie(res, newRefreshToken);
|
|
415
434
|
}
|
|
@@ -476,69 +495,89 @@ const executeRedirectStrategy = async (req, providerStrategy, options) => {
|
|
|
476
495
|
});
|
|
477
496
|
};
|
|
478
497
|
const executeFrameHandlerStrategy = async (req, providerStrategy) => {
|
|
479
|
-
return new Promise(
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
498
|
+
return new Promise(
|
|
499
|
+
(resolve, reject) => {
|
|
500
|
+
const strategy = Object.create(providerStrategy);
|
|
501
|
+
strategy.success = (result, privateInfo) => {
|
|
502
|
+
resolve({ result, privateInfo });
|
|
503
|
+
};
|
|
504
|
+
strategy.fail = (info) => {
|
|
505
|
+
var _a;
|
|
506
|
+
reject(new Error(`Authentication rejected, ${(_a = info.message) != null ? _a : ""}`));
|
|
507
|
+
};
|
|
508
|
+
strategy.error = (error) => {
|
|
509
|
+
var _a;
|
|
510
|
+
let message = `Authentication failed, ${error.message}`;
|
|
511
|
+
if ((_a = error.oauthError) == null ? void 0 : _a.data) {
|
|
512
|
+
try {
|
|
513
|
+
const errorData = JSON.parse(error.oauthError.data);
|
|
514
|
+
if (errorData.message) {
|
|
515
|
+
message += ` - ${errorData.message}`;
|
|
516
|
+
}
|
|
517
|
+
} catch (parseError) {
|
|
518
|
+
message += ` - ${error.oauthError}`;
|
|
496
519
|
}
|
|
497
|
-
} catch (parseError) {
|
|
498
|
-
message += ` - ${error.oauthError}`;
|
|
499
520
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
521
|
+
reject(new Error(message));
|
|
522
|
+
};
|
|
523
|
+
strategy.redirect = () => {
|
|
524
|
+
reject(new Error("Unexpected redirect"));
|
|
525
|
+
};
|
|
526
|
+
strategy.authenticate(req, {});
|
|
527
|
+
}
|
|
528
|
+
);
|
|
508
529
|
};
|
|
509
530
|
const executeRefreshTokenStrategy = async (providerStrategy, refreshToken, scope) => {
|
|
510
531
|
return new Promise((resolve, reject) => {
|
|
511
532
|
const anyStrategy = providerStrategy;
|
|
512
533
|
const OAuth2 = anyStrategy._oauth2.constructor;
|
|
513
|
-
const oauth2 = new OAuth2(
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
534
|
+
const oauth2 = new OAuth2(
|
|
535
|
+
anyStrategy._oauth2._clientId,
|
|
536
|
+
anyStrategy._oauth2._clientSecret,
|
|
537
|
+
anyStrategy._oauth2._baseSite,
|
|
538
|
+
anyStrategy._oauth2._authorizeUrl,
|
|
539
|
+
anyStrategy._refreshURL || anyStrategy._oauth2._accessTokenUrl,
|
|
540
|
+
anyStrategy._oauth2._customHeaders
|
|
541
|
+
);
|
|
542
|
+
oauth2.getOAuthAccessToken(
|
|
543
|
+
refreshToken,
|
|
544
|
+
{
|
|
545
|
+
scope,
|
|
546
|
+
grant_type: "refresh_token"
|
|
547
|
+
},
|
|
548
|
+
(err, accessToken, newRefreshToken, params) => {
|
|
549
|
+
if (err) {
|
|
550
|
+
reject(new Error(`Failed to refresh access token ${err.toString()}`));
|
|
551
|
+
}
|
|
552
|
+
if (!accessToken) {
|
|
553
|
+
reject(
|
|
554
|
+
new Error(
|
|
555
|
+
`Failed to refresh access token, no access token received`
|
|
556
|
+
)
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
resolve({
|
|
560
|
+
accessToken,
|
|
561
|
+
refreshToken: newRefreshToken,
|
|
562
|
+
params
|
|
563
|
+
});
|
|
523
564
|
}
|
|
524
|
-
|
|
525
|
-
accessToken,
|
|
526
|
-
refreshToken: newRefreshToken,
|
|
527
|
-
params
|
|
528
|
-
});
|
|
529
|
-
});
|
|
565
|
+
);
|
|
530
566
|
});
|
|
531
567
|
};
|
|
532
568
|
const executeFetchUserProfileStrategy = async (providerStrategy, accessToken) => {
|
|
533
569
|
return new Promise((resolve, reject) => {
|
|
534
570
|
const anyStrategy = providerStrategy;
|
|
535
|
-
anyStrategy.userProfile(
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
571
|
+
anyStrategy.userProfile(
|
|
572
|
+
accessToken,
|
|
573
|
+
(error, rawProfile) => {
|
|
574
|
+
if (error) {
|
|
575
|
+
reject(error);
|
|
576
|
+
} else {
|
|
577
|
+
resolve(rawProfile);
|
|
578
|
+
}
|
|
540
579
|
}
|
|
541
|
-
|
|
580
|
+
);
|
|
542
581
|
});
|
|
543
582
|
};
|
|
544
583
|
|
|
@@ -561,19 +600,22 @@ class AtlassianAuthProvider {
|
|
|
561
600
|
this.resolverContext = options.resolverContext;
|
|
562
601
|
this.authHandler = options.authHandler;
|
|
563
602
|
this.signInResolver = options.signInResolver;
|
|
564
|
-
this._strategy = new AtlassianStrategy(
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
603
|
+
this._strategy = new AtlassianStrategy(
|
|
604
|
+
{
|
|
605
|
+
clientID: options.clientId,
|
|
606
|
+
clientSecret: options.clientSecret,
|
|
607
|
+
callbackURL: options.callbackUrl,
|
|
608
|
+
scope: options.scopes
|
|
609
|
+
},
|
|
610
|
+
(accessToken, refreshToken, params, fullProfile, done) => {
|
|
611
|
+
done(void 0, {
|
|
612
|
+
fullProfile,
|
|
613
|
+
accessToken,
|
|
614
|
+
refreshToken,
|
|
615
|
+
params
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
);
|
|
577
619
|
}
|
|
578
620
|
async start(req) {
|
|
579
621
|
return await executeRedirectStrategy(req, this._strategy, {
|
|
@@ -581,7 +623,10 @@ class AtlassianAuthProvider {
|
|
|
581
623
|
});
|
|
582
624
|
}
|
|
583
625
|
async handler(req) {
|
|
584
|
-
const { result } = await executeFrameHandlerStrategy(
|
|
626
|
+
const { result } = await executeFrameHandlerStrategy(
|
|
627
|
+
req,
|
|
628
|
+
this._strategy
|
|
629
|
+
);
|
|
585
630
|
return {
|
|
586
631
|
response: await this.handleResult(result),
|
|
587
632
|
refreshToken: result.refreshToken
|
|
@@ -599,16 +644,26 @@ class AtlassianAuthProvider {
|
|
|
599
644
|
profile
|
|
600
645
|
};
|
|
601
646
|
if (this.signInResolver) {
|
|
602
|
-
response.backstageIdentity = await this.signInResolver(
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
647
|
+
response.backstageIdentity = await this.signInResolver(
|
|
648
|
+
{
|
|
649
|
+
result,
|
|
650
|
+
profile
|
|
651
|
+
},
|
|
652
|
+
this.resolverContext
|
|
653
|
+
);
|
|
606
654
|
}
|
|
607
655
|
return response;
|
|
608
656
|
}
|
|
609
657
|
async refresh(req) {
|
|
610
|
-
const { accessToken, params, refreshToken } = await executeRefreshTokenStrategy(
|
|
611
|
-
|
|
658
|
+
const { accessToken, params, refreshToken } = await executeRefreshTokenStrategy(
|
|
659
|
+
this._strategy,
|
|
660
|
+
req.refreshToken,
|
|
661
|
+
req.scope
|
|
662
|
+
);
|
|
663
|
+
const fullProfile = await executeFetchUserProfileStrategy(
|
|
664
|
+
this._strategy,
|
|
665
|
+
accessToken
|
|
666
|
+
);
|
|
612
667
|
return {
|
|
613
668
|
response: await this.handleResult({
|
|
614
669
|
fullProfile,
|
|
@@ -664,22 +719,29 @@ class Auth0AuthProvider {
|
|
|
664
719
|
this.signInResolver = options.signInResolver;
|
|
665
720
|
this.authHandler = options.authHandler;
|
|
666
721
|
this.resolverContext = options.resolverContext;
|
|
667
|
-
this._strategy = new Auth0Strategy(
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
722
|
+
this._strategy = new Auth0Strategy(
|
|
723
|
+
{
|
|
724
|
+
clientID: options.clientId,
|
|
725
|
+
clientSecret: options.clientSecret,
|
|
726
|
+
callbackURL: options.callbackUrl,
|
|
727
|
+
domain: options.domain,
|
|
728
|
+
passReqToCallback: false
|
|
729
|
+
},
|
|
730
|
+
(accessToken, refreshToken, params, fullProfile, done) => {
|
|
731
|
+
done(
|
|
732
|
+
void 0,
|
|
733
|
+
{
|
|
734
|
+
fullProfile,
|
|
735
|
+
accessToken,
|
|
736
|
+
refreshToken,
|
|
737
|
+
params
|
|
738
|
+
},
|
|
739
|
+
{
|
|
740
|
+
refreshToken
|
|
741
|
+
}
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
);
|
|
683
745
|
}
|
|
684
746
|
async start(req) {
|
|
685
747
|
return await executeRedirectStrategy(req, this._strategy, {
|
|
@@ -697,8 +759,15 @@ class Auth0AuthProvider {
|
|
|
697
759
|
};
|
|
698
760
|
}
|
|
699
761
|
async refresh(req) {
|
|
700
|
-
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
701
|
-
|
|
762
|
+
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
763
|
+
this._strategy,
|
|
764
|
+
req.refreshToken,
|
|
765
|
+
req.scope
|
|
766
|
+
);
|
|
767
|
+
const fullProfile = await executeFetchUserProfileStrategy(
|
|
768
|
+
this._strategy,
|
|
769
|
+
accessToken
|
|
770
|
+
);
|
|
702
771
|
return {
|
|
703
772
|
response: await this.handleResult({
|
|
704
773
|
fullProfile,
|
|
@@ -720,10 +789,13 @@ class Auth0AuthProvider {
|
|
|
720
789
|
profile
|
|
721
790
|
};
|
|
722
791
|
if (this.signInResolver) {
|
|
723
|
-
response.backstageIdentity = await this.signInResolver(
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
792
|
+
response.backstageIdentity = await this.signInResolver(
|
|
793
|
+
{
|
|
794
|
+
result,
|
|
795
|
+
profile
|
|
796
|
+
},
|
|
797
|
+
this.resolverContext
|
|
798
|
+
);
|
|
727
799
|
}
|
|
728
800
|
return response;
|
|
729
801
|
}
|
|
@@ -770,9 +842,16 @@ class AwsAlbAuthProvider {
|
|
|
770
842
|
if (optionalCacheKey) {
|
|
771
843
|
return crypto__namespace.createPublicKey(optionalCacheKey);
|
|
772
844
|
}
|
|
773
|
-
const keyText = await fetch__default["default"](
|
|
845
|
+
const keyText = await fetch__default["default"](
|
|
846
|
+
`https://public-keys.auth.elb.${encodeURIComponent(
|
|
847
|
+
this.region
|
|
848
|
+
)}.amazonaws.com/${encodeURIComponent(header.kid)}`
|
|
849
|
+
).then((response) => response.text());
|
|
774
850
|
const keyValue = crypto__namespace.createPublicKey(keyText);
|
|
775
|
-
this.keyCache.set(
|
|
851
|
+
this.keyCache.set(
|
|
852
|
+
header.kid,
|
|
853
|
+
keyValue.export({ format: "pem", type: "spki" })
|
|
854
|
+
);
|
|
776
855
|
return keyValue;
|
|
777
856
|
};
|
|
778
857
|
this.region = options.region;
|
|
@@ -791,7 +870,10 @@ class AwsAlbAuthProvider {
|
|
|
791
870
|
const response = await this.handleResult(result);
|
|
792
871
|
res.json(response);
|
|
793
872
|
} catch (e) {
|
|
794
|
-
throw new errors.AuthenticationError(
|
|
873
|
+
throw new errors.AuthenticationError(
|
|
874
|
+
"Exception occurred during AWS ALB token refresh",
|
|
875
|
+
e
|
|
876
|
+
);
|
|
795
877
|
}
|
|
796
878
|
}
|
|
797
879
|
start() {
|
|
@@ -801,10 +883,14 @@ class AwsAlbAuthProvider {
|
|
|
801
883
|
const jwt = req.header(ALB_JWT_HEADER);
|
|
802
884
|
const accessToken = req.header(ALB_ACCESS_TOKEN_HEADER);
|
|
803
885
|
if (jwt === void 0) {
|
|
804
|
-
throw new errors.AuthenticationError(
|
|
886
|
+
throw new errors.AuthenticationError(
|
|
887
|
+
`Missing ALB OIDC header: ${ALB_JWT_HEADER}`
|
|
888
|
+
);
|
|
805
889
|
}
|
|
806
890
|
if (accessToken === void 0) {
|
|
807
|
-
throw new errors.AuthenticationError(
|
|
891
|
+
throw new errors.AuthenticationError(
|
|
892
|
+
`Missing ALB OIDC header: ${ALB_ACCESS_TOKEN_HEADER}`
|
|
893
|
+
);
|
|
808
894
|
}
|
|
809
895
|
try {
|
|
810
896
|
const verifyResult = await jose.jwtVerify(jwt, this.getKey);
|
|
@@ -835,10 +921,13 @@ class AwsAlbAuthProvider {
|
|
|
835
921
|
}
|
|
836
922
|
async handleResult(result) {
|
|
837
923
|
const { profile } = await this.authHandler(result, this.resolverContext);
|
|
838
|
-
const backstageIdentity = await this.signInResolver(
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
924
|
+
const backstageIdentity = await this.signInResolver(
|
|
925
|
+
{
|
|
926
|
+
result,
|
|
927
|
+
profile
|
|
928
|
+
},
|
|
929
|
+
this.resolverContext
|
|
930
|
+
);
|
|
842
931
|
return {
|
|
843
932
|
providerInfo: {
|
|
844
933
|
accessToken: result.accessToken,
|
|
@@ -855,7 +944,9 @@ const awsAlb = createAuthProviderIntegration({
|
|
|
855
944
|
const region = config.getString("region");
|
|
856
945
|
const issuer = config.getOptionalString("iss");
|
|
857
946
|
if ((options == null ? void 0 : options.signIn.resolver) === void 0) {
|
|
858
|
-
throw new Error(
|
|
947
|
+
throw new Error(
|
|
948
|
+
"SignInResolver is required to use this authentication provider"
|
|
949
|
+
);
|
|
859
950
|
}
|
|
860
951
|
const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile }) => ({
|
|
861
952
|
profile: makeProfileInfo(fullProfile)
|
|
@@ -876,21 +967,28 @@ class BitbucketAuthProvider {
|
|
|
876
967
|
this.signInResolver = options.signInResolver;
|
|
877
968
|
this.authHandler = options.authHandler;
|
|
878
969
|
this.resolverContext = options.resolverContext;
|
|
879
|
-
this._strategy = new passportBitbucketOauth2.Strategy(
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
970
|
+
this._strategy = new passportBitbucketOauth2.Strategy(
|
|
971
|
+
{
|
|
972
|
+
clientID: options.clientId,
|
|
973
|
+
clientSecret: options.clientSecret,
|
|
974
|
+
callbackURL: options.callbackUrl,
|
|
975
|
+
passReqToCallback: false
|
|
976
|
+
},
|
|
977
|
+
(accessToken, refreshToken, params, fullProfile, done) => {
|
|
978
|
+
done(
|
|
979
|
+
void 0,
|
|
980
|
+
{
|
|
981
|
+
fullProfile,
|
|
982
|
+
params,
|
|
983
|
+
accessToken,
|
|
984
|
+
refreshToken
|
|
985
|
+
},
|
|
986
|
+
{
|
|
987
|
+
refreshToken
|
|
988
|
+
}
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
);
|
|
894
992
|
}
|
|
895
993
|
async start(req) {
|
|
896
994
|
return await executeRedirectStrategy(req, this._strategy, {
|
|
@@ -908,8 +1006,15 @@ class BitbucketAuthProvider {
|
|
|
908
1006
|
};
|
|
909
1007
|
}
|
|
910
1008
|
async refresh(req) {
|
|
911
|
-
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
912
|
-
|
|
1009
|
+
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
1010
|
+
this._strategy,
|
|
1011
|
+
req.refreshToken,
|
|
1012
|
+
req.scope
|
|
1013
|
+
);
|
|
1014
|
+
const fullProfile = await executeFetchUserProfileStrategy(
|
|
1015
|
+
this._strategy,
|
|
1016
|
+
accessToken
|
|
1017
|
+
);
|
|
913
1018
|
return {
|
|
914
1019
|
response: await this.handleResult({
|
|
915
1020
|
fullProfile,
|
|
@@ -932,10 +1037,13 @@ class BitbucketAuthProvider {
|
|
|
932
1037
|
profile
|
|
933
1038
|
};
|
|
934
1039
|
if (this.signInResolver) {
|
|
935
|
-
response.backstageIdentity = await this.signInResolver(
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1040
|
+
response.backstageIdentity = await this.signInResolver(
|
|
1041
|
+
{
|
|
1042
|
+
result,
|
|
1043
|
+
profile
|
|
1044
|
+
},
|
|
1045
|
+
this.resolverContext
|
|
1046
|
+
);
|
|
939
1047
|
}
|
|
940
1048
|
return response;
|
|
941
1049
|
}
|
|
@@ -1026,7 +1134,11 @@ class CloudflareAccessAuthProvider {
|
|
|
1026
1134
|
this.authHandler = options.authHandler;
|
|
1027
1135
|
this.signInResolver = options.signInResolver;
|
|
1028
1136
|
this.resolverContext = options.resolverContext;
|
|
1029
|
-
this.jwtKeySet = jose.createRemoteJWKSet(
|
|
1137
|
+
this.jwtKeySet = jose.createRemoteJWKSet(
|
|
1138
|
+
new URL(
|
|
1139
|
+
`https://${this.teamName}.cloudflareaccess.com/cdn-cgi/access/certs`
|
|
1140
|
+
)
|
|
1141
|
+
);
|
|
1030
1142
|
this.cache = options.cache;
|
|
1031
1143
|
}
|
|
1032
1144
|
frameHandler() {
|
|
@@ -1045,7 +1157,10 @@ class CloudflareAccessAuthProvider {
|
|
|
1045
1157
|
headers.set(CF_JWT_HEADER, jwt);
|
|
1046
1158
|
headers.set("cookie", `${COOKIE_AUTH_NAME}=${jwt}`);
|
|
1047
1159
|
try {
|
|
1048
|
-
const res = await fetch__default["default"](
|
|
1160
|
+
const res = await fetch__default["default"](
|
|
1161
|
+
`https://${this.teamName}.cloudflareaccess.com/cdn-cgi/access/get-identity`,
|
|
1162
|
+
{ headers }
|
|
1163
|
+
);
|
|
1049
1164
|
if (!res.ok) {
|
|
1050
1165
|
throw errors.ResponseError.fromResponse(res);
|
|
1051
1166
|
}
|
|
@@ -1062,7 +1177,9 @@ class CloudflareAccessAuthProvider {
|
|
|
1062
1177
|
jwt = req.cookies.CF_Authorization;
|
|
1063
1178
|
}
|
|
1064
1179
|
if (!jwt) {
|
|
1065
|
-
throw new errors.AuthenticationError(
|
|
1180
|
+
throw new errors.AuthenticationError(
|
|
1181
|
+
`Missing ${CF_JWT_HEADER} from Cloudflare Access`
|
|
1182
|
+
);
|
|
1066
1183
|
}
|
|
1067
1184
|
const verifyResult = await jose.jwtVerify(jwt, this.jwtKeySet, {
|
|
1068
1185
|
issuer: `https://${this.teamName}.cloudflareaccess.com`
|
|
@@ -1083,15 +1200,21 @@ class CloudflareAccessAuthProvider {
|
|
|
1083
1200
|
(_b = this.cache) == null ? void 0 : _b.set(`${CACHE_PREFIX}/${sub}`, JSON.stringify(cfAccessResult));
|
|
1084
1201
|
return cfAccessResult;
|
|
1085
1202
|
} catch (err) {
|
|
1086
|
-
throw new errors.ForwardedError(
|
|
1203
|
+
throw new errors.ForwardedError(
|
|
1204
|
+
"Failed to populate access identity information",
|
|
1205
|
+
err
|
|
1206
|
+
);
|
|
1087
1207
|
}
|
|
1088
1208
|
}
|
|
1089
1209
|
async handleResult(result) {
|
|
1090
1210
|
const { profile } = await this.authHandler(result, this.resolverContext);
|
|
1091
|
-
const backstageIdentity = await this.signInResolver(
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1211
|
+
const backstageIdentity = await this.signInResolver(
|
|
1212
|
+
{
|
|
1213
|
+
result,
|
|
1214
|
+
profile
|
|
1215
|
+
},
|
|
1216
|
+
this.resolverContext
|
|
1217
|
+
);
|
|
1095
1218
|
return {
|
|
1096
1219
|
providerInfo: {
|
|
1097
1220
|
expiresInSeconds: result.expiresInSeconds,
|
|
@@ -1108,7 +1231,9 @@ const cfAccess = createAuthProviderIntegration({
|
|
|
1108
1231
|
return ({ config, resolverContext }) => {
|
|
1109
1232
|
const teamName = config.getString("teamName");
|
|
1110
1233
|
if (!options.signIn.resolver) {
|
|
1111
|
-
throw new Error(
|
|
1234
|
+
throw new Error(
|
|
1235
|
+
"SignInResolver is required to use this authentication provider"
|
|
1236
|
+
);
|
|
1112
1237
|
}
|
|
1113
1238
|
const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ claims, cfIdentity }) => {
|
|
1114
1239
|
return {
|
|
@@ -1138,7 +1263,12 @@ function createTokenValidator(audience, mockClient) {
|
|
|
1138
1263
|
const client = mockClient != null ? mockClient : new googleAuthLibrary.OAuth2Client();
|
|
1139
1264
|
return async function tokenValidator(token) {
|
|
1140
1265
|
const response = await client.getIapPublicKeys();
|
|
1141
|
-
const ticket = await client.verifySignedJwtWithCertsAsync(
|
|
1266
|
+
const ticket = await client.verifySignedJwtWithCertsAsync(
|
|
1267
|
+
token,
|
|
1268
|
+
response.pubkeys,
|
|
1269
|
+
audience,
|
|
1270
|
+
["https://cloud.google.com/iap"]
|
|
1271
|
+
);
|
|
1142
1272
|
const payload = ticket.getPayload();
|
|
1143
1273
|
if (!payload) {
|
|
1144
1274
|
throw new TypeError("Token had no payload");
|
|
@@ -1148,7 +1278,9 @@ function createTokenValidator(audience, mockClient) {
|
|
|
1148
1278
|
}
|
|
1149
1279
|
async function parseRequestToken(jwtToken, tokenValidator) {
|
|
1150
1280
|
if (typeof jwtToken !== "string" || !jwtToken) {
|
|
1151
|
-
throw new errors.AuthenticationError(
|
|
1281
|
+
throw new errors.AuthenticationError(
|
|
1282
|
+
`Missing Google IAP header: ${IAP_JWT_HEADER}`
|
|
1283
|
+
);
|
|
1152
1284
|
}
|
|
1153
1285
|
let payload;
|
|
1154
1286
|
try {
|
|
@@ -1157,7 +1289,9 @@ async function parseRequestToken(jwtToken, tokenValidator) {
|
|
|
1157
1289
|
throw new errors.AuthenticationError(`Google IAP token verification failed, ${e}`);
|
|
1158
1290
|
}
|
|
1159
1291
|
if (!payload.sub || !payload.email) {
|
|
1160
|
-
throw new errors.AuthenticationError(
|
|
1292
|
+
throw new errors.AuthenticationError(
|
|
1293
|
+
"Google IAP token payload is missing sub and/or email claim"
|
|
1294
|
+
);
|
|
1161
1295
|
}
|
|
1162
1296
|
return {
|
|
1163
1297
|
iapToken: {
|
|
@@ -1183,9 +1317,15 @@ class GcpIapProvider {
|
|
|
1183
1317
|
async frameHandler() {
|
|
1184
1318
|
}
|
|
1185
1319
|
async refresh(req, res) {
|
|
1186
|
-
const result = await parseRequestToken(
|
|
1320
|
+
const result = await parseRequestToken(
|
|
1321
|
+
req.header(IAP_JWT_HEADER),
|
|
1322
|
+
this.tokenValidator
|
|
1323
|
+
);
|
|
1187
1324
|
const { profile } = await this.authHandler(result, this.resolverContext);
|
|
1188
|
-
const backstageIdentity = await this.signInResolver(
|
|
1325
|
+
const backstageIdentity = await this.signInResolver(
|
|
1326
|
+
{ profile, result },
|
|
1327
|
+
this.resolverContext
|
|
1328
|
+
);
|
|
1189
1329
|
const response = {
|
|
1190
1330
|
providerInfo: { iapToken: result.iapToken },
|
|
1191
1331
|
profile,
|
|
@@ -1220,16 +1360,19 @@ class GithubAuthProvider {
|
|
|
1220
1360
|
this.authHandler = options.authHandler;
|
|
1221
1361
|
this.stateEncoder = options.stateEncoder;
|
|
1222
1362
|
this.resolverContext = options.resolverContext;
|
|
1223
|
-
this._strategy = new passportGithub2.Strategy(
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1363
|
+
this._strategy = new passportGithub2.Strategy(
|
|
1364
|
+
{
|
|
1365
|
+
clientID: options.clientId,
|
|
1366
|
+
clientSecret: options.clientSecret,
|
|
1367
|
+
callbackURL: options.callbackUrl,
|
|
1368
|
+
tokenURL: options.tokenUrl,
|
|
1369
|
+
userProfileURL: options.userProfileUrl,
|
|
1370
|
+
authorizationURL: options.authorizationUrl
|
|
1371
|
+
},
|
|
1372
|
+
(accessToken, refreshToken, params, fullProfile, done) => {
|
|
1373
|
+
done(void 0, { fullProfile, params, accessToken }, { refreshToken });
|
|
1374
|
+
}
|
|
1375
|
+
);
|
|
1233
1376
|
}
|
|
1234
1377
|
async start(req) {
|
|
1235
1378
|
return await executeRedirectStrategy(req, this._strategy, {
|
|
@@ -1252,7 +1395,10 @@ class GithubAuthProvider {
|
|
|
1252
1395
|
const { scope, refreshToken } = req;
|
|
1253
1396
|
if (refreshToken == null ? void 0 : refreshToken.startsWith(ACCESS_TOKEN_PREFIX)) {
|
|
1254
1397
|
const accessToken = refreshToken.slice(ACCESS_TOKEN_PREFIX.length);
|
|
1255
|
-
const fullProfile = await executeFetchUserProfileStrategy(
|
|
1398
|
+
const fullProfile = await executeFetchUserProfileStrategy(
|
|
1399
|
+
this._strategy,
|
|
1400
|
+
accessToken
|
|
1401
|
+
).catch((error) => {
|
|
1256
1402
|
var _a;
|
|
1257
1403
|
if (((_a = error.oauthError) == null ? void 0 : _a.statusCode) === 401) {
|
|
1258
1404
|
throw new Error("Invalid access token");
|
|
@@ -1268,10 +1414,17 @@ class GithubAuthProvider {
|
|
|
1268
1414
|
refreshToken
|
|
1269
1415
|
};
|
|
1270
1416
|
}
|
|
1271
|
-
const result = await executeRefreshTokenStrategy(
|
|
1417
|
+
const result = await executeRefreshTokenStrategy(
|
|
1418
|
+
this._strategy,
|
|
1419
|
+
refreshToken,
|
|
1420
|
+
scope
|
|
1421
|
+
);
|
|
1272
1422
|
return {
|
|
1273
1423
|
response: await this.handleResult({
|
|
1274
|
-
fullProfile: await executeFetchUserProfileStrategy(
|
|
1424
|
+
fullProfile: await executeFetchUserProfileStrategy(
|
|
1425
|
+
this._strategy,
|
|
1426
|
+
result.accessToken
|
|
1427
|
+
),
|
|
1275
1428
|
params: { ...result.params, scope },
|
|
1276
1429
|
accessToken: result.accessToken
|
|
1277
1430
|
}),
|
|
@@ -1284,12 +1437,18 @@ class GithubAuthProvider {
|
|
|
1284
1437
|
let expiresInSeconds = expiresInStr === void 0 ? void 0 : Number(expiresInStr);
|
|
1285
1438
|
let backstageIdentity = void 0;
|
|
1286
1439
|
if (this.signInResolver) {
|
|
1287
|
-
backstageIdentity = await this.signInResolver(
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1440
|
+
backstageIdentity = await this.signInResolver(
|
|
1441
|
+
{
|
|
1442
|
+
result,
|
|
1443
|
+
profile
|
|
1444
|
+
},
|
|
1445
|
+
this.resolverContext
|
|
1446
|
+
);
|
|
1291
1447
|
if (expiresInSeconds) {
|
|
1292
|
-
expiresInSeconds = Math.min(
|
|
1448
|
+
expiresInSeconds = Math.min(
|
|
1449
|
+
expiresInSeconds,
|
|
1450
|
+
BACKSTAGE_SESSION_EXPIRATION
|
|
1451
|
+
);
|
|
1293
1452
|
} else {
|
|
1294
1453
|
expiresInSeconds = BACKSTAGE_SESSION_EXPIRATION;
|
|
1295
1454
|
}
|
|
@@ -1367,16 +1526,23 @@ class GitlabAuthProvider {
|
|
|
1367
1526
|
this.resolverContext = options.resolverContext;
|
|
1368
1527
|
this.authHandler = options.authHandler;
|
|
1369
1528
|
this.signInResolver = options.signInResolver;
|
|
1370
|
-
this._strategy = new passportGitlab2.Strategy(
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1529
|
+
this._strategy = new passportGitlab2.Strategy(
|
|
1530
|
+
{
|
|
1531
|
+
clientID: options.clientId,
|
|
1532
|
+
clientSecret: options.clientSecret,
|
|
1533
|
+
callbackURL: options.callbackUrl,
|
|
1534
|
+
baseURL: options.baseUrl
|
|
1535
|
+
},
|
|
1536
|
+
(accessToken, refreshToken, params, fullProfile, done) => {
|
|
1537
|
+
done(
|
|
1538
|
+
void 0,
|
|
1539
|
+
{ fullProfile, params, accessToken },
|
|
1540
|
+
{
|
|
1541
|
+
refreshToken
|
|
1542
|
+
}
|
|
1543
|
+
);
|
|
1544
|
+
}
|
|
1545
|
+
);
|
|
1380
1546
|
}
|
|
1381
1547
|
async start(req) {
|
|
1382
1548
|
return await executeRedirectStrategy(req, this._strategy, {
|
|
@@ -1392,8 +1558,15 @@ class GitlabAuthProvider {
|
|
|
1392
1558
|
};
|
|
1393
1559
|
}
|
|
1394
1560
|
async refresh(req) {
|
|
1395
|
-
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
1396
|
-
|
|
1561
|
+
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
1562
|
+
this._strategy,
|
|
1563
|
+
req.refreshToken,
|
|
1564
|
+
req.scope
|
|
1565
|
+
);
|
|
1566
|
+
const fullProfile = await executeFetchUserProfileStrategy(
|
|
1567
|
+
this._strategy,
|
|
1568
|
+
accessToken
|
|
1569
|
+
);
|
|
1397
1570
|
return {
|
|
1398
1571
|
response: await this.handleResult({
|
|
1399
1572
|
fullProfile,
|
|
@@ -1415,10 +1588,13 @@ class GitlabAuthProvider {
|
|
|
1415
1588
|
profile
|
|
1416
1589
|
};
|
|
1417
1590
|
if (this.signInResolver) {
|
|
1418
|
-
response.backstageIdentity = await this.signInResolver(
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1591
|
+
response.backstageIdentity = await this.signInResolver(
|
|
1592
|
+
{
|
|
1593
|
+
result,
|
|
1594
|
+
profile
|
|
1595
|
+
},
|
|
1596
|
+
this.resolverContext
|
|
1597
|
+
);
|
|
1422
1598
|
}
|
|
1423
1599
|
return response;
|
|
1424
1600
|
}
|
|
@@ -1456,21 +1632,28 @@ class GoogleAuthProvider {
|
|
|
1456
1632
|
this.authHandler = options.authHandler;
|
|
1457
1633
|
this.signInResolver = options.signInResolver;
|
|
1458
1634
|
this.resolverContext = options.resolverContext;
|
|
1459
|
-
this.strategy = new passportGoogleOauth20.Strategy(
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1635
|
+
this.strategy = new passportGoogleOauth20.Strategy(
|
|
1636
|
+
{
|
|
1637
|
+
clientID: options.clientId,
|
|
1638
|
+
clientSecret: options.clientSecret,
|
|
1639
|
+
callbackURL: options.callbackUrl,
|
|
1640
|
+
passReqToCallback: false
|
|
1641
|
+
},
|
|
1642
|
+
(accessToken, refreshToken, params, fullProfile, done) => {
|
|
1643
|
+
done(
|
|
1644
|
+
void 0,
|
|
1645
|
+
{
|
|
1646
|
+
fullProfile,
|
|
1647
|
+
params,
|
|
1648
|
+
accessToken,
|
|
1649
|
+
refreshToken
|
|
1650
|
+
},
|
|
1651
|
+
{
|
|
1652
|
+
refreshToken
|
|
1653
|
+
}
|
|
1654
|
+
);
|
|
1655
|
+
}
|
|
1656
|
+
);
|
|
1474
1657
|
}
|
|
1475
1658
|
async start(req) {
|
|
1476
1659
|
return await executeRedirectStrategy(req, this.strategy, {
|
|
@@ -1488,8 +1671,15 @@ class GoogleAuthProvider {
|
|
|
1488
1671
|
};
|
|
1489
1672
|
}
|
|
1490
1673
|
async refresh(req) {
|
|
1491
|
-
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
1492
|
-
|
|
1674
|
+
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
1675
|
+
this.strategy,
|
|
1676
|
+
req.refreshToken,
|
|
1677
|
+
req.scope
|
|
1678
|
+
);
|
|
1679
|
+
const fullProfile = await executeFetchUserProfileStrategy(
|
|
1680
|
+
this.strategy,
|
|
1681
|
+
accessToken
|
|
1682
|
+
);
|
|
1493
1683
|
return {
|
|
1494
1684
|
response: await this.handleResult({
|
|
1495
1685
|
fullProfile,
|
|
@@ -1511,10 +1701,13 @@ class GoogleAuthProvider {
|
|
|
1511
1701
|
profile
|
|
1512
1702
|
};
|
|
1513
1703
|
if (this.signInResolver) {
|
|
1514
|
-
response.backstageIdentity = await this.signInResolver(
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1704
|
+
response.backstageIdentity = await this.signInResolver(
|
|
1705
|
+
{
|
|
1706
|
+
result,
|
|
1707
|
+
profile
|
|
1708
|
+
},
|
|
1709
|
+
this.resolverContext
|
|
1710
|
+
);
|
|
1518
1711
|
}
|
|
1519
1712
|
return response;
|
|
1520
1713
|
}
|
|
@@ -1569,16 +1762,19 @@ class MicrosoftAuthProvider {
|
|
|
1569
1762
|
this.authHandler = options.authHandler;
|
|
1570
1763
|
this.logger = options.logger;
|
|
1571
1764
|
this.resolverContext = options.resolverContext;
|
|
1572
|
-
this._strategy = new passportMicrosoft.Strategy(
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1765
|
+
this._strategy = new passportMicrosoft.Strategy(
|
|
1766
|
+
{
|
|
1767
|
+
clientID: options.clientId,
|
|
1768
|
+
clientSecret: options.clientSecret,
|
|
1769
|
+
callbackURL: options.callbackUrl,
|
|
1770
|
+
authorizationURL: options.authorizationUrl,
|
|
1771
|
+
tokenURL: options.tokenUrl,
|
|
1772
|
+
passReqToCallback: false
|
|
1773
|
+
},
|
|
1774
|
+
(accessToken, refreshToken, params, fullProfile, done) => {
|
|
1775
|
+
done(void 0, { fullProfile, accessToken, params }, { refreshToken });
|
|
1776
|
+
}
|
|
1777
|
+
);
|
|
1582
1778
|
}
|
|
1583
1779
|
async start(req) {
|
|
1584
1780
|
return await executeRedirectStrategy(req, this._strategy, {
|
|
@@ -1594,8 +1790,15 @@ class MicrosoftAuthProvider {
|
|
|
1594
1790
|
};
|
|
1595
1791
|
}
|
|
1596
1792
|
async refresh(req) {
|
|
1597
|
-
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
1598
|
-
|
|
1793
|
+
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
1794
|
+
this._strategy,
|
|
1795
|
+
req.refreshToken,
|
|
1796
|
+
req.scope
|
|
1797
|
+
);
|
|
1798
|
+
const fullProfile = await executeFetchUserProfileStrategy(
|
|
1799
|
+
this._strategy,
|
|
1800
|
+
accessToken
|
|
1801
|
+
);
|
|
1599
1802
|
return {
|
|
1600
1803
|
response: await this.handleResult({
|
|
1601
1804
|
fullProfile,
|
|
@@ -1619,24 +1822,32 @@ class MicrosoftAuthProvider {
|
|
|
1619
1822
|
profile
|
|
1620
1823
|
};
|
|
1621
1824
|
if (this.signInResolver) {
|
|
1622
|
-
response.backstageIdentity = await this.signInResolver(
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1825
|
+
response.backstageIdentity = await this.signInResolver(
|
|
1826
|
+
{
|
|
1827
|
+
result,
|
|
1828
|
+
profile
|
|
1829
|
+
},
|
|
1830
|
+
this.resolverContext
|
|
1831
|
+
);
|
|
1626
1832
|
}
|
|
1627
1833
|
return response;
|
|
1628
1834
|
}
|
|
1629
1835
|
async getUserPhoto(accessToken) {
|
|
1630
1836
|
try {
|
|
1631
|
-
const res = await fetch__default["default"](
|
|
1632
|
-
|
|
1633
|
-
|
|
1837
|
+
const res = await fetch__default["default"](
|
|
1838
|
+
"https://graph.microsoft.com/v1.0/me/photos/48x48/$value",
|
|
1839
|
+
{
|
|
1840
|
+
headers: {
|
|
1841
|
+
Authorization: `Bearer ${accessToken}`
|
|
1842
|
+
}
|
|
1634
1843
|
}
|
|
1635
|
-
|
|
1844
|
+
);
|
|
1636
1845
|
const data = await res.buffer();
|
|
1637
1846
|
return `data:image/jpeg;base64,${data.toString("base64")}`;
|
|
1638
1847
|
} catch (error) {
|
|
1639
|
-
this.logger.warn(
|
|
1848
|
+
this.logger.warn(
|
|
1849
|
+
`Could not retrieve user profile photo from Microsoft Graph API: ${error}`
|
|
1850
|
+
);
|
|
1640
1851
|
return void 0;
|
|
1641
1852
|
}
|
|
1642
1853
|
}
|
|
@@ -1698,27 +1909,37 @@ class OAuth2AuthProvider {
|
|
|
1698
1909
|
this.authHandler = options.authHandler;
|
|
1699
1910
|
this.resolverContext = options.resolverContext;
|
|
1700
1911
|
this.disableRefresh = (_a = options.disableRefresh) != null ? _a : false;
|
|
1701
|
-
this._strategy = new OAuth2Strategy.Strategy(
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1912
|
+
this._strategy = new OAuth2Strategy.Strategy(
|
|
1913
|
+
{
|
|
1914
|
+
clientID: options.clientId,
|
|
1915
|
+
clientSecret: options.clientSecret,
|
|
1916
|
+
callbackURL: options.callbackUrl,
|
|
1917
|
+
authorizationURL: options.authorizationUrl,
|
|
1918
|
+
tokenURL: options.tokenUrl,
|
|
1919
|
+
passReqToCallback: false,
|
|
1920
|
+
scope: options.scope,
|
|
1921
|
+
customHeaders: options.includeBasicAuth ? {
|
|
1922
|
+
Authorization: `Basic ${this.encodeClientCredentials(
|
|
1923
|
+
options.clientId,
|
|
1924
|
+
options.clientSecret
|
|
1925
|
+
)}`
|
|
1926
|
+
} : void 0
|
|
1927
|
+
},
|
|
1928
|
+
(accessToken, refreshToken, params, fullProfile, done) => {
|
|
1929
|
+
done(
|
|
1930
|
+
void 0,
|
|
1931
|
+
{
|
|
1932
|
+
fullProfile,
|
|
1933
|
+
accessToken,
|
|
1934
|
+
refreshToken,
|
|
1935
|
+
params
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
refreshToken
|
|
1939
|
+
}
|
|
1940
|
+
);
|
|
1941
|
+
}
|
|
1942
|
+
);
|
|
1722
1943
|
}
|
|
1723
1944
|
async start(req) {
|
|
1724
1945
|
return await executeRedirectStrategy(req, this._strategy, {
|
|
@@ -1739,9 +1960,16 @@ class OAuth2AuthProvider {
|
|
|
1739
1960
|
if (this.disableRefresh) {
|
|
1740
1961
|
throw new errors.InputError("Session refreshes have been disabled");
|
|
1741
1962
|
}
|
|
1742
|
-
const refreshTokenResponse = await executeRefreshTokenStrategy(
|
|
1963
|
+
const refreshTokenResponse = await executeRefreshTokenStrategy(
|
|
1964
|
+
this._strategy,
|
|
1965
|
+
req.refreshToken,
|
|
1966
|
+
req.scope
|
|
1967
|
+
);
|
|
1743
1968
|
const { accessToken, params, refreshToken } = refreshTokenResponse;
|
|
1744
|
-
const fullProfile = await executeFetchUserProfileStrategy(
|
|
1969
|
+
const fullProfile = await executeFetchUserProfileStrategy(
|
|
1970
|
+
this._strategy,
|
|
1971
|
+
accessToken
|
|
1972
|
+
);
|
|
1745
1973
|
return {
|
|
1746
1974
|
response: await this.handleResult({
|
|
1747
1975
|
fullProfile,
|
|
@@ -1763,10 +1991,13 @@ class OAuth2AuthProvider {
|
|
|
1763
1991
|
profile
|
|
1764
1992
|
};
|
|
1765
1993
|
if (this.signInResolver) {
|
|
1766
|
-
response.backstageIdentity = await this.signInResolver(
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1994
|
+
response.backstageIdentity = await this.signInResolver(
|
|
1995
|
+
{
|
|
1996
|
+
result,
|
|
1997
|
+
profile
|
|
1998
|
+
},
|
|
1999
|
+
this.resolverContext
|
|
2000
|
+
);
|
|
1770
2001
|
}
|
|
1771
2002
|
return response;
|
|
1772
2003
|
}
|
|
@@ -1848,15 +2079,20 @@ class Oauth2ProxyAuthProvider {
|
|
|
1848
2079
|
}
|
|
1849
2080
|
async handleResult(result) {
|
|
1850
2081
|
const { profile } = await this.authHandler(result, this.resolverContext);
|
|
1851
|
-
const backstageSignInResult = await this.signInResolver(
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
2082
|
+
const backstageSignInResult = await this.signInResolver(
|
|
2083
|
+
{
|
|
2084
|
+
result,
|
|
2085
|
+
profile
|
|
2086
|
+
},
|
|
2087
|
+
this.resolverContext
|
|
2088
|
+
);
|
|
1855
2089
|
return {
|
|
1856
2090
|
providerInfo: {
|
|
1857
2091
|
accessToken: result.accessToken
|
|
1858
2092
|
},
|
|
1859
|
-
backstageIdentity: prepareBackstageIdentityResponse(
|
|
2093
|
+
backstageIdentity: prepareBackstageIdentityResponse(
|
|
2094
|
+
backstageSignInResult
|
|
2095
|
+
),
|
|
1860
2096
|
profile
|
|
1861
2097
|
};
|
|
1862
2098
|
}
|
|
@@ -1935,17 +2171,26 @@ class OidcAuthProvider {
|
|
|
1935
2171
|
id_token_signed_response_alg: options.tokenSignedResponseAlg || "RS256",
|
|
1936
2172
|
scope: options.scope || ""
|
|
1937
2173
|
});
|
|
1938
|
-
const strategy = new openidClient.Strategy(
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
2174
|
+
const strategy = new openidClient.Strategy(
|
|
2175
|
+
{
|
|
2176
|
+
client,
|
|
2177
|
+
passReqToCallback: false
|
|
2178
|
+
},
|
|
2179
|
+
(tokenset, userinfo, done) => {
|
|
2180
|
+
if (typeof done !== "function") {
|
|
2181
|
+
throw new Error(
|
|
2182
|
+
"OIDC IdP must provide a userinfo_endpoint in the metadata response"
|
|
2183
|
+
);
|
|
2184
|
+
}
|
|
2185
|
+
done(
|
|
2186
|
+
void 0,
|
|
2187
|
+
{ tokenset, userinfo },
|
|
2188
|
+
{
|
|
2189
|
+
refreshToken: tokenset.refresh_token
|
|
2190
|
+
}
|
|
2191
|
+
);
|
|
1944
2192
|
}
|
|
1945
|
-
|
|
1946
|
-
refreshToken: tokenset.refresh_token
|
|
1947
|
-
});
|
|
1948
|
-
});
|
|
2193
|
+
);
|
|
1949
2194
|
strategy.error = console.error;
|
|
1950
2195
|
return { strategy, client };
|
|
1951
2196
|
}
|
|
@@ -1961,10 +2206,13 @@ class OidcAuthProvider {
|
|
|
1961
2206
|
profile
|
|
1962
2207
|
};
|
|
1963
2208
|
if (this.signInResolver) {
|
|
1964
|
-
response.backstageIdentity = await this.signInResolver(
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
2209
|
+
response.backstageIdentity = await this.signInResolver(
|
|
2210
|
+
{
|
|
2211
|
+
result,
|
|
2212
|
+
profile
|
|
2213
|
+
},
|
|
2214
|
+
this.resolverContext
|
|
2215
|
+
);
|
|
1968
2216
|
}
|
|
1969
2217
|
return response;
|
|
1970
2218
|
}
|
|
@@ -1978,7 +2226,9 @@ const oidc = createAuthProviderIntegration({
|
|
|
1978
2226
|
const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
|
|
1979
2227
|
const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
|
|
1980
2228
|
const metadataUrl = envConfig.getString("metadataUrl");
|
|
1981
|
-
const tokenSignedResponseAlg = envConfig.getOptionalString(
|
|
2229
|
+
const tokenSignedResponseAlg = envConfig.getOptionalString(
|
|
2230
|
+
"tokenSignedResponseAlg"
|
|
2231
|
+
);
|
|
1982
2232
|
const scope = envConfig.getOptionalString("scope");
|
|
1983
2233
|
const prompt = envConfig.getOptionalString("prompt");
|
|
1984
2234
|
const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ userinfo }) => ({
|
|
@@ -2021,26 +2271,33 @@ class OktaAuthProvider {
|
|
|
2021
2271
|
this.signInResolver = options.signInResolver;
|
|
2022
2272
|
this.authHandler = options.authHandler;
|
|
2023
2273
|
this.resolverContext = options.resolverContext;
|
|
2024
|
-
this.strategy = new passportOktaOauth.Strategy(
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2274
|
+
this.strategy = new passportOktaOauth.Strategy(
|
|
2275
|
+
{
|
|
2276
|
+
clientID: options.clientId,
|
|
2277
|
+
clientSecret: options.clientSecret,
|
|
2278
|
+
callbackURL: options.callbackUrl,
|
|
2279
|
+
audience: options.audience,
|
|
2280
|
+
authServerID: options.authServerId,
|
|
2281
|
+
idp: options.idp,
|
|
2282
|
+
passReqToCallback: false,
|
|
2283
|
+
store: this.store,
|
|
2284
|
+
response_type: "code"
|
|
2285
|
+
},
|
|
2286
|
+
(accessToken, refreshToken, params, fullProfile, done) => {
|
|
2287
|
+
done(
|
|
2288
|
+
void 0,
|
|
2289
|
+
{
|
|
2290
|
+
accessToken,
|
|
2291
|
+
refreshToken,
|
|
2292
|
+
params,
|
|
2293
|
+
fullProfile
|
|
2294
|
+
},
|
|
2295
|
+
{
|
|
2296
|
+
refreshToken
|
|
2297
|
+
}
|
|
2298
|
+
);
|
|
2299
|
+
}
|
|
2300
|
+
);
|
|
2044
2301
|
}
|
|
2045
2302
|
async start(req) {
|
|
2046
2303
|
return await executeRedirectStrategy(req, this.strategy, {
|
|
@@ -2058,8 +2315,15 @@ class OktaAuthProvider {
|
|
|
2058
2315
|
};
|
|
2059
2316
|
}
|
|
2060
2317
|
async refresh(req) {
|
|
2061
|
-
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
2062
|
-
|
|
2318
|
+
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
2319
|
+
this.strategy,
|
|
2320
|
+
req.refreshToken,
|
|
2321
|
+
req.scope
|
|
2322
|
+
);
|
|
2323
|
+
const fullProfile = await executeFetchUserProfileStrategy(
|
|
2324
|
+
this.strategy,
|
|
2325
|
+
accessToken
|
|
2326
|
+
);
|
|
2063
2327
|
return {
|
|
2064
2328
|
response: await this.handleResult({
|
|
2065
2329
|
fullProfile,
|
|
@@ -2081,10 +2345,13 @@ class OktaAuthProvider {
|
|
|
2081
2345
|
profile
|
|
2082
2346
|
};
|
|
2083
2347
|
if (this.signInResolver) {
|
|
2084
|
-
response.backstageIdentity = await this.signInResolver(
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2348
|
+
response.backstageIdentity = await this.signInResolver(
|
|
2349
|
+
{
|
|
2350
|
+
result,
|
|
2351
|
+
profile
|
|
2352
|
+
},
|
|
2353
|
+
this.resolverContext
|
|
2354
|
+
);
|
|
2088
2355
|
}
|
|
2089
2356
|
return response;
|
|
2090
2357
|
}
|
|
@@ -2147,22 +2414,29 @@ class OneLoginProvider {
|
|
|
2147
2414
|
this.signInResolver = options.signInResolver;
|
|
2148
2415
|
this.authHandler = options.authHandler;
|
|
2149
2416
|
this.resolverContext = options.resolverContext;
|
|
2150
|
-
this._strategy = new passportOneloginOauth.Strategy(
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2417
|
+
this._strategy = new passportOneloginOauth.Strategy(
|
|
2418
|
+
{
|
|
2419
|
+
issuer: options.issuer,
|
|
2420
|
+
clientID: options.clientId,
|
|
2421
|
+
clientSecret: options.clientSecret,
|
|
2422
|
+
callbackURL: options.callbackUrl,
|
|
2423
|
+
passReqToCallback: false
|
|
2424
|
+
},
|
|
2425
|
+
(accessToken, refreshToken, params, fullProfile, done) => {
|
|
2426
|
+
done(
|
|
2427
|
+
void 0,
|
|
2428
|
+
{
|
|
2429
|
+
accessToken,
|
|
2430
|
+
refreshToken,
|
|
2431
|
+
params,
|
|
2432
|
+
fullProfile
|
|
2433
|
+
},
|
|
2434
|
+
{
|
|
2435
|
+
refreshToken
|
|
2436
|
+
}
|
|
2437
|
+
);
|
|
2438
|
+
}
|
|
2439
|
+
);
|
|
2166
2440
|
}
|
|
2167
2441
|
async start(req) {
|
|
2168
2442
|
return await executeRedirectStrategy(req, this._strategy, {
|
|
@@ -2180,8 +2454,15 @@ class OneLoginProvider {
|
|
|
2180
2454
|
};
|
|
2181
2455
|
}
|
|
2182
2456
|
async refresh(req) {
|
|
2183
|
-
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
2184
|
-
|
|
2457
|
+
const { accessToken, refreshToken, params } = await executeRefreshTokenStrategy(
|
|
2458
|
+
this._strategy,
|
|
2459
|
+
req.refreshToken,
|
|
2460
|
+
req.scope
|
|
2461
|
+
);
|
|
2462
|
+
const fullProfile = await executeFetchUserProfileStrategy(
|
|
2463
|
+
this._strategy,
|
|
2464
|
+
accessToken
|
|
2465
|
+
);
|
|
2185
2466
|
return {
|
|
2186
2467
|
response: await this.handleResult({
|
|
2187
2468
|
fullProfile,
|
|
@@ -2203,10 +2484,13 @@ class OneLoginProvider {
|
|
|
2203
2484
|
profile
|
|
2204
2485
|
};
|
|
2205
2486
|
if (this.signInResolver) {
|
|
2206
|
-
response.backstageIdentity = await this.signInResolver(
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2487
|
+
response.backstageIdentity = await this.signInResolver(
|
|
2488
|
+
{
|
|
2489
|
+
result,
|
|
2490
|
+
profile
|
|
2491
|
+
},
|
|
2492
|
+
this.resolverContext
|
|
2493
|
+
);
|
|
2210
2494
|
}
|
|
2211
2495
|
return response;
|
|
2212
2496
|
}
|
|
@@ -2256,17 +2540,23 @@ class SamlAuthProvider {
|
|
|
2256
2540
|
}
|
|
2257
2541
|
async frameHandler(req, res) {
|
|
2258
2542
|
try {
|
|
2259
|
-
const { result } = await executeFrameHandlerStrategy(
|
|
2543
|
+
const { result } = await executeFrameHandlerStrategy(
|
|
2544
|
+
req,
|
|
2545
|
+
this.strategy
|
|
2546
|
+
);
|
|
2260
2547
|
const { profile } = await this.authHandler(result, this.resolverContext);
|
|
2261
2548
|
const response = {
|
|
2262
2549
|
profile,
|
|
2263
2550
|
providerInfo: {}
|
|
2264
2551
|
};
|
|
2265
2552
|
if (this.signInResolver) {
|
|
2266
|
-
const signInResponse = await this.signInResolver(
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2553
|
+
const signInResponse = await this.signInResolver(
|
|
2554
|
+
{
|
|
2555
|
+
result,
|
|
2556
|
+
profile
|
|
2557
|
+
},
|
|
2558
|
+
this.resolverContext
|
|
2559
|
+
);
|
|
2270
2560
|
response.backstageIdentity = prepareBackstageIdentityResponse(signInResponse);
|
|
2271
2561
|
}
|
|
2272
2562
|
return postMessageResponse(res, this.appUrl, {
|
|
@@ -2418,7 +2708,9 @@ class TokenFactory {
|
|
|
2418
2708
|
try {
|
|
2419
2709
|
catalogModel.parseEntityRef(sub);
|
|
2420
2710
|
} catch (error) {
|
|
2421
|
-
throw new Error(
|
|
2711
|
+
throw new Error(
|
|
2712
|
+
'"sub" claim provided by the auth resolver is not a valid EntityRef.'
|
|
2713
|
+
);
|
|
2422
2714
|
}
|
|
2423
2715
|
this.logger.info(`Issuing token for ${sub}, with entities ${ent != null ? ent : []}`);
|
|
2424
2716
|
if (!key.alg) {
|
|
@@ -2482,34 +2774,43 @@ class TokenFactory {
|
|
|
2482
2774
|
}
|
|
2483
2775
|
}
|
|
2484
2776
|
|
|
2485
|
-
const migrationsDir = backendCommon.resolvePackagePath(
|
|
2777
|
+
const migrationsDir = backendCommon.resolvePackagePath(
|
|
2778
|
+
"@backstage/plugin-auth-backend",
|
|
2779
|
+
"migrations"
|
|
2780
|
+
);
|
|
2486
2781
|
const TABLE = "signing_keys";
|
|
2487
2782
|
const parseDate = (date) => {
|
|
2488
2783
|
const parsedDate = typeof date === "string" ? luxon.DateTime.fromSQL(date, { zone: "UTC" }) : luxon.DateTime.fromJSDate(date);
|
|
2489
2784
|
if (!parsedDate.isValid) {
|
|
2490
|
-
throw new Error(
|
|
2785
|
+
throw new Error(
|
|
2786
|
+
`Failed to parse date, reason: ${parsedDate.invalidReason}, explanation: ${parsedDate.invalidExplanation}`
|
|
2787
|
+
);
|
|
2491
2788
|
}
|
|
2492
2789
|
return parsedDate.toJSDate();
|
|
2493
2790
|
};
|
|
2494
2791
|
class DatabaseKeyStore {
|
|
2495
2792
|
static async create(options) {
|
|
2793
|
+
var _a;
|
|
2496
2794
|
const { database } = options;
|
|
2497
|
-
await database.
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2795
|
+
const client = await database.getClient();
|
|
2796
|
+
if (!((_a = database.migrations) == null ? void 0 : _a.skip)) {
|
|
2797
|
+
await client.migrate.latest({
|
|
2798
|
+
directory: migrationsDir
|
|
2799
|
+
});
|
|
2800
|
+
}
|
|
2801
|
+
return new DatabaseKeyStore(client);
|
|
2501
2802
|
}
|
|
2502
|
-
constructor(
|
|
2503
|
-
this.
|
|
2803
|
+
constructor(client) {
|
|
2804
|
+
this.client = client;
|
|
2504
2805
|
}
|
|
2505
2806
|
async addKey(key) {
|
|
2506
|
-
await this.
|
|
2807
|
+
await this.client(TABLE).insert({
|
|
2507
2808
|
kid: key.kid,
|
|
2508
2809
|
key: JSON.stringify(key)
|
|
2509
2810
|
});
|
|
2510
2811
|
}
|
|
2511
2812
|
async listKeys() {
|
|
2512
|
-
const rows = await this.
|
|
2813
|
+
const rows = await this.client(TABLE).select();
|
|
2513
2814
|
return {
|
|
2514
2815
|
items: rows.map((row) => ({
|
|
2515
2816
|
key: JSON.parse(row.key),
|
|
@@ -2518,7 +2819,7 @@ class DatabaseKeyStore {
|
|
|
2518
2819
|
};
|
|
2519
2820
|
}
|
|
2520
2821
|
async removeKeys(kids) {
|
|
2521
|
-
await this.
|
|
2822
|
+
await this.client(TABLE).delete().whereIn("kid", kids);
|
|
2522
2823
|
}
|
|
2523
2824
|
}
|
|
2524
2825
|
|
|
@@ -2558,26 +2859,38 @@ class FirestoreKeyStore {
|
|
|
2558
2859
|
static async create(settings) {
|
|
2559
2860
|
const { path, timeout, ...firestoreSettings } = settings != null ? settings : {};
|
|
2560
2861
|
const database = new firestore.Firestore(firestoreSettings);
|
|
2561
|
-
return new FirestoreKeyStore(
|
|
2862
|
+
return new FirestoreKeyStore(
|
|
2863
|
+
database,
|
|
2864
|
+
path != null ? path : DEFAULT_DOCUMENT_PATH,
|
|
2865
|
+
timeout != null ? timeout : DEFAULT_TIMEOUT_MS
|
|
2866
|
+
);
|
|
2562
2867
|
}
|
|
2563
2868
|
static async verifyConnection(keyStore, logger) {
|
|
2564
2869
|
try {
|
|
2565
2870
|
await keyStore.verify();
|
|
2566
2871
|
} catch (error) {
|
|
2567
2872
|
if (process.env.NODE_ENV !== "development") {
|
|
2568
|
-
throw new Error(
|
|
2873
|
+
throw new Error(
|
|
2874
|
+
`Failed to connect to database: ${error.message}`
|
|
2875
|
+
);
|
|
2569
2876
|
}
|
|
2570
|
-
logger == null ? void 0 : logger.warn(
|
|
2877
|
+
logger == null ? void 0 : logger.warn(
|
|
2878
|
+
`Failed to connect to database: ${error.message}`
|
|
2879
|
+
);
|
|
2571
2880
|
}
|
|
2572
2881
|
}
|
|
2573
2882
|
async addKey(key) {
|
|
2574
|
-
await this.withTimeout(
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2883
|
+
await this.withTimeout(
|
|
2884
|
+
this.database.collection(this.path).doc(key.kid).set({
|
|
2885
|
+
kid: key.kid,
|
|
2886
|
+
key: JSON.stringify(key)
|
|
2887
|
+
})
|
|
2888
|
+
);
|
|
2578
2889
|
}
|
|
2579
2890
|
async listKeys() {
|
|
2580
|
-
const keys = await this.withTimeout(
|
|
2891
|
+
const keys = await this.withTimeout(
|
|
2892
|
+
this.database.collection(this.path).get()
|
|
2893
|
+
);
|
|
2581
2894
|
return {
|
|
2582
2895
|
items: keys.docs.map((key) => ({
|
|
2583
2896
|
key: key.data(),
|
|
@@ -2587,13 +2900,17 @@ class FirestoreKeyStore {
|
|
|
2587
2900
|
}
|
|
2588
2901
|
async removeKeys(kids) {
|
|
2589
2902
|
for (const kid of kids) {
|
|
2590
|
-
await this.withTimeout(
|
|
2903
|
+
await this.withTimeout(
|
|
2904
|
+
this.database.collection(this.path).doc(kid).delete()
|
|
2905
|
+
);
|
|
2591
2906
|
}
|
|
2592
2907
|
}
|
|
2593
2908
|
async withTimeout(operation) {
|
|
2594
|
-
const timer = new Promise(
|
|
2595
|
-
|
|
2596
|
-
|
|
2909
|
+
const timer = new Promise(
|
|
2910
|
+
(_, reject) => setTimeout(() => {
|
|
2911
|
+
reject(new Error(`Operation timed out after ${this.timeout}ms`));
|
|
2912
|
+
}, this.timeout)
|
|
2913
|
+
);
|
|
2597
2914
|
return Promise.race([operation, timer]);
|
|
2598
2915
|
}
|
|
2599
2916
|
async verify() {
|
|
@@ -2612,24 +2929,27 @@ class KeyStores {
|
|
|
2612
2929
|
if (!database) {
|
|
2613
2930
|
throw new Error("This KeyStore provider requires a database");
|
|
2614
2931
|
}
|
|
2615
|
-
return await DatabaseKeyStore.create({
|
|
2616
|
-
database: await database.getClient()
|
|
2617
|
-
});
|
|
2932
|
+
return await DatabaseKeyStore.create({ database });
|
|
2618
2933
|
}
|
|
2619
2934
|
if (provider === "memory") {
|
|
2620
2935
|
return new MemoryKeyStore();
|
|
2621
2936
|
}
|
|
2622
2937
|
if (provider === "firestore") {
|
|
2623
2938
|
const settings = ks == null ? void 0 : ks.getConfig(provider);
|
|
2624
|
-
const keyStore = await FirestoreKeyStore.create(
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2939
|
+
const keyStore = await FirestoreKeyStore.create(
|
|
2940
|
+
lodash.pickBy(
|
|
2941
|
+
{
|
|
2942
|
+
projectId: settings == null ? void 0 : settings.getOptionalString("projectId"),
|
|
2943
|
+
keyFilename: settings == null ? void 0 : settings.getOptionalString("keyFilename"),
|
|
2944
|
+
host: settings == null ? void 0 : settings.getOptionalString("host"),
|
|
2945
|
+
port: settings == null ? void 0 : settings.getOptionalNumber("port"),
|
|
2946
|
+
ssl: settings == null ? void 0 : settings.getOptionalBoolean("ssl"),
|
|
2947
|
+
path: settings == null ? void 0 : settings.getOptionalString("path"),
|
|
2948
|
+
timeout: settings == null ? void 0 : settings.getOptionalNumber("timeout")
|
|
2949
|
+
},
|
|
2950
|
+
(value) => value !== void 0
|
|
2951
|
+
)
|
|
2952
|
+
);
|
|
2633
2953
|
await FirestoreKeyStore.verifyConnection(keyStore, logger);
|
|
2634
2954
|
return keyStore;
|
|
2635
2955
|
}
|
|
@@ -2686,10 +3006,12 @@ class CatalogIdentityClient {
|
|
|
2686
3006
|
const missingEntityNames = resolvedEntityRefs.map(catalogModel.stringifyEntityRef).filter((s) => !foundEntityNames.includes(s));
|
|
2687
3007
|
logger == null ? void 0 : logger.debug(`Entities not found for refs ${missingEntityNames.join()}`);
|
|
2688
3008
|
}
|
|
2689
|
-
const memberOf = entities.flatMap(
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
3009
|
+
const memberOf = entities.flatMap(
|
|
3010
|
+
(e) => {
|
|
3011
|
+
var _a, _b;
|
|
3012
|
+
return (_b = (_a = e.relations) == null ? void 0 : _a.filter((r) => r.type === catalogModel.RELATION_MEMBER_OF).map((r) => r.targetRef)) != null ? _b : [];
|
|
3013
|
+
}
|
|
3014
|
+
);
|
|
2693
3015
|
const newEntityRefs = [
|
|
2694
3016
|
...new Set(resolvedEntityRefs.map(catalogModel.stringifyEntityRef).concat(memberOf))
|
|
2695
3017
|
];
|
|
@@ -2700,7 +3022,9 @@ class CatalogIdentityClient {
|
|
|
2700
3022
|
|
|
2701
3023
|
function getDefaultOwnershipEntityRefs(entity) {
|
|
2702
3024
|
var _a, _b;
|
|
2703
|
-
const membershipRefs = (_b = (_a = entity.relations) == null ? void 0 : _a.filter(
|
|
3025
|
+
const membershipRefs = (_b = (_a = entity.relations) == null ? void 0 : _a.filter(
|
|
3026
|
+
(r) => r.type === catalogModel.RELATION_MEMBER_OF && r.targetRef.startsWith("group:")
|
|
3027
|
+
).map((r) => r.targetRef)) != null ? _b : [];
|
|
2704
3028
|
return Array.from(/* @__PURE__ */ new Set([catalogModel.stringifyEntityRef(entity), ...membershipRefs]));
|
|
2705
3029
|
}
|
|
2706
3030
|
class CatalogAuthResolverContext {
|
|
@@ -2716,7 +3040,13 @@ class CatalogAuthResolverContext {
|
|
|
2716
3040
|
catalogApi: options.catalogApi,
|
|
2717
3041
|
tokenManager: options.tokenManager
|
|
2718
3042
|
});
|
|
2719
|
-
return new CatalogAuthResolverContext(
|
|
3043
|
+
return new CatalogAuthResolverContext(
|
|
3044
|
+
options.logger,
|
|
3045
|
+
options.tokenIssuer,
|
|
3046
|
+
catalogIdentityClient,
|
|
3047
|
+
options.catalogApi,
|
|
3048
|
+
options.tokenManager
|
|
3049
|
+
);
|
|
2720
3050
|
}
|
|
2721
3051
|
async issueToken(params) {
|
|
2722
3052
|
const token = await this.tokenIssuer.issueToken(params);
|
|
@@ -2741,7 +3071,10 @@ class CatalogAuthResolverContext {
|
|
|
2741
3071
|
const res = await this.catalogApi.getEntities({ filter }, { token });
|
|
2742
3072
|
result = res.items;
|
|
2743
3073
|
} else if ("filter" in query) {
|
|
2744
|
-
const res = await this.catalogApi.getEntities(
|
|
3074
|
+
const res = await this.catalogApi.getEntities(
|
|
3075
|
+
{ filter: query.filter },
|
|
3076
|
+
{ token }
|
|
3077
|
+
);
|
|
2745
3078
|
result = res.items;
|
|
2746
3079
|
} else {
|
|
2747
3080
|
throw new errors.InputError("Invalid user lookup query");
|
|
@@ -2797,12 +3130,14 @@ async function createRouter(options) {
|
|
|
2797
3130
|
if (secret) {
|
|
2798
3131
|
router.use(cookieParser__default["default"](secret));
|
|
2799
3132
|
const enforceCookieSSL = authUrl.startsWith("https");
|
|
2800
|
-
router.use(
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
3133
|
+
router.use(
|
|
3134
|
+
session__default["default"]({
|
|
3135
|
+
secret,
|
|
3136
|
+
saveUninitialized: false,
|
|
3137
|
+
resave: false,
|
|
3138
|
+
cookie: { secure: enforceCookieSSL ? "auto" : false }
|
|
3139
|
+
})
|
|
3140
|
+
);
|
|
2806
3141
|
router.use(passport__default["default"].initialize());
|
|
2807
3142
|
router.use(passport__default["default"].session());
|
|
2808
3143
|
} else {
|
|
@@ -2817,7 +3152,9 @@ async function createRouter(options) {
|
|
|
2817
3152
|
const providersConfig = config.getConfig("auth.providers");
|
|
2818
3153
|
const configuredProviders = providersConfig.keys();
|
|
2819
3154
|
const isOriginAllowed = createOriginFilter(config);
|
|
2820
|
-
for (const [providerId, providerFactory] of Object.entries(
|
|
3155
|
+
for (const [providerId, providerFactory] of Object.entries(
|
|
3156
|
+
allProviderFactories
|
|
3157
|
+
)) {
|
|
2821
3158
|
if (configuredProviders.includes(providerId)) {
|
|
2822
3159
|
logger.info(`Configuring provider, ${providerId}`);
|
|
2823
3160
|
try {
|
|
@@ -2852,23 +3189,31 @@ async function createRouter(options) {
|
|
|
2852
3189
|
} catch (e) {
|
|
2853
3190
|
errors.assertError(e);
|
|
2854
3191
|
if (process.env.NODE_ENV !== "development") {
|
|
2855
|
-
throw new Error(
|
|
3192
|
+
throw new Error(
|
|
3193
|
+
`Failed to initialize ${providerId} auth provider, ${e.message}`
|
|
3194
|
+
);
|
|
2856
3195
|
}
|
|
2857
3196
|
logger.warn(`Skipping ${providerId} auth provider, ${e.message}`);
|
|
2858
3197
|
router.use(`/${providerId}`, () => {
|
|
2859
|
-
throw new errors.NotFoundError(
|
|
3198
|
+
throw new errors.NotFoundError(
|
|
3199
|
+
`Auth provider registered for '${providerId}' is misconfigured. This could mean the configs under auth.providers.${providerId} are missing or the environment variables used are not defined. Check the auth backend plugin logs when the backend starts to see more details.`
|
|
3200
|
+
);
|
|
2860
3201
|
});
|
|
2861
3202
|
}
|
|
2862
3203
|
} else {
|
|
2863
3204
|
router.use(`/${providerId}`, () => {
|
|
2864
|
-
throw new errors.NotFoundError(
|
|
3205
|
+
throw new errors.NotFoundError(
|
|
3206
|
+
`No auth provider registered for '${providerId}'`
|
|
3207
|
+
);
|
|
2865
3208
|
});
|
|
2866
3209
|
}
|
|
2867
3210
|
}
|
|
2868
|
-
router.use(
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
3211
|
+
router.use(
|
|
3212
|
+
createOidcRouter({
|
|
3213
|
+
tokenIssuer,
|
|
3214
|
+
baseUrl: authUrl
|
|
3215
|
+
})
|
|
3216
|
+
);
|
|
2872
3217
|
router.use("/:provider/", (req) => {
|
|
2873
3218
|
const { provider } = req.params;
|
|
2874
3219
|
throw new errors.NotFoundError(`Unknown auth provider '${provider}'`);
|
|
@@ -2879,8 +3224,12 @@ function createOriginFilter(config) {
|
|
|
2879
3224
|
var _a;
|
|
2880
3225
|
const appUrl = config.getString("app.baseUrl");
|
|
2881
3226
|
const { origin: appOrigin } = new URL(appUrl);
|
|
2882
|
-
const allowedOrigins = config.getOptionalStringArray(
|
|
2883
|
-
|
|
3227
|
+
const allowedOrigins = config.getOptionalStringArray(
|
|
3228
|
+
"auth.experimentalExtraAllowedOrigins"
|
|
3229
|
+
);
|
|
3230
|
+
const allowedOriginPatterns = (_a = allowedOrigins == null ? void 0 : allowedOrigins.map(
|
|
3231
|
+
(pattern) => new minimatch.Minimatch(pattern, { nocase: true, noglobstar: true })
|
|
3232
|
+
)) != null ? _a : [];
|
|
2884
3233
|
return (origin) => {
|
|
2885
3234
|
if (origin === appOrigin) {
|
|
2886
3235
|
return true;
|