@backstage/plugin-auth-backend 0.17.3-next.0 → 0.17.3-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/CHANGELOG.md +26 -0
- package/dist/index.cjs.js +100 -0
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# @backstage/plugin-auth-backend
|
|
2
2
|
|
|
3
|
+
## 0.17.3-next.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @backstage/backend-common@0.18.0-next.1
|
|
9
|
+
- @backstage/catalog-client@1.3.0-next.2
|
|
10
|
+
- @backstage/plugin-auth-node@0.2.9-next.1
|
|
11
|
+
- @backstage/catalog-model@1.1.5-next.1
|
|
12
|
+
- @backstage/config@1.0.6-next.0
|
|
13
|
+
- @backstage/errors@1.1.4
|
|
14
|
+
- @backstage/types@1.0.2
|
|
15
|
+
|
|
16
|
+
## 0.17.3-next.1
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Updated dependencies
|
|
21
|
+
- @backstage/backend-common@0.18.0-next.0
|
|
22
|
+
- @backstage/config@1.0.6-next.0
|
|
23
|
+
- @backstage/catalog-client@1.3.0-next.1
|
|
24
|
+
- @backstage/catalog-model@1.1.5-next.1
|
|
25
|
+
- @backstage/errors@1.1.4
|
|
26
|
+
- @backstage/types@1.0.2
|
|
27
|
+
- @backstage/plugin-auth-node@0.2.9-next.0
|
|
28
|
+
|
|
3
29
|
## 0.17.3-next.0
|
|
4
30
|
|
|
5
31
|
### Patch Changes
|
package/dist/index.cjs.js
CHANGED
|
@@ -464,6 +464,10 @@ class OAuthAdapter {
|
|
|
464
464
|
throw new errors.AuthenticationError("Refresh failed", error);
|
|
465
465
|
}
|
|
466
466
|
}
|
|
467
|
+
/**
|
|
468
|
+
* If the response from the OAuth provider includes a Backstage identity, we
|
|
469
|
+
* make sure it's populated with all the information we can derive from the user ID.
|
|
470
|
+
*/
|
|
467
471
|
async populateIdentity(identity) {
|
|
468
472
|
if (!identity) {
|
|
469
473
|
return void 0;
|
|
@@ -743,6 +747,14 @@ class Auth0Strategy extends Auth0InternalStrategy__default["default"] {
|
|
|
743
747
|
|
|
744
748
|
class Auth0AuthProvider {
|
|
745
749
|
constructor(options) {
|
|
750
|
+
/**
|
|
751
|
+
* Due to passport-auth0 forcing options.state = true,
|
|
752
|
+
* passport-oauth2 requires express-session to be installed
|
|
753
|
+
* so that the 'state' parameter of the oauth2 flow can be stored.
|
|
754
|
+
* This implementation of StateStore matches the NullStore found within
|
|
755
|
+
* passport-oauth2, which is the StateStore implementation used when options.state = false,
|
|
756
|
+
* allowing us to avoid using express-session in order to integrate with auth0.
|
|
757
|
+
*/
|
|
746
758
|
this.store = {
|
|
747
759
|
store(_req, cb) {
|
|
748
760
|
cb(null, null);
|
|
@@ -763,6 +775,8 @@ class Auth0AuthProvider {
|
|
|
763
775
|
clientSecret: options.clientSecret,
|
|
764
776
|
callbackURL: options.callbackUrl,
|
|
765
777
|
domain: options.domain,
|
|
778
|
+
// We need passReqToCallback set to false to get params, but there's
|
|
779
|
+
// no matching type signature for that, so instead behold this beauty
|
|
766
780
|
passReqToCallback: false,
|
|
767
781
|
store: this.store
|
|
768
782
|
},
|
|
@@ -1126,6 +1140,9 @@ const bitbucket = createAuthProviderIntegration({
|
|
|
1126
1140
|
});
|
|
1127
1141
|
},
|
|
1128
1142
|
resolvers: {
|
|
1143
|
+
/**
|
|
1144
|
+
* Looks up the user by matching their username to the `bitbucket.org/username` annotation.
|
|
1145
|
+
*/
|
|
1129
1146
|
usernameMatchingUserEntityAnnotation() {
|
|
1130
1147
|
return async (info, ctx) => {
|
|
1131
1148
|
const { result } = info;
|
|
@@ -1139,6 +1156,9 @@ const bitbucket = createAuthProviderIntegration({
|
|
|
1139
1156
|
});
|
|
1140
1157
|
};
|
|
1141
1158
|
},
|
|
1159
|
+
/**
|
|
1160
|
+
* Looks up the user by matching their user ID to the `bitbucket.org/user-id` annotation.
|
|
1161
|
+
*/
|
|
1142
1162
|
userIdMatchingUserEntityAnnotation() {
|
|
1143
1163
|
return async (info, ctx) => {
|
|
1144
1164
|
const { result } = info;
|
|
@@ -1312,6 +1332,9 @@ const cfAccess = createAuthProviderIntegration({
|
|
|
1312
1332
|
};
|
|
1313
1333
|
},
|
|
1314
1334
|
resolvers: {
|
|
1335
|
+
/**
|
|
1336
|
+
* Looks up the user by matching their email to the entity email.
|
|
1337
|
+
*/
|
|
1315
1338
|
emailMatchingUserEntityProfileEmail: () => commonByEmailResolver
|
|
1316
1339
|
}
|
|
1317
1340
|
});
|
|
@@ -1562,6 +1585,9 @@ const github = createAuthProviderIntegration({
|
|
|
1562
1585
|
});
|
|
1563
1586
|
},
|
|
1564
1587
|
resolvers: {
|
|
1588
|
+
/**
|
|
1589
|
+
* Looks up the user by matching their GitHub username to the entity name.
|
|
1590
|
+
*/
|
|
1565
1591
|
usernameMatchingUserEntityName: () => {
|
|
1566
1592
|
return async (info, ctx) => {
|
|
1567
1593
|
const { fullProfile } = info.result;
|
|
@@ -1805,8 +1831,17 @@ const google = createAuthProviderIntegration({
|
|
|
1805
1831
|
});
|
|
1806
1832
|
},
|
|
1807
1833
|
resolvers: {
|
|
1834
|
+
/**
|
|
1835
|
+
* Looks up the user by matching their email local part to the entity name.
|
|
1836
|
+
*/
|
|
1808
1837
|
emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver,
|
|
1838
|
+
/**
|
|
1839
|
+
* Looks up the user by matching their email to the entity email.
|
|
1840
|
+
*/
|
|
1809
1841
|
emailMatchingUserEntityProfileEmail: () => commonByEmailResolver,
|
|
1842
|
+
/**
|
|
1843
|
+
* Looks up the user by matching their email to the `google.com/email` annotation.
|
|
1844
|
+
*/
|
|
1810
1845
|
emailMatchingUserEntityAnnotation() {
|
|
1811
1846
|
return async (info, ctx) => {
|
|
1812
1847
|
const { profile } = info;
|
|
@@ -1951,8 +1986,17 @@ const microsoft = createAuthProviderIntegration({
|
|
|
1951
1986
|
});
|
|
1952
1987
|
},
|
|
1953
1988
|
resolvers: {
|
|
1989
|
+
/**
|
|
1990
|
+
* Looks up the user by matching their email local part to the entity name.
|
|
1991
|
+
*/
|
|
1954
1992
|
emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver,
|
|
1993
|
+
/**
|
|
1994
|
+
* Looks up the user by matching their email to the entity email.
|
|
1995
|
+
*/
|
|
1955
1996
|
emailMatchingUserEntityProfileEmail: () => commonByEmailResolver,
|
|
1997
|
+
/**
|
|
1998
|
+
* Looks up the user by matching their email to the `microsoft.com/email` annotation.
|
|
1999
|
+
*/
|
|
1956
2000
|
emailMatchingUserEntityAnnotation() {
|
|
1957
2001
|
return async (info, ctx) => {
|
|
1958
2002
|
const { profile } = info;
|
|
@@ -2231,6 +2275,7 @@ class OidcAuthProvider {
|
|
|
2231
2275
|
const issuer = await openidClient.Issuer.discover(options.metadataUrl);
|
|
2232
2276
|
const client = new issuer.Client({
|
|
2233
2277
|
access_type: "offline",
|
|
2278
|
+
// this option must be passed to provider to receive a refresh token
|
|
2234
2279
|
client_id: options.clientId,
|
|
2235
2280
|
client_secret: options.clientSecret,
|
|
2236
2281
|
redirect_uris: [options.callbackUrl],
|
|
@@ -2261,6 +2306,8 @@ class OidcAuthProvider {
|
|
|
2261
2306
|
strategy.error = console.error;
|
|
2262
2307
|
return { strategy, client };
|
|
2263
2308
|
}
|
|
2309
|
+
// Use this function to grab the user profile info from the token
|
|
2310
|
+
// Then populate the profile with it
|
|
2264
2311
|
async handleResult(result) {
|
|
2265
2312
|
const { profile } = await this.authHandler(result, this.resolverContext);
|
|
2266
2313
|
const response = {
|
|
@@ -2327,6 +2374,14 @@ const oidc = createAuthProviderIntegration({
|
|
|
2327
2374
|
|
|
2328
2375
|
class OktaAuthProvider {
|
|
2329
2376
|
constructor(options) {
|
|
2377
|
+
/**
|
|
2378
|
+
* Due to passport-okta-oauth forcing options.state = true,
|
|
2379
|
+
* passport-oauth2 requires express-session to be installed
|
|
2380
|
+
* so that the 'state' parameter of the oauth2 flow can be stored.
|
|
2381
|
+
* This implementation of StateStore matches the NullStore found within
|
|
2382
|
+
* passport-oauth2, which is the StateStore implementation used when options.state = false,
|
|
2383
|
+
* allowing us to avoid using express-session in order to integrate with Okta.
|
|
2384
|
+
*/
|
|
2330
2385
|
this.store = {
|
|
2331
2386
|
store(_req, cb) {
|
|
2332
2387
|
cb(null, null);
|
|
@@ -2458,8 +2513,17 @@ const okta = createAuthProviderIntegration({
|
|
|
2458
2513
|
});
|
|
2459
2514
|
},
|
|
2460
2515
|
resolvers: {
|
|
2516
|
+
/**
|
|
2517
|
+
* Looks up the user by matching their email local part to the entity name.
|
|
2518
|
+
*/
|
|
2461
2519
|
emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver,
|
|
2520
|
+
/**
|
|
2521
|
+
* Looks up the user by matching their email to the entity email.
|
|
2522
|
+
*/
|
|
2462
2523
|
emailMatchingUserEntityProfileEmail: () => commonByEmailResolver,
|
|
2524
|
+
/**
|
|
2525
|
+
* Looks up the user by matching their email to the `okta.com/email` annotation.
|
|
2526
|
+
*/
|
|
2463
2527
|
emailMatchingUserEntityAnnotation() {
|
|
2464
2528
|
return async (info, ctx) => {
|
|
2465
2529
|
const { profile } = info;
|
|
@@ -2674,6 +2738,9 @@ const saml = createAuthProviderIntegration({
|
|
|
2674
2738
|
};
|
|
2675
2739
|
},
|
|
2676
2740
|
resolvers: {
|
|
2741
|
+
/**
|
|
2742
|
+
* Looks up the user by matching their nameID to the entity name.
|
|
2743
|
+
*/
|
|
2677
2744
|
nameIdMatchingUserEntityName() {
|
|
2678
2745
|
return async (info, ctx) => {
|
|
2679
2746
|
const id = info.result.fullProfile.nameID;
|
|
@@ -2784,6 +2851,9 @@ class TokenFactory {
|
|
|
2784
2851
|
}
|
|
2785
2852
|
return new jose.SignJWT({ ...additionalClaims, iss, sub, ent, aud, iat, exp }).setProtectedHeader({ alg: key.alg, kid: key.kid }).setIssuer(iss).setAudience(aud).setSubject(sub).setIssuedAt(iat).setExpirationTime(exp).sign(await jose.importJWK(key));
|
|
2786
2853
|
}
|
|
2854
|
+
// This will be called by other services that want to verify ID tokens.
|
|
2855
|
+
// It is important that it returns a list of all public keys that could
|
|
2856
|
+
// have been used to sign tokens that have not yet expired.
|
|
2787
2857
|
async listPublicKeys() {
|
|
2788
2858
|
const { items: keys } = await this.keyStore.listKeys();
|
|
2789
2859
|
const validKeys = [];
|
|
@@ -2971,6 +3041,15 @@ class FirestoreKeyStore {
|
|
|
2971
3041
|
);
|
|
2972
3042
|
}
|
|
2973
3043
|
}
|
|
3044
|
+
/**
|
|
3045
|
+
* Helper function to allow us to modify the timeout used when
|
|
3046
|
+
* performing Firestore database operations.
|
|
3047
|
+
*
|
|
3048
|
+
* The reason for this is that it seems that there's no other
|
|
3049
|
+
* practical solution to change the default timeout of 10mins
|
|
3050
|
+
* that Firestore has.
|
|
3051
|
+
*
|
|
3052
|
+
*/
|
|
2974
3053
|
async withTimeout(operation) {
|
|
2975
3054
|
const timer = new Promise(
|
|
2976
3055
|
(_, reject) => setTimeout(() => {
|
|
@@ -2979,12 +3058,21 @@ class FirestoreKeyStore {
|
|
|
2979
3058
|
);
|
|
2980
3059
|
return Promise.race([operation, timer]);
|
|
2981
3060
|
}
|
|
3061
|
+
/**
|
|
3062
|
+
* Used to verify that the database is reachable.
|
|
3063
|
+
*/
|
|
2982
3064
|
async verify() {
|
|
2983
3065
|
await this.withTimeout(this.database.collection(this.path).limit(1).get());
|
|
2984
3066
|
}
|
|
2985
3067
|
}
|
|
2986
3068
|
|
|
2987
3069
|
class KeyStores {
|
|
3070
|
+
/**
|
|
3071
|
+
* Looks at the `auth.keyStore` section in the application configuration
|
|
3072
|
+
* and returns a KeyStore store. Defaults to `database`
|
|
3073
|
+
*
|
|
3074
|
+
* @returns a KeyStore store
|
|
3075
|
+
*/
|
|
2988
3076
|
static async fromConfig(config, options) {
|
|
2989
3077
|
var _a;
|
|
2990
3078
|
const { logger, database } = options != null ? options : {};
|
|
@@ -3028,6 +3116,11 @@ class CatalogIdentityClient {
|
|
|
3028
3116
|
this.catalogApi = options.catalogApi;
|
|
3029
3117
|
this.tokenManager = options.tokenManager;
|
|
3030
3118
|
}
|
|
3119
|
+
/**
|
|
3120
|
+
* Looks up a single user using a query.
|
|
3121
|
+
*
|
|
3122
|
+
* Throws a NotFoundError or ConflictError if 0 or multiple users are found.
|
|
3123
|
+
*/
|
|
3031
3124
|
async findUser(query) {
|
|
3032
3125
|
const filter = {
|
|
3033
3126
|
kind: "user"
|
|
@@ -3046,6 +3139,13 @@ class CatalogIdentityClient {
|
|
|
3046
3139
|
}
|
|
3047
3140
|
return items[0];
|
|
3048
3141
|
}
|
|
3142
|
+
/**
|
|
3143
|
+
* Resolve additional entity claims from the catalog, using the passed-in entity names. Designed
|
|
3144
|
+
* to be used within a `signInResolver` where additional entity claims might be provided, but
|
|
3145
|
+
* group membership and transient group membership lean on imported catalog relations.
|
|
3146
|
+
*
|
|
3147
|
+
* Returns a superset of the entity names that can be passed directly to `issueToken` as `ent`.
|
|
3148
|
+
*/
|
|
3049
3149
|
async resolveCatalogMembership(query) {
|
|
3050
3150
|
const { entityRefs, logger } = query;
|
|
3051
3151
|
const resolvedEntityRefs = entityRefs.map((ref) => {
|