@backstage/plugin-auth-backend 0.13.0 → 0.13.1-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 +48 -0
- package/dist/index.cjs.js +59 -36
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +38 -5
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# @backstage/plugin-auth-backend
|
|
2
2
|
|
|
3
|
+
## 0.13.1-next.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @backstage/backend-common@0.13.3-next.2
|
|
9
|
+
- @backstage/config@1.0.1-next.0
|
|
10
|
+
- @backstage/catalog-model@1.0.2-next.0
|
|
11
|
+
- @backstage/plugin-auth-node@0.2.1-next.1
|
|
12
|
+
- @backstage/catalog-client@1.0.2-next.0
|
|
13
|
+
|
|
14
|
+
## 0.13.1-next.1
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- cac3ba68a2: Fixed a bug that was introduced in `0.13.1-next.0` which caused the `ent` claim of issued tokens to be dropped.
|
|
19
|
+
- 5d268623dd: Updates the OAuth2 Proxy provider to require less infrastructure configuration.
|
|
20
|
+
|
|
21
|
+
The auth result object of the OAuth2 Proxy now provides access to the request headers, both through the `headers` object as well as `getHeader` method. The existing logic that parses and extracts the user information from ID tokens is deprecated and will be removed in a future release. See the OAuth2 Proxy provider documentation for more details.
|
|
22
|
+
|
|
23
|
+
The OAuth2 Proxy provider now also has a default `authHandler` implementation that reads the display name and email from the incoming request headers.
|
|
24
|
+
|
|
25
|
+
- Updated dependencies
|
|
26
|
+
- @backstage/backend-common@0.13.3-next.1
|
|
27
|
+
|
|
28
|
+
## 0.13.1-next.0
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- cfc0f19699: Updated dependency `fs-extra` to `10.1.0`.
|
|
33
|
+
- 787ae0d541: Add more common predefined sign-in resolvers to auth providers.
|
|
34
|
+
|
|
35
|
+
Add the existing resolver to more providers (already available at `google`):
|
|
36
|
+
|
|
37
|
+
- `providers.microsoft.resolvers.emailLocalPartMatchingUserEntityName()`
|
|
38
|
+
- `providers.okta.resolvers.emailLocalPartMatchingUserEntityName()`
|
|
39
|
+
|
|
40
|
+
Add a new resolver for simple email-to-email matching:
|
|
41
|
+
|
|
42
|
+
- `providers.google.resolvers.emailMatchingUserEntityProfileEmail()`
|
|
43
|
+
- `providers.microsoft.resolvers.emailMatchingUserEntityProfileEmail()`
|
|
44
|
+
- `providers.okta.resolvers.emailMatchingUserEntityProfileEmail()`
|
|
45
|
+
|
|
46
|
+
- 9ec4e0613e: Update to `jose` 4.6.0
|
|
47
|
+
- Updated dependencies
|
|
48
|
+
- @backstage/backend-common@0.13.3-next.0
|
|
49
|
+
- @backstage/plugin-auth-node@0.2.1-next.0
|
|
50
|
+
|
|
3
51
|
## 0.13.0
|
|
4
52
|
|
|
5
53
|
### Minor Changes
|
package/dist/index.cjs.js
CHANGED
|
@@ -763,10 +763,6 @@ const createAuth0Provider = auth0.create;
|
|
|
763
763
|
|
|
764
764
|
const ALB_JWT_HEADER = "x-amzn-oidc-data";
|
|
765
765
|
const ALB_ACCESS_TOKEN_HEADER = "x-amzn-oidc-accesstoken";
|
|
766
|
-
const getJWTHeaders = (input) => {
|
|
767
|
-
const encoded = input.split(".")[0];
|
|
768
|
-
return JSON.parse(Buffer.from(encoded, "base64").toString("utf8"));
|
|
769
|
-
};
|
|
770
766
|
class AwsAlbAuthProvider {
|
|
771
767
|
constructor(options) {
|
|
772
768
|
this.region = options.region;
|
|
@@ -801,9 +797,8 @@ class AwsAlbAuthProvider {
|
|
|
801
797
|
throw new errors.AuthenticationError(`Missing ALB OIDC header: ${ALB_ACCESS_TOKEN_HEADER}`);
|
|
802
798
|
}
|
|
803
799
|
try {
|
|
804
|
-
const
|
|
805
|
-
const
|
|
806
|
-
const claims = jose.JWT.verify(jwt, key);
|
|
800
|
+
const verifyResult = await jose.jwtVerify(jwt, this.getKey);
|
|
801
|
+
const claims = verifyResult.payload;
|
|
807
802
|
if (this.issuer && claims.iss !== this.issuer) {
|
|
808
803
|
throw new errors.AuthenticationError("Issuer mismatch on JWT token");
|
|
809
804
|
}
|
|
@@ -843,14 +838,17 @@ class AwsAlbAuthProvider {
|
|
|
843
838
|
profile
|
|
844
839
|
};
|
|
845
840
|
}
|
|
846
|
-
async getKey(
|
|
847
|
-
|
|
841
|
+
async getKey(header) {
|
|
842
|
+
if (!header.kid) {
|
|
843
|
+
throw new errors.AuthenticationError("No key id was specified in header");
|
|
844
|
+
}
|
|
845
|
+
const optionalCacheKey = this.keyCache.get(header.kid);
|
|
848
846
|
if (optionalCacheKey) {
|
|
849
847
|
return crypto__namespace.createPublicKey(optionalCacheKey);
|
|
850
848
|
}
|
|
851
|
-
const keyText = await fetch__default["default"](`https://public-keys.auth.elb.${encodeURIComponent(this.region)}.amazonaws.com/${encodeURIComponent(
|
|
849
|
+
const keyText = await fetch__default["default"](`https://public-keys.auth.elb.${encodeURIComponent(this.region)}.amazonaws.com/${encodeURIComponent(header.kid)}`).then((response) => response.text());
|
|
852
850
|
const keyValue = crypto__namespace.createPublicKey(keyText);
|
|
853
|
-
this.keyCache.set(
|
|
851
|
+
this.keyCache.set(header.kid, keyValue.export({ format: "pem", type: "spki" }));
|
|
854
852
|
return keyValue;
|
|
855
853
|
}
|
|
856
854
|
}
|
|
@@ -1257,6 +1255,17 @@ const commonByEmailLocalPartResolver = async (info, ctx) => {
|
|
|
1257
1255
|
entityRef: { name: localPart }
|
|
1258
1256
|
});
|
|
1259
1257
|
};
|
|
1258
|
+
const commonByEmailResolver = async (info, ctx) => {
|
|
1259
|
+
const { profile } = info;
|
|
1260
|
+
if (!profile.email) {
|
|
1261
|
+
throw new Error("Login failed, user profile does not contain an email");
|
|
1262
|
+
}
|
|
1263
|
+
return ctx.signInWithCatalogUser({
|
|
1264
|
+
filter: {
|
|
1265
|
+
"spec.profile.email": profile.email
|
|
1266
|
+
}
|
|
1267
|
+
});
|
|
1268
|
+
};
|
|
1260
1269
|
|
|
1261
1270
|
class GoogleAuthProvider {
|
|
1262
1271
|
constructor(options) {
|
|
@@ -1354,6 +1363,7 @@ const google = createAuthProviderIntegration({
|
|
|
1354
1363
|
},
|
|
1355
1364
|
resolvers: {
|
|
1356
1365
|
emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver,
|
|
1366
|
+
emailMatchingUserEntityProfileEmail: () => commonByEmailResolver,
|
|
1357
1367
|
emailMatchingUserEntityAnnotation() {
|
|
1358
1368
|
return async (info, ctx) => {
|
|
1359
1369
|
const { profile } = info;
|
|
@@ -1483,6 +1493,8 @@ const microsoft = createAuthProviderIntegration({
|
|
|
1483
1493
|
});
|
|
1484
1494
|
},
|
|
1485
1495
|
resolvers: {
|
|
1496
|
+
emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver,
|
|
1497
|
+
emailMatchingUserEntityProfileEmail: () => commonByEmailResolver,
|
|
1486
1498
|
emailMatchingUserEntityAnnotation() {
|
|
1487
1499
|
return async (info, ctx) => {
|
|
1488
1500
|
const { profile } = info;
|
|
@@ -1629,7 +1641,20 @@ class Oauth2ProxyAuthProvider {
|
|
|
1629
1641
|
}
|
|
1630
1642
|
async refresh(req, res) {
|
|
1631
1643
|
try {
|
|
1632
|
-
const
|
|
1644
|
+
const authHeader = req.header(OAUTH2_PROXY_JWT_HEADER);
|
|
1645
|
+
const jwt = pluginAuthNode.getBearerTokenFromAuthorizationHeader(authHeader);
|
|
1646
|
+
const decodedJWT = jwt && jose.decodeJwt(jwt);
|
|
1647
|
+
const result = {
|
|
1648
|
+
fullProfile: decodedJWT || {},
|
|
1649
|
+
accessToken: jwt || "",
|
|
1650
|
+
headers: req.headers,
|
|
1651
|
+
getHeader(name) {
|
|
1652
|
+
if (name.toLocaleLowerCase("en-US") === "set-cookie") {
|
|
1653
|
+
throw new Error("Access Set-Cookie via the headers object instead");
|
|
1654
|
+
}
|
|
1655
|
+
return req.get(name);
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1633
1658
|
const response = await this.handleResult(result);
|
|
1634
1659
|
res.json(response);
|
|
1635
1660
|
} catch (e) {
|
|
@@ -1653,18 +1678,14 @@ class Oauth2ProxyAuthProvider {
|
|
|
1653
1678
|
profile
|
|
1654
1679
|
};
|
|
1655
1680
|
}
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1681
|
+
}
|
|
1682
|
+
async function defaultAuthHandler$1(result) {
|
|
1683
|
+
return {
|
|
1684
|
+
profile: {
|
|
1685
|
+
email: result.getHeader("x-forwarded-email"),
|
|
1686
|
+
displayName: result.getHeader("x-forwarded-preferred-username") || result.getHeader("x-forwarded-user")
|
|
1661
1687
|
}
|
|
1662
|
-
|
|
1663
|
-
return {
|
|
1664
|
-
fullProfile: decodedJWT,
|
|
1665
|
-
accessToken: jwt
|
|
1666
|
-
};
|
|
1667
|
-
}
|
|
1688
|
+
};
|
|
1668
1689
|
}
|
|
1669
1690
|
const oauth2Proxy = createAuthProviderIntegration({
|
|
1670
1691
|
create(options) {
|
|
@@ -1674,7 +1695,7 @@ const oauth2Proxy = createAuthProviderIntegration({
|
|
|
1674
1695
|
return new Oauth2ProxyAuthProvider({
|
|
1675
1696
|
resolverContext,
|
|
1676
1697
|
signInResolver,
|
|
1677
|
-
authHandler
|
|
1698
|
+
authHandler: authHandler != null ? authHandler : defaultAuthHandler$1
|
|
1678
1699
|
});
|
|
1679
1700
|
};
|
|
1680
1701
|
}
|
|
@@ -1919,6 +1940,8 @@ const okta = createAuthProviderIntegration({
|
|
|
1919
1940
|
});
|
|
1920
1941
|
},
|
|
1921
1942
|
resolvers: {
|
|
1943
|
+
emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver,
|
|
1944
|
+
emailMatchingUserEntityProfileEmail: () => commonByEmailResolver,
|
|
1922
1945
|
emailMatchingUserEntityAnnotation() {
|
|
1923
1946
|
return async (info, ctx) => {
|
|
1924
1947
|
const { profile } = info;
|
|
@@ -2299,10 +2322,10 @@ class TokenFactory {
|
|
|
2299
2322
|
throw new Error('"sub" claim provided by the auth resolver is not a valid EntityRef.');
|
|
2300
2323
|
}
|
|
2301
2324
|
this.logger.info(`Issuing token for ${sub}, with entities ${ent != null ? ent : []}`);
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
});
|
|
2325
|
+
if (!key.alg) {
|
|
2326
|
+
throw new errors.AuthenticationError("No algorithm was provided in the key");
|
|
2327
|
+
}
|
|
2328
|
+
return new jose.SignJWT({ 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));
|
|
2306
2329
|
}
|
|
2307
2330
|
async listPublicKeys() {
|
|
2308
2331
|
const { items: keys } = await this.keyStore.listKeys();
|
|
@@ -2339,14 +2362,14 @@ class TokenFactory {
|
|
|
2339
2362
|
seconds: this.keyDurationSeconds
|
|
2340
2363
|
}).toJSDate();
|
|
2341
2364
|
const promise = (async () => {
|
|
2342
|
-
const key = await jose.
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
this.logger.info(`Created new signing key ${
|
|
2348
|
-
await this.keyStore.addKey(
|
|
2349
|
-
return
|
|
2365
|
+
const key = await jose.generateKeyPair("ES256");
|
|
2366
|
+
const publicKey = await jose.exportJWK(key.publicKey);
|
|
2367
|
+
const privateKey = await jose.exportJWK(key.privateKey);
|
|
2368
|
+
publicKey.kid = privateKey.kid = uuid.v4();
|
|
2369
|
+
publicKey.alg = privateKey.alg = "ES256";
|
|
2370
|
+
this.logger.info(`Created new signing key ${publicKey.kid}`);
|
|
2371
|
+
await this.keyStore.addKey(publicKey);
|
|
2372
|
+
return privateKey;
|
|
2350
2373
|
})();
|
|
2351
2374
|
this.privateKeyPromise = promise;
|
|
2352
2375
|
try {
|