@backstage/plugin-auth-backend 0.20.4-next.1 → 0.21.0-next.3
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 +68 -0
- package/README.md +11 -0
- package/config.d.ts +10 -0
- package/dist/index.cjs.js +58 -15
- package/dist/index.cjs.js.map +1 -1
- package/package.json +21 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,73 @@
|
|
|
1
1
|
# @backstage/plugin-auth-backend
|
|
2
2
|
|
|
3
|
+
## 0.21.0-next.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8321c97: Added `experimentalExtraAllowedOrigins` to config
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @backstage/backend-common@0.21.0-next.3
|
|
10
|
+
- @backstage/plugin-auth-backend-module-oidc-provider@0.1.0-next.3
|
|
11
|
+
- @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.2-next.3
|
|
12
|
+
- @backstage/plugin-auth-backend-module-atlassian-provider@0.1.2-next.3
|
|
13
|
+
- @backstage/plugin-auth-backend-module-microsoft-provider@0.1.5-next.3
|
|
14
|
+
- @backstage/plugin-auth-backend-module-github-provider@0.1.7-next.3
|
|
15
|
+
- @backstage/plugin-auth-backend-module-gitlab-provider@0.1.7-next.3
|
|
16
|
+
- @backstage/plugin-auth-backend-module-oauth2-provider@0.1.7-next.3
|
|
17
|
+
- @backstage/plugin-auth-backend-module-okta-provider@0.0.3-next.3
|
|
18
|
+
- @backstage/plugin-catalog-node@1.6.2-next.3
|
|
19
|
+
- @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.0-next.2
|
|
20
|
+
- @backstage/plugin-auth-node@0.4.4-next.3
|
|
21
|
+
- @backstage/backend-plugin-api@0.6.10-next.3
|
|
22
|
+
- @backstage/catalog-client@1.6.0-next.1
|
|
23
|
+
- @backstage/catalog-model@1.4.4-next.0
|
|
24
|
+
- @backstage/config@1.1.1
|
|
25
|
+
- @backstage/errors@1.2.3
|
|
26
|
+
- @backstage/types@1.1.1
|
|
27
|
+
- @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.4-next.3
|
|
28
|
+
- @backstage/plugin-auth-backend-module-google-provider@0.1.7-next.3
|
|
29
|
+
|
|
30
|
+
## 0.21.0-next.2
|
|
31
|
+
|
|
32
|
+
### Minor Changes
|
|
33
|
+
|
|
34
|
+
- 7dd8463: **BREAKING**: The `saml` provider has been migrated from `passport-saml` to `@node-saml/passport-saml`.
|
|
35
|
+
|
|
36
|
+
This comes with breaking changes to config options:
|
|
37
|
+
|
|
38
|
+
- `audience` is now mandatory
|
|
39
|
+
- `wantAuthnResponseSigned` is now exposed and defaults to `true`
|
|
40
|
+
- `wantAssertionsSigned` is now exposed and defaults to `true`
|
|
41
|
+
|
|
42
|
+
### Patch Changes
|
|
43
|
+
|
|
44
|
+
- 97f8724: Support additional algorithms in the `/.well-known/openid-configuration` endpoint.
|
|
45
|
+
- a9e0107: The auth backend will now refuse to issue user tokens are excessively large.
|
|
46
|
+
- d4cc552: The helper function `makeProfileInfo` and `PassportHelpers.transformProfile`
|
|
47
|
+
were refactored to use the `jose` library.
|
|
48
|
+
- 8e8a25d: Ability for user to configure backstage token expiration
|
|
49
|
+
- Updated dependencies
|
|
50
|
+
- @backstage/backend-common@0.21.0-next.2
|
|
51
|
+
- @backstage/backend-plugin-api@0.6.10-next.2
|
|
52
|
+
- @backstage/plugin-auth-backend-module-aws-alb-provider@0.1.0-next.1
|
|
53
|
+
- @backstage/plugin-auth-node@0.4.4-next.2
|
|
54
|
+
- @backstage/plugin-auth-backend-module-atlassian-provider@0.1.2-next.2
|
|
55
|
+
- @backstage/plugin-auth-backend-module-github-provider@0.1.7-next.2
|
|
56
|
+
- @backstage/plugin-auth-backend-module-gitlab-provider@0.1.7-next.2
|
|
57
|
+
- @backstage/plugin-auth-backend-module-google-provider@0.1.7-next.2
|
|
58
|
+
- @backstage/plugin-auth-backend-module-microsoft-provider@0.1.5-next.2
|
|
59
|
+
- @backstage/plugin-auth-backend-module-oauth2-provider@0.1.7-next.2
|
|
60
|
+
- @backstage/plugin-auth-backend-module-oidc-provider@0.1.0-next.2
|
|
61
|
+
- @backstage/plugin-auth-backend-module-okta-provider@0.0.3-next.2
|
|
62
|
+
- @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.4-next.2
|
|
63
|
+
- @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.2-next.2
|
|
64
|
+
- @backstage/plugin-catalog-node@1.6.2-next.2
|
|
65
|
+
- @backstage/config@1.1.1
|
|
66
|
+
- @backstage/catalog-client@1.6.0-next.1
|
|
67
|
+
- @backstage/catalog-model@1.4.4-next.0
|
|
68
|
+
- @backstage/errors@1.2.3
|
|
69
|
+
- @backstage/types@1.1.1
|
|
70
|
+
|
|
3
71
|
## 0.20.4-next.1
|
|
4
72
|
|
|
5
73
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -165,3 +165,14 @@ To try out SAML, you can use the mock identity provider:
|
|
|
165
165
|
## Links
|
|
166
166
|
|
|
167
167
|
- [The Backstage homepage](https://backstage.io)
|
|
168
|
+
|
|
169
|
+
## Configuring Token Expiration in App Config
|
|
170
|
+
|
|
171
|
+
If you need to change Backstage token expiration from the default value of one hour you can do so through configuration. Note that this is **not** the session duration, but rather the duration that the short-term cryptographic tokens are valid for. The expiration can not be set lower than 10 minutes or above 24 hours.
|
|
172
|
+
|
|
173
|
+
This is what the configuration looks like:
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
auth:
|
|
177
|
+
backstageTokenExpiration: { minutes: <user_defined_value> }
|
|
178
|
+
```
|
package/config.d.ts
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { HumanDuration } from '@backstage/types';
|
|
18
|
+
|
|
17
19
|
export interface Config {
|
|
18
20
|
/** Configuration options for the auth plugin */
|
|
19
21
|
auth?: {
|
|
@@ -184,6 +186,14 @@ export interface Config {
|
|
|
184
186
|
cfaccess?: {
|
|
185
187
|
teamName: string;
|
|
186
188
|
};
|
|
189
|
+
/**
|
|
190
|
+
* The backstage token expiration.
|
|
191
|
+
*/
|
|
192
|
+
backstageTokenExpiration?: HumanDuration;
|
|
187
193
|
};
|
|
194
|
+
/**
|
|
195
|
+
* Additional app origins to allow for authenticating
|
|
196
|
+
*/
|
|
197
|
+
experimentalExtraAllowedOrigins?: string[];
|
|
188
198
|
};
|
|
189
199
|
}
|
package/dist/index.cjs.js
CHANGED
|
@@ -13,11 +13,10 @@ var Auth0InternalStrategy = require('passport-auth0');
|
|
|
13
13
|
var crypto = require('crypto');
|
|
14
14
|
var url = require('url');
|
|
15
15
|
var errors = require('@backstage/errors');
|
|
16
|
-
var
|
|
16
|
+
var jose = require('jose');
|
|
17
17
|
var pluginAuthBackendModuleAwsAlbProvider = require('@backstage/plugin-auth-backend-module-aws-alb-provider');
|
|
18
18
|
var passportBitbucketOauth2 = require('passport-bitbucket-oauth2');
|
|
19
19
|
var fetch = require('node-fetch');
|
|
20
|
-
var jose = require('jose');
|
|
21
20
|
var pluginAuthBackendModuleGcpIapProvider = require('@backstage/plugin-auth-backend-module-gcp-iap-provider');
|
|
22
21
|
var pluginAuthBackendModuleGithubProvider = require('@backstage/plugin-auth-backend-module-github-provider');
|
|
23
22
|
var pluginAuthBackendModuleGitlabProvider = require('@backstage/plugin-auth-backend-module-gitlab-provider');
|
|
@@ -28,7 +27,7 @@ var pluginAuthBackendModuleOauth2ProxyProvider = require('@backstage/plugin-auth
|
|
|
28
27
|
var pluginAuthBackendModuleOidcProvider = require('@backstage/plugin-auth-backend-module-oidc-provider');
|
|
29
28
|
var pluginAuthBackendModuleOktaProvider = require('@backstage/plugin-auth-backend-module-okta-provider');
|
|
30
29
|
var passportOneloginOauth = require('passport-onelogin-oauth');
|
|
31
|
-
var passportSaml = require('passport-saml');
|
|
30
|
+
var passportSaml = require('@node-saml/passport-saml');
|
|
32
31
|
var passportOauth2 = require('passport-oauth2');
|
|
33
32
|
var catalogClient = require('@backstage/catalog-client');
|
|
34
33
|
var catalogModel = require('@backstage/catalog-model');
|
|
@@ -43,6 +42,7 @@ var passport = require('passport');
|
|
|
43
42
|
var minimatch = require('minimatch');
|
|
44
43
|
var backendCommon = require('@backstage/backend-common');
|
|
45
44
|
var config = require('@backstage/config');
|
|
45
|
+
var types = require('@backstage/types');
|
|
46
46
|
|
|
47
47
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
48
48
|
|
|
@@ -51,7 +51,6 @@ var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
|
|
|
51
51
|
var cookieParser__default = /*#__PURE__*/_interopDefaultLegacy(cookieParser);
|
|
52
52
|
var Auth0InternalStrategy__default = /*#__PURE__*/_interopDefaultLegacy(Auth0InternalStrategy);
|
|
53
53
|
var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
|
|
54
|
-
var jwtDecoder__default = /*#__PURE__*/_interopDefaultLegacy(jwtDecoder);
|
|
55
54
|
var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
|
|
56
55
|
var session__default = /*#__PURE__*/_interopDefaultLegacy(session);
|
|
57
56
|
var connectSessionKnex__default = /*#__PURE__*/_interopDefaultLegacy(connectSessionKnex);
|
|
@@ -450,7 +449,7 @@ const makeProfileInfo = (profile, idToken) => {
|
|
|
450
449
|
let displayName = (_b = (_a = profile.displayName) != null ? _a : profile.username) != null ? _b : profile.id;
|
|
451
450
|
if ((!email || !picture || !displayName) && idToken) {
|
|
452
451
|
try {
|
|
453
|
-
const decoded =
|
|
452
|
+
const decoded = jose.decodeJwt(idToken);
|
|
454
453
|
if (!email && decoded.email) {
|
|
455
454
|
email = decoded.email;
|
|
456
455
|
}
|
|
@@ -1412,9 +1411,10 @@ class SamlAuthProvider {
|
|
|
1412
1411
|
this.signInResolver = options.signInResolver;
|
|
1413
1412
|
this.authHandler = options.authHandler;
|
|
1414
1413
|
this.resolverContext = options.resolverContext;
|
|
1415
|
-
|
|
1416
|
-
done(
|
|
1417
|
-
}
|
|
1414
|
+
const verifier = (profile, done) => {
|
|
1415
|
+
done(null, { fullProfile: profile });
|
|
1416
|
+
};
|
|
1417
|
+
this.strategy = new passportSaml.Strategy(options, verifier, verifier);
|
|
1418
1418
|
}
|
|
1419
1419
|
async start(req, res) {
|
|
1420
1420
|
const { url } = await executeRedirectStrategy(req, this.strategy, {});
|
|
@@ -1471,7 +1471,7 @@ const saml = createAuthProviderIntegration({
|
|
|
1471
1471
|
callbackUrl: `${globalConfig.baseUrl}/${providerId}/handler/frame`,
|
|
1472
1472
|
entryPoint: config.getString("entryPoint"),
|
|
1473
1473
|
logoutUrl: config.getOptionalString("logoutUrl"),
|
|
1474
|
-
audience: config.
|
|
1474
|
+
audience: config.getString("audience"),
|
|
1475
1475
|
issuer: config.getString("issuer"),
|
|
1476
1476
|
cert: config.getString("cert"),
|
|
1477
1477
|
privateKey: config.getOptionalString("privateKey"),
|
|
@@ -1481,6 +1481,10 @@ const saml = createAuthProviderIntegration({
|
|
|
1481
1481
|
signatureAlgorithm: config.getOptionalString("signatureAlgorithm"),
|
|
1482
1482
|
digestAlgorithm: config.getOptionalString("digestAlgorithm"),
|
|
1483
1483
|
acceptedClockSkewMs: config.getOptionalNumber("acceptedClockSkewMs"),
|
|
1484
|
+
wantAuthnResponseSigned: config.getOptionalBoolean(
|
|
1485
|
+
"wantAuthnResponseSigned"
|
|
1486
|
+
),
|
|
1487
|
+
wantAssertionsSigned: config.getOptionalBoolean("wantAssertionsSigned"),
|
|
1484
1488
|
appUrl: globalConfig.appUrl,
|
|
1485
1489
|
authHandler,
|
|
1486
1490
|
signInResolver: (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver,
|
|
@@ -1838,7 +1842,18 @@ function createOidcRouter(options) {
|
|
|
1838
1842
|
jwks_uri: `${baseUrl}/.well-known/jwks.json`,
|
|
1839
1843
|
response_types_supported: ["id_token"],
|
|
1840
1844
|
subject_types_supported: ["public"],
|
|
1841
|
-
id_token_signing_alg_values_supported: [
|
|
1845
|
+
id_token_signing_alg_values_supported: [
|
|
1846
|
+
"RS256",
|
|
1847
|
+
"RS384",
|
|
1848
|
+
"RS512",
|
|
1849
|
+
"ES256",
|
|
1850
|
+
"ES384",
|
|
1851
|
+
"ES512",
|
|
1852
|
+
"PS256",
|
|
1853
|
+
"PS384",
|
|
1854
|
+
"PS512",
|
|
1855
|
+
"EdDSA"
|
|
1856
|
+
],
|
|
1842
1857
|
scopes_supported: ["openid"],
|
|
1843
1858
|
token_endpoint_auth_methods_supported: [],
|
|
1844
1859
|
claims_supported: ["sub"],
|
|
@@ -1867,6 +1882,7 @@ var __publicField$4 = (obj, key, value) => {
|
|
|
1867
1882
|
return value;
|
|
1868
1883
|
};
|
|
1869
1884
|
const MS_IN_S$1 = 1e3;
|
|
1885
|
+
const MAX_TOKEN_LENGTH = 32768;
|
|
1870
1886
|
class TokenFactory {
|
|
1871
1887
|
constructor(options) {
|
|
1872
1888
|
__publicField$4(this, "issuer");
|
|
@@ -1901,7 +1917,16 @@ class TokenFactory {
|
|
|
1901
1917
|
if (!key.alg) {
|
|
1902
1918
|
throw new errors.AuthenticationError("No algorithm was provided in the key");
|
|
1903
1919
|
}
|
|
1904
|
-
|
|
1920
|
+
const claims = { ...additionalClaims, iss, sub, ent, aud, iat, exp };
|
|
1921
|
+
const token = await new jose.SignJWT(claims).setProtectedHeader({ alg: key.alg, kid: key.kid }).setIssuer(iss).setAudience(aud).setSubject(sub).setIssuedAt(iat).setExpirationTime(exp).sign(await jose.importJWK(key));
|
|
1922
|
+
if (token.length > MAX_TOKEN_LENGTH) {
|
|
1923
|
+
throw new Error(
|
|
1924
|
+
`Failed to issue a new user token. The resulting token is excessively large, with either too many ownership claims or too large custom claims. You likely have a bug either in the sign-in resolver or catalog data. The following claims were requested: '${JSON.stringify(
|
|
1925
|
+
claims
|
|
1926
|
+
)}'`
|
|
1927
|
+
);
|
|
1928
|
+
}
|
|
1929
|
+
return token;
|
|
1905
1930
|
}
|
|
1906
1931
|
// This will be called by other services that want to verify ID tokens.
|
|
1907
1932
|
// It is important that it returns a list of all public keys that could
|
|
@@ -2478,7 +2503,25 @@ _database = new WeakMap();
|
|
|
2478
2503
|
_promise = new WeakMap();
|
|
2479
2504
|
let AuthDatabase = _AuthDatabase;
|
|
2480
2505
|
|
|
2481
|
-
const
|
|
2506
|
+
const TOKEN_EXP_DEFAULT_S = 3600;
|
|
2507
|
+
const TOKEN_EXP_MIN_S = 600;
|
|
2508
|
+
const TOKEN_EXP_MAX_S = 86400;
|
|
2509
|
+
function readBackstageTokenExpiration(config$1) {
|
|
2510
|
+
const processingIntervalKey = "auth.backstageTokenExpiration";
|
|
2511
|
+
if (!config$1.has(processingIntervalKey)) {
|
|
2512
|
+
return TOKEN_EXP_DEFAULT_S;
|
|
2513
|
+
}
|
|
2514
|
+
const duration = config.readDurationFromConfig(config$1, {
|
|
2515
|
+
key: processingIntervalKey
|
|
2516
|
+
});
|
|
2517
|
+
const durationS = Math.round(types.durationToMilliseconds(duration) / 1e3);
|
|
2518
|
+
if (durationS < TOKEN_EXP_MIN_S) {
|
|
2519
|
+
return TOKEN_EXP_MIN_S;
|
|
2520
|
+
} else if (durationS > TOKEN_EXP_MAX_S) {
|
|
2521
|
+
return TOKEN_EXP_MAX_S;
|
|
2522
|
+
}
|
|
2523
|
+
return durationS;
|
|
2524
|
+
}
|
|
2482
2525
|
|
|
2483
2526
|
var __defProp = Object.defineProperty;
|
|
2484
2527
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -2545,8 +2588,8 @@ async function createRouter(options) {
|
|
|
2545
2588
|
const router = Router__default["default"]();
|
|
2546
2589
|
const appUrl = config.getString("app.baseUrl");
|
|
2547
2590
|
const authUrl = await discovery.getExternalBaseUrl("auth");
|
|
2591
|
+
const backstageTokenExpiration = readBackstageTokenExpiration(config);
|
|
2548
2592
|
const authDb = AuthDatabase.create(database);
|
|
2549
|
-
const sessionExpirationSeconds = BACKSTAGE_SESSION_EXPIRATION;
|
|
2550
2593
|
const keyStore = await KeyStores.fromConfig(config, {
|
|
2551
2594
|
logger,
|
|
2552
2595
|
database: authDb
|
|
@@ -2557,7 +2600,7 @@ async function createRouter(options) {
|
|
|
2557
2600
|
{
|
|
2558
2601
|
logger: logger.child({ component: "token-factory" }),
|
|
2559
2602
|
issuer: authUrl,
|
|
2560
|
-
sessionExpirationSeconds
|
|
2603
|
+
sessionExpirationSeconds: backstageTokenExpiration
|
|
2561
2604
|
},
|
|
2562
2605
|
keyStore
|
|
2563
2606
|
);
|
|
@@ -2565,7 +2608,7 @@ async function createRouter(options) {
|
|
|
2565
2608
|
tokenIssuer = new TokenFactory({
|
|
2566
2609
|
issuer: authUrl,
|
|
2567
2610
|
keyStore,
|
|
2568
|
-
keyDurationSeconds:
|
|
2611
|
+
keyDurationSeconds: backstageTokenExpiration,
|
|
2569
2612
|
logger: logger.child({ component: "token-factory" }),
|
|
2570
2613
|
algorithm: tokenFactoryAlgorithm != null ? tokenFactoryAlgorithm : config.getOptionalString("auth.identityTokenAlgorithm")
|
|
2571
2614
|
});
|