@backstage/backend-defaults 0.5.1-next.1 → 0.5.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 +25 -0
- package/auth/package.json +1 -1
- package/cache/package.json +1 -1
- package/database/package.json +1 -1
- package/discovery/package.json +1 -1
- package/dist/CreateBackend.cjs.js +49 -0
- package/dist/CreateBackend.cjs.js.map +1 -0
- package/dist/PackageDiscoveryService.cjs.js +109 -0
- package/dist/PackageDiscoveryService.cjs.js.map +1 -0
- package/dist/auth.cjs.js +2 -996
- package/dist/auth.cjs.js.map +1 -1
- package/dist/cache.cjs.js +4 -204
- package/dist/cache.cjs.js.map +1 -1
- package/dist/database.cjs.js +4 -957
- package/dist/database.cjs.js.map +1 -1
- package/dist/database.d.ts +4 -1
- package/dist/discovery.cjs.js +4 -92
- package/dist/discovery.cjs.js.map +1 -1
- package/dist/discoveryFeatureLoader.cjs.js +19 -0
- package/dist/discoveryFeatureLoader.cjs.js.map +1 -0
- package/dist/entrypoints/auth/DefaultAuthService.cjs.js +130 -0
- package/dist/entrypoints/auth/DefaultAuthService.cjs.js.map +1 -0
- package/dist/entrypoints/auth/JwksClient.cjs.js +49 -0
- package/dist/entrypoints/auth/JwksClient.cjs.js.map +1 -0
- package/dist/entrypoints/auth/authServiceFactory.cjs.js +57 -0
- package/dist/entrypoints/auth/authServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/auth/external/ExternalTokenHandler.cjs.js +78 -0
- package/dist/entrypoints/auth/external/ExternalTokenHandler.cjs.js.map +1 -0
- package/dist/entrypoints/auth/external/helpers.cjs.js +92 -0
- package/dist/entrypoints/auth/external/helpers.cjs.js.map +1 -0
- package/dist/entrypoints/auth/external/jwks.cjs.js +63 -0
- package/dist/entrypoints/auth/external/jwks.cjs.js.map +1 -0
- package/dist/entrypoints/auth/external/legacy.cjs.js +73 -0
- package/dist/entrypoints/auth/external/legacy.cjs.js.map +1 -0
- package/dist/entrypoints/auth/external/static.cjs.js +33 -0
- package/dist/entrypoints/auth/external/static.cjs.js.map +1 -0
- package/dist/{cjs/helpers-D2f1CG0o.cjs.js → entrypoints/auth/helpers.cjs.js} +1 -1
- package/dist/entrypoints/auth/helpers.cjs.js.map +1 -0
- package/dist/entrypoints/auth/plugin/PluginTokenHandler.cjs.js +147 -0
- package/dist/entrypoints/auth/plugin/PluginTokenHandler.cjs.js.map +1 -0
- package/dist/entrypoints/auth/plugin/keys/DatabaseKeyStore.cjs.js +73 -0
- package/dist/entrypoints/auth/plugin/keys/DatabaseKeyStore.cjs.js.map +1 -0
- package/dist/entrypoints/auth/plugin/keys/DatabasePluginKeySource.cjs.js +75 -0
- package/dist/entrypoints/auth/plugin/keys/DatabasePluginKeySource.cjs.js.map +1 -0
- package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js +91 -0
- package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js.map +1 -0
- package/dist/entrypoints/auth/plugin/keys/createPluginKeySource.cjs.js +29 -0
- package/dist/entrypoints/auth/plugin/keys/createPluginKeySource.cjs.js.map +1 -0
- package/dist/entrypoints/auth/user/UserTokenHandler.cjs.js +110 -0
- package/dist/entrypoints/auth/user/UserTokenHandler.cjs.js.map +1 -0
- package/dist/entrypoints/cache/CacheClient.cjs.js +50 -0
- package/dist/entrypoints/cache/CacheClient.cjs.js.map +1 -0
- package/dist/entrypoints/cache/CacheManager.cjs.js +147 -0
- package/dist/entrypoints/cache/CacheManager.cjs.js.map +1 -0
- package/dist/entrypoints/cache/cacheServiceFactory.cjs.js +22 -0
- package/dist/entrypoints/cache/cacheServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/cache/types.cjs.js +10 -0
- package/dist/entrypoints/cache/types.cjs.js.map +1 -0
- package/dist/entrypoints/database/DatabaseManager.cjs.js +173 -0
- package/dist/entrypoints/database/DatabaseManager.cjs.js.map +1 -0
- package/dist/entrypoints/database/connectors/defaultNameOverride.cjs.js +14 -0
- package/dist/entrypoints/database/connectors/defaultNameOverride.cjs.js.map +1 -0
- package/dist/entrypoints/database/connectors/defaultSchemaOverride.cjs.js +12 -0
- package/dist/entrypoints/database/connectors/defaultSchemaOverride.cjs.js.map +1 -0
- package/dist/entrypoints/database/connectors/mergeDatabaseConfig.cjs.js +10 -0
- package/dist/entrypoints/database/connectors/mergeDatabaseConfig.cjs.js.map +1 -0
- package/dist/entrypoints/database/connectors/mysql.cjs.js +278 -0
- package/dist/entrypoints/database/connectors/mysql.cjs.js.map +1 -0
- package/dist/entrypoints/database/connectors/postgres.cjs.js +304 -0
- package/dist/entrypoints/database/connectors/postgres.cjs.js.map +1 -0
- package/dist/entrypoints/database/connectors/sqlite3.cjs.js +251 -0
- package/dist/entrypoints/database/connectors/sqlite3.cjs.js.map +1 -0
- package/dist/entrypoints/database/databaseServiceFactory.cjs.js +36 -0
- package/dist/entrypoints/database/databaseServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/discovery/HostDiscovery.cjs.js +86 -0
- package/dist/entrypoints/discovery/HostDiscovery.cjs.js.map +1 -0
- package/dist/entrypoints/discovery/discoveryServiceFactory.cjs.js +17 -0
- package/dist/entrypoints/discovery/discoveryServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/httpAuth/httpAuthServiceFactory.cjs.js +192 -0
- package/dist/entrypoints/httpAuth/httpAuthServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/httpRouter/createAuthIntegrationRouter.cjs.js +19 -0
- package/dist/entrypoints/httpRouter/createAuthIntegrationRouter.cjs.js.map +1 -0
- package/dist/entrypoints/httpRouter/createCookieAuthRefreshMiddleware.cjs.js +26 -0
- package/dist/entrypoints/httpRouter/createCookieAuthRefreshMiddleware.cjs.js.map +1 -0
- package/dist/entrypoints/httpRouter/createCredentialsBarrier.cjs.js +63 -0
- package/dist/entrypoints/httpRouter/createCredentialsBarrier.cjs.js.map +1 -0
- package/dist/entrypoints/httpRouter/createLifecycleMiddleware.cjs.js +52 -0
- package/dist/entrypoints/httpRouter/createLifecycleMiddleware.cjs.js.map +1 -0
- package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js +48 -0
- package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/lifecycle/lifecycleServiceFactory.cjs.js +88 -0
- package/dist/entrypoints/lifecycle/lifecycleServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/logger/loggerServiceFactory.cjs.js +17 -0
- package/dist/entrypoints/logger/loggerServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/permissions/permissionsServiceFactory.cjs.js +22 -0
- package/dist/entrypoints/permissions/permissionsServiceFactory.cjs.js.map +1 -0
- package/dist/{cjs/createConfigSecretEnumerator-DShyoWWL.cjs.js → entrypoints/rootConfig/createConfigSecretEnumerator.cjs.js} +1 -1
- package/dist/entrypoints/rootConfig/createConfigSecretEnumerator.cjs.js.map +1 -0
- package/dist/entrypoints/rootConfig/rootConfigServiceFactory.cjs.js +26 -0
- package/dist/entrypoints/rootConfig/rootConfigServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/rootHealth/rootHealthServiceFactory.cjs.js +41 -0
- package/dist/entrypoints/rootHealth/rootHealthServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/rootHttpRouter/DefaultRootHttpRouter.cjs.js +77 -0
- package/dist/entrypoints/rootHttpRouter/DefaultRootHttpRouter.cjs.js.map +1 -0
- package/dist/entrypoints/rootHttpRouter/createHealthRouter.cjs.js +29 -0
- package/dist/entrypoints/rootHttpRouter/createHealthRouter.cjs.js.map +1 -0
- package/dist/entrypoints/rootHttpRouter/http/MiddlewareFactory.cjs.js +187 -0
- package/dist/entrypoints/rootHttpRouter/http/MiddlewareFactory.cjs.js.map +1 -0
- package/dist/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.cjs.js +28 -0
- package/dist/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.cjs.js.map +1 -0
- package/dist/{cjs/config-BDOwXIyo.cjs.js → entrypoints/rootHttpRouter/http/config.cjs.js} +1 -1
- package/dist/entrypoints/rootHttpRouter/http/config.cjs.js.map +1 -0
- package/dist/entrypoints/rootHttpRouter/http/createHttpServer.cjs.js +88 -0
- package/dist/entrypoints/rootHttpRouter/http/createHttpServer.cjs.js.map +1 -0
- package/dist/entrypoints/rootHttpRouter/http/getGeneratedCertificate.cjs.js +130 -0
- package/dist/entrypoints/rootHttpRouter/http/getGeneratedCertificate.cjs.js.map +1 -0
- package/dist/entrypoints/rootHttpRouter/http/readCorsOptions.cjs.js +51 -0
- package/dist/entrypoints/rootHttpRouter/http/readCorsOptions.cjs.js.map +1 -0
- package/dist/entrypoints/rootHttpRouter/http/readHelmetOptions.cjs.js +62 -0
- package/dist/entrypoints/rootHttpRouter/http/readHelmetOptions.cjs.js.map +1 -0
- package/dist/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.cjs.js +73 -0
- package/dist/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/rootLifecycle/rootLifecycleServiceFactory.cjs.js +76 -0
- package/dist/entrypoints/rootLifecycle/rootLifecycleServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/rootLogger/WinstonLogger.cjs.js +114 -0
- package/dist/entrypoints/rootLogger/WinstonLogger.cjs.js.map +1 -0
- package/dist/entrypoints/rootLogger/rootLoggerServiceFactory.cjs.js +30 -0
- package/dist/entrypoints/rootLogger/rootLoggerServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/scheduler/database/migrateBackendTasks.cjs.js +18 -0
- package/dist/entrypoints/scheduler/database/migrateBackendTasks.cjs.js.map +1 -0
- package/dist/entrypoints/scheduler/database/tables.cjs.js +8 -0
- package/dist/entrypoints/scheduler/database/tables.cjs.js.map +1 -0
- package/dist/entrypoints/scheduler/lib/DefaultSchedulerService.cjs.js +37 -0
- package/dist/entrypoints/scheduler/lib/DefaultSchedulerService.cjs.js.map +1 -0
- package/dist/entrypoints/scheduler/lib/LocalTaskWorker.cjs.js +105 -0
- package/dist/entrypoints/scheduler/lib/LocalTaskWorker.cjs.js.map +1 -0
- package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.cjs.js +138 -0
- package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.cjs.js.map +1 -0
- package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.cjs.js +59 -0
- package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.cjs.js.map +1 -0
- package/dist/entrypoints/scheduler/lib/TaskWorker.cjs.js +275 -0
- package/dist/entrypoints/scheduler/lib/TaskWorker.cjs.js.map +1 -0
- package/dist/entrypoints/scheduler/lib/types.cjs.js +60 -0
- package/dist/entrypoints/scheduler/lib/types.cjs.js.map +1 -0
- package/dist/entrypoints/scheduler/lib/util.cjs.js +66 -0
- package/dist/entrypoints/scheduler/lib/util.cjs.js.map +1 -0
- package/dist/entrypoints/scheduler/schedulerServiceFactory.cjs.js +19 -0
- package/dist/entrypoints/scheduler/schedulerServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js +274 -0
- package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js +261 -0
- package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/AzureUrlReader.cjs.js +148 -0
- package/dist/entrypoints/urlReader/lib/AzureUrlReader.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/BitbucketCloudUrlReader.cjs.js +174 -0
- package/dist/entrypoints/urlReader/lib/BitbucketCloudUrlReader.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/BitbucketServerUrlReader.cjs.js +170 -0
- package/dist/entrypoints/urlReader/lib/BitbucketServerUrlReader.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/BitbucketUrlReader.cjs.js +182 -0
- package/dist/entrypoints/urlReader/lib/BitbucketUrlReader.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js +132 -0
- package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/GerritUrlReader.cjs.js +147 -0
- package/dist/entrypoints/urlReader/lib/GerritUrlReader.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/GiteaUrlReader.cjs.js +122 -0
- package/dist/entrypoints/urlReader/lib/GiteaUrlReader.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/GithubUrlReader.cjs.js +226 -0
- package/dist/entrypoints/urlReader/lib/GithubUrlReader.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js +277 -0
- package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js +129 -0
- package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js +120 -0
- package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/ReadUrlResponseFactory.cjs.js +49 -0
- package/dist/entrypoints/urlReader/lib/ReadUrlResponseFactory.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/UrlReaderPredicateMux.cjs.js +46 -0
- package/dist/entrypoints/urlReader/lib/UrlReaderPredicateMux.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/UrlReaders.cjs.js +68 -0
- package/dist/entrypoints/urlReader/lib/UrlReaders.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.cjs.js +46 -0
- package/dist/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/tree/ReadableArrayResponse.cjs.js +78 -0
- package/dist/entrypoints/urlReader/lib/tree/ReadableArrayResponse.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/tree/TarArchiveResponse.cjs.js +147 -0
- package/dist/entrypoints/urlReader/lib/tree/TarArchiveResponse.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/tree/ZipArchiveResponse.cjs.js +161 -0
- package/dist/entrypoints/urlReader/lib/tree/ZipArchiveResponse.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/tree/util.cjs.js +28 -0
- package/dist/entrypoints/urlReader/lib/tree/util.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/lib/util.cjs.js +11 -0
- package/dist/entrypoints/urlReader/lib/util.cjs.js.map +1 -0
- package/dist/entrypoints/urlReader/urlReaderServiceFactory.cjs.js +29 -0
- package/dist/entrypoints/urlReader/urlReaderServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/userInfo/DefaultUserInfoService.cjs.js +59 -0
- package/dist/entrypoints/userInfo/DefaultUserInfoService.cjs.js.map +1 -0
- package/dist/entrypoints/userInfo/userInfoServiceFactory.cjs.js +17 -0
- package/dist/entrypoints/userInfo/userInfoServiceFactory.cjs.js.map +1 -0
- package/dist/httpAuth.cjs.js +3 -187
- package/dist/httpAuth.cjs.js.map +1 -1
- package/dist/httpRouter.cjs.js +2 -166
- package/dist/httpRouter.cjs.js.map +1 -1
- package/dist/index.cjs.js +4 -160
- package/dist/index.cjs.js.map +1 -1
- package/dist/lib/escapeRegExp.cjs.js +8 -0
- package/dist/lib/escapeRegExp.cjs.js.map +1 -0
- package/dist/lifecycle.cjs.js +3 -58
- package/dist/lifecycle.cjs.js.map +1 -1
- package/dist/logger.cjs.js +3 -12
- package/dist/logger.cjs.js.map +1 -1
- package/dist/package.json.cjs.js +252 -0
- package/dist/package.json.cjs.js.map +1 -0
- package/dist/permissions.cjs.js +3 -17
- package/dist/permissions.cjs.js.map +1 -1
- package/dist/rootConfig.cjs.js +4 -22
- package/dist/rootConfig.cjs.js.map +1 -1
- package/dist/rootHealth.cjs.js +3 -35
- package/dist/rootHealth.cjs.js.map +1 -1
- package/dist/rootHttpRouter.cjs.js +15 -651
- package/dist/rootHttpRouter.cjs.js.map +1 -1
- package/dist/rootLifecycle.cjs.js +3 -70
- package/dist/rootLifecycle.cjs.js.map +1 -1
- package/dist/rootLogger.cjs.js +4 -137
- package/dist/rootLogger.cjs.js.map +1 -1
- package/dist/scheduler.cjs.js +4 -693
- package/dist/scheduler.cjs.js.map +1 -1
- package/dist/scheduler.d.ts +2 -1
- package/dist/urlReader.cjs.js +32 -2962
- package/dist/urlReader.cjs.js.map +1 -1
- package/dist/userInfo.cjs.js +2 -64
- package/dist/userInfo.cjs.js.map +1 -1
- package/httpAuth/package.json +1 -1
- package/httpRouter/package.json +1 -1
- package/lifecycle/package.json +1 -1
- package/logger/package.json +1 -1
- package/package.json +13 -13
- package/permissions/package.json +1 -1
- package/rootConfig/package.json +1 -1
- package/rootHealth/package.json +1 -1
- package/rootHttpRouter/package.json +1 -1
- package/rootLifecycle/package.json +1 -1
- package/rootLogger/package.json +1 -1
- package/scheduler/package.json +1 -1
- package/urlReader/package.json +1 -1
- package/userInfo/package.json +1 -1
- package/dist/cjs/config-BDOwXIyo.cjs.js.map +0 -1
- package/dist/cjs/createConfigSecretEnumerator-DShyoWWL.cjs.js.map +0 -1
- package/dist/cjs/helpers-D2f1CG0o.cjs.js.map +0 -1
package/dist/auth.cjs.js
CHANGED
|
@@ -1,1002 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var errors = require('@backstage/errors');
|
|
5
|
-
var jose = require('jose');
|
|
6
|
-
var helpers = require('./cjs/helpers-D2f1CG0o.cjs.js');
|
|
7
|
-
var pluginAuthNode = require('@backstage/plugin-auth-node');
|
|
8
|
-
var types = require('@backstage/types');
|
|
9
|
-
var uuid = require('uuid');
|
|
10
|
-
var luxon = require('luxon');
|
|
11
|
-
var fs = require('fs');
|
|
3
|
+
var authServiceFactory = require('./entrypoints/auth/authServiceFactory.cjs.js');
|
|
12
4
|
|
|
13
|
-
class DefaultAuthService {
|
|
14
|
-
constructor(userTokenHandler, pluginTokenHandler, externalTokenHandler, pluginId, disableDefaultAuthPolicy, pluginKeySource) {
|
|
15
|
-
this.userTokenHandler = userTokenHandler;
|
|
16
|
-
this.pluginTokenHandler = pluginTokenHandler;
|
|
17
|
-
this.externalTokenHandler = externalTokenHandler;
|
|
18
|
-
this.pluginId = pluginId;
|
|
19
|
-
this.disableDefaultAuthPolicy = disableDefaultAuthPolicy;
|
|
20
|
-
this.pluginKeySource = pluginKeySource;
|
|
21
|
-
}
|
|
22
|
-
async authenticate(token, options) {
|
|
23
|
-
const pluginResult = await this.pluginTokenHandler.verifyToken(token);
|
|
24
|
-
if (pluginResult) {
|
|
25
|
-
if (pluginResult.limitedUserToken) {
|
|
26
|
-
const userResult2 = await this.userTokenHandler.verifyToken(
|
|
27
|
-
pluginResult.limitedUserToken
|
|
28
|
-
);
|
|
29
|
-
if (!userResult2) {
|
|
30
|
-
throw new errors.AuthenticationError(
|
|
31
|
-
"Invalid user token in plugin token obo claim"
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
return helpers.createCredentialsWithUserPrincipal(
|
|
35
|
-
userResult2.userEntityRef,
|
|
36
|
-
pluginResult.limitedUserToken,
|
|
37
|
-
this.#getJwtExpiration(pluginResult.limitedUserToken)
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
return helpers.createCredentialsWithServicePrincipal(pluginResult.subject);
|
|
41
|
-
}
|
|
42
|
-
const userResult = await this.userTokenHandler.verifyToken(token);
|
|
43
|
-
if (userResult) {
|
|
44
|
-
if (!options?.allowLimitedAccess && this.userTokenHandler.isLimitedUserToken(token)) {
|
|
45
|
-
throw new errors.AuthenticationError("Illegal limited user token");
|
|
46
|
-
}
|
|
47
|
-
return helpers.createCredentialsWithUserPrincipal(
|
|
48
|
-
userResult.userEntityRef,
|
|
49
|
-
token,
|
|
50
|
-
this.#getJwtExpiration(token)
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
const externalResult = await this.externalTokenHandler.verifyToken(token);
|
|
54
|
-
if (externalResult) {
|
|
55
|
-
return helpers.createCredentialsWithServicePrincipal(
|
|
56
|
-
externalResult.subject,
|
|
57
|
-
void 0,
|
|
58
|
-
externalResult.accessRestrictions
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
throw new errors.AuthenticationError("Illegal token");
|
|
62
|
-
}
|
|
63
|
-
isPrincipal(credentials, type) {
|
|
64
|
-
const principal = credentials.principal;
|
|
65
|
-
if (type === "unknown") {
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
if (principal.type !== type) {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
async getNoneCredentials() {
|
|
74
|
-
return helpers.createCredentialsWithNonePrincipal();
|
|
75
|
-
}
|
|
76
|
-
async getOwnServiceCredentials() {
|
|
77
|
-
return helpers.createCredentialsWithServicePrincipal(`plugin:${this.pluginId}`);
|
|
78
|
-
}
|
|
79
|
-
async getPluginRequestToken(options) {
|
|
80
|
-
const { targetPluginId } = options;
|
|
81
|
-
const internalForward = helpers.toInternalBackstageCredentials(options.onBehalfOf);
|
|
82
|
-
const { type } = internalForward.principal;
|
|
83
|
-
if (type === "none" && this.disableDefaultAuthPolicy) {
|
|
84
|
-
return { token: "" };
|
|
85
|
-
}
|
|
86
|
-
switch (type) {
|
|
87
|
-
// TODO: Check whether the principal is ourselves
|
|
88
|
-
case "service":
|
|
89
|
-
return this.pluginTokenHandler.issueToken({
|
|
90
|
-
pluginId: this.pluginId,
|
|
91
|
-
targetPluginId
|
|
92
|
-
});
|
|
93
|
-
case "user": {
|
|
94
|
-
const { token } = internalForward;
|
|
95
|
-
if (!token) {
|
|
96
|
-
throw new Error("User credentials is unexpectedly missing token");
|
|
97
|
-
}
|
|
98
|
-
const onBehalfOf = await this.userTokenHandler.createLimitedUserToken(
|
|
99
|
-
token
|
|
100
|
-
);
|
|
101
|
-
return this.pluginTokenHandler.issueToken({
|
|
102
|
-
pluginId: this.pluginId,
|
|
103
|
-
targetPluginId,
|
|
104
|
-
onBehalfOf
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
default:
|
|
108
|
-
throw new errors.AuthenticationError(
|
|
109
|
-
`Refused to issue service token for credential type '${type}'`
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
async getLimitedUserToken(credentials) {
|
|
114
|
-
const { token: backstageToken } = helpers.toInternalBackstageCredentials(credentials);
|
|
115
|
-
if (!backstageToken) {
|
|
116
|
-
throw new errors.AuthenticationError(
|
|
117
|
-
"User credentials is unexpectedly missing token"
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
return this.userTokenHandler.createLimitedUserToken(backstageToken);
|
|
121
|
-
}
|
|
122
|
-
async listPublicServiceKeys() {
|
|
123
|
-
const { keys } = await this.pluginKeySource.listKeys();
|
|
124
|
-
return { keys: keys.map(({ key }) => key) };
|
|
125
|
-
}
|
|
126
|
-
#getJwtExpiration(token) {
|
|
127
|
-
const { exp } = jose.decodeJwt(token);
|
|
128
|
-
if (!exp) {
|
|
129
|
-
throw new errors.AuthenticationError("User token is missing expiration");
|
|
130
|
-
}
|
|
131
|
-
return new Date(exp * 1e3);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
5
|
|
|
135
|
-
function readAccessRestrictionsFromConfig(externalAccessEntryConfig) {
|
|
136
|
-
const configs = externalAccessEntryConfig.getOptionalConfigArray("accessRestrictions") ?? [];
|
|
137
|
-
const result = /* @__PURE__ */ new Map();
|
|
138
|
-
for (const config of configs) {
|
|
139
|
-
const validKeys = ["plugin", "permission", "permissionAttribute"];
|
|
140
|
-
for (const key of config.keys()) {
|
|
141
|
-
if (!validKeys.includes(key)) {
|
|
142
|
-
const valid = validKeys.map((k) => `'${k}'`).join(", ");
|
|
143
|
-
throw new Error(
|
|
144
|
-
`Invalid key '${key}' in 'accessRestrictions' config, expected one of ${valid}`
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
const pluginId = config.getString("plugin");
|
|
149
|
-
const permissionNames = readPermissionNames(config);
|
|
150
|
-
const permissionAttributes = readPermissionAttributes(config);
|
|
151
|
-
if (result.has(pluginId)) {
|
|
152
|
-
throw new Error(
|
|
153
|
-
`Attempted to declare 'accessRestrictions' twice for plugin '${pluginId}', which is not permitted`
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
result.set(pluginId, {
|
|
157
|
-
...permissionNames ? { permissionNames } : {},
|
|
158
|
-
...permissionAttributes ? { permissionAttributes } : {}
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
return result.size ? result : void 0;
|
|
162
|
-
}
|
|
163
|
-
function readStringOrStringArrayFromConfig(root, key, validValues) {
|
|
164
|
-
if (!root.has(key)) {
|
|
165
|
-
return void 0;
|
|
166
|
-
}
|
|
167
|
-
const rawValues = Array.isArray(root.get(key)) ? root.getStringArray(key) : [root.getString(key)];
|
|
168
|
-
const values = [
|
|
169
|
-
...new Set(
|
|
170
|
-
rawValues.map((v) => v.split(/[ ,]/)).flat().filter(Boolean)
|
|
171
|
-
)
|
|
172
|
-
];
|
|
173
|
-
if (!values.length) {
|
|
174
|
-
return void 0;
|
|
175
|
-
}
|
|
176
|
-
if (validValues?.length) {
|
|
177
|
-
for (const value of values) {
|
|
178
|
-
if (!validValues.includes(value)) {
|
|
179
|
-
const valid = validValues.map((k) => `'${k}'`).join(", ");
|
|
180
|
-
throw new Error(
|
|
181
|
-
`Invalid value '${value}' at '${key}' in 'permissionAttributes' config, valid values are ${valid}`
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
return values;
|
|
187
|
-
}
|
|
188
|
-
function readPermissionNames(externalAccessEntryConfig) {
|
|
189
|
-
return readStringOrStringArrayFromConfig(
|
|
190
|
-
externalAccessEntryConfig,
|
|
191
|
-
"permission"
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
function readPermissionAttributes(externalAccessEntryConfig) {
|
|
195
|
-
const config = externalAccessEntryConfig.getOptionalConfig(
|
|
196
|
-
"permissionAttribute"
|
|
197
|
-
);
|
|
198
|
-
if (!config) {
|
|
199
|
-
return void 0;
|
|
200
|
-
}
|
|
201
|
-
const validKeys = ["action"];
|
|
202
|
-
for (const key of config.keys()) {
|
|
203
|
-
if (!validKeys.includes(key)) {
|
|
204
|
-
const valid = validKeys.map((k) => `'${k}'`).join(", ");
|
|
205
|
-
throw new Error(
|
|
206
|
-
`Invalid key '${key}' in 'permissionAttribute' config, expected ${valid}`
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
const action = readStringOrStringArrayFromConfig(config, "action", [
|
|
211
|
-
"create",
|
|
212
|
-
"read",
|
|
213
|
-
"update",
|
|
214
|
-
"delete"
|
|
215
|
-
]);
|
|
216
|
-
const result = {
|
|
217
|
-
...action ? { action } : {}
|
|
218
|
-
};
|
|
219
|
-
return Object.keys(result).length ? result : void 0;
|
|
220
|
-
}
|
|
221
6
|
|
|
222
|
-
|
|
223
|
-
#entries = new Array();
|
|
224
|
-
add(config) {
|
|
225
|
-
const allAccessRestrictions = readAccessRestrictionsFromConfig(config);
|
|
226
|
-
this.#doAdd(
|
|
227
|
-
config.getString("options.secret"),
|
|
228
|
-
config.getString("options.subject"),
|
|
229
|
-
allAccessRestrictions
|
|
230
|
-
);
|
|
231
|
-
}
|
|
232
|
-
// used only for the old backend.auth.keys array
|
|
233
|
-
addOld(config) {
|
|
234
|
-
this.#doAdd(config.getString("secret"), "external:backstage-plugin");
|
|
235
|
-
}
|
|
236
|
-
#doAdd(secret, subject, allAccessRestrictions) {
|
|
237
|
-
if (!secret.match(/^\S+$/)) {
|
|
238
|
-
throw new Error("Illegal secret, must be a valid base64 string");
|
|
239
|
-
} else if (!subject.match(/^\S+$/)) {
|
|
240
|
-
throw new Error("Illegal subject, must be a set of non-space characters");
|
|
241
|
-
}
|
|
242
|
-
let key;
|
|
243
|
-
try {
|
|
244
|
-
key = jose.base64url.decode(secret);
|
|
245
|
-
} catch {
|
|
246
|
-
throw new Error("Illegal secret, must be a valid base64 string");
|
|
247
|
-
}
|
|
248
|
-
if (this.#entries.some((e) => e.key === key)) {
|
|
249
|
-
throw new Error(
|
|
250
|
-
"Legacy externalAccess token was declared more than once"
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
|
-
this.#entries.push({
|
|
254
|
-
key,
|
|
255
|
-
result: {
|
|
256
|
-
subject,
|
|
257
|
-
allAccessRestrictions
|
|
258
|
-
}
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
async verifyToken(token) {
|
|
262
|
-
try {
|
|
263
|
-
const { alg } = jose.decodeProtectedHeader(token);
|
|
264
|
-
if (alg !== "HS256") {
|
|
265
|
-
return void 0;
|
|
266
|
-
}
|
|
267
|
-
const { sub, aud } = jose.decodeJwt(token);
|
|
268
|
-
if (sub !== "backstage-server" || aud) {
|
|
269
|
-
return void 0;
|
|
270
|
-
}
|
|
271
|
-
} catch (e) {
|
|
272
|
-
return void 0;
|
|
273
|
-
}
|
|
274
|
-
for (const { key, result } of this.#entries) {
|
|
275
|
-
try {
|
|
276
|
-
await jose.jwtVerify(token, key);
|
|
277
|
-
return result;
|
|
278
|
-
} catch (e) {
|
|
279
|
-
if (e.code !== "ERR_JWS_SIGNATURE_VERIFICATION_FAILED") {
|
|
280
|
-
throw e;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
return void 0;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const MIN_TOKEN_LENGTH = 8;
|
|
289
|
-
class StaticTokenHandler {
|
|
290
|
-
#entries = /* @__PURE__ */ new Map();
|
|
291
|
-
add(config) {
|
|
292
|
-
const token = config.getString("options.token");
|
|
293
|
-
const subject = config.getString("options.subject");
|
|
294
|
-
const allAccessRestrictions = readAccessRestrictionsFromConfig(config);
|
|
295
|
-
if (!token.match(/^\S+$/)) {
|
|
296
|
-
throw new Error("Illegal token, must be a set of non-space characters");
|
|
297
|
-
} else if (token.length < MIN_TOKEN_LENGTH) {
|
|
298
|
-
throw new Error(
|
|
299
|
-
`Illegal token, must be at least ${MIN_TOKEN_LENGTH} characters length`
|
|
300
|
-
);
|
|
301
|
-
} else if (!subject.match(/^\S+$/)) {
|
|
302
|
-
throw new Error("Illegal subject, must be a set of non-space characters");
|
|
303
|
-
} else if (this.#entries.has(token)) {
|
|
304
|
-
throw new Error(
|
|
305
|
-
"Static externalAccess token was declared more than once"
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
this.#entries.set(token, { subject, allAccessRestrictions });
|
|
309
|
-
}
|
|
310
|
-
async verifyToken(token) {
|
|
311
|
-
return this.#entries.get(token);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
class JWKSHandler {
|
|
316
|
-
#entries = [];
|
|
317
|
-
add(config) {
|
|
318
|
-
if (!config.getString("options.url").match(/^\S+$/)) {
|
|
319
|
-
throw new Error(
|
|
320
|
-
"Illegal JWKS URL, must be a set of non-space characters"
|
|
321
|
-
);
|
|
322
|
-
}
|
|
323
|
-
const algorithms = readStringOrStringArrayFromConfig(
|
|
324
|
-
config,
|
|
325
|
-
"options.algorithm"
|
|
326
|
-
);
|
|
327
|
-
const issuers = readStringOrStringArrayFromConfig(config, "options.issuer");
|
|
328
|
-
const audiences = readStringOrStringArrayFromConfig(
|
|
329
|
-
config,
|
|
330
|
-
"options.audience"
|
|
331
|
-
);
|
|
332
|
-
const subjectPrefix = config.getOptionalString("options.subjectPrefix");
|
|
333
|
-
const url = new URL(config.getString("options.url"));
|
|
334
|
-
const jwks = jose.createRemoteJWKSet(url);
|
|
335
|
-
const allAccessRestrictions = readAccessRestrictionsFromConfig(config);
|
|
336
|
-
this.#entries.push({
|
|
337
|
-
algorithms,
|
|
338
|
-
audiences,
|
|
339
|
-
issuers,
|
|
340
|
-
jwks,
|
|
341
|
-
subjectPrefix,
|
|
342
|
-
url,
|
|
343
|
-
allAccessRestrictions
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
async verifyToken(token) {
|
|
347
|
-
for (const entry of this.#entries) {
|
|
348
|
-
try {
|
|
349
|
-
const {
|
|
350
|
-
payload: { sub }
|
|
351
|
-
} = await jose.jwtVerify(token, entry.jwks, {
|
|
352
|
-
algorithms: entry.algorithms,
|
|
353
|
-
issuer: entry.issuers,
|
|
354
|
-
audience: entry.audiences
|
|
355
|
-
});
|
|
356
|
-
if (sub) {
|
|
357
|
-
const prefix = entry.subjectPrefix ? `external:${entry.subjectPrefix}:` : "external:";
|
|
358
|
-
return {
|
|
359
|
-
subject: `${prefix}${sub}`,
|
|
360
|
-
allAccessRestrictions: entry.allAccessRestrictions
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
} catch {
|
|
364
|
-
continue;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
return void 0;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const NEW_CONFIG_KEY = "backend.auth.externalAccess";
|
|
372
|
-
const OLD_CONFIG_KEY = "backend.auth.keys";
|
|
373
|
-
let loggedDeprecationWarning = false;
|
|
374
|
-
class ExternalTokenHandler {
|
|
375
|
-
constructor(ownPluginId, handlers) {
|
|
376
|
-
this.ownPluginId = ownPluginId;
|
|
377
|
-
this.handlers = handlers;
|
|
378
|
-
}
|
|
379
|
-
static create(options) {
|
|
380
|
-
const { ownPluginId, config, logger } = options;
|
|
381
|
-
const staticHandler = new StaticTokenHandler();
|
|
382
|
-
const legacyHandler = new LegacyTokenHandler();
|
|
383
|
-
const jwksHandler = new JWKSHandler();
|
|
384
|
-
const handlers = {
|
|
385
|
-
static: staticHandler,
|
|
386
|
-
legacy: legacyHandler,
|
|
387
|
-
jwks: jwksHandler
|
|
388
|
-
};
|
|
389
|
-
const handlerConfigs = config.getOptionalConfigArray(NEW_CONFIG_KEY) ?? [];
|
|
390
|
-
for (const handlerConfig of handlerConfigs) {
|
|
391
|
-
const type = handlerConfig.getString("type");
|
|
392
|
-
const handler = handlers[type];
|
|
393
|
-
if (!handler) {
|
|
394
|
-
const valid = Object.keys(handlers).map((k) => `'${k}'`).join(", ");
|
|
395
|
-
throw new Error(
|
|
396
|
-
`Unknown type '${type}' in ${NEW_CONFIG_KEY}, expected one of ${valid}`
|
|
397
|
-
);
|
|
398
|
-
}
|
|
399
|
-
handler.add(handlerConfig);
|
|
400
|
-
}
|
|
401
|
-
const legacyConfigs = config.getOptionalConfigArray(OLD_CONFIG_KEY) ?? [];
|
|
402
|
-
if (legacyConfigs.length && !loggedDeprecationWarning) {
|
|
403
|
-
loggedDeprecationWarning = true;
|
|
404
|
-
logger.warn(
|
|
405
|
-
`DEPRECATION WARNING: The ${OLD_CONFIG_KEY} config has been replaced by ${NEW_CONFIG_KEY}, see https://backstage.io/docs/auth/service-to-service-auth`
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
for (const handlerConfig of legacyConfigs) {
|
|
409
|
-
legacyHandler.addOld(handlerConfig);
|
|
410
|
-
}
|
|
411
|
-
return new ExternalTokenHandler(ownPluginId, Object.values(handlers));
|
|
412
|
-
}
|
|
413
|
-
async verifyToken(token) {
|
|
414
|
-
for (const handler of this.handlers) {
|
|
415
|
-
const result = await handler.verifyToken(token);
|
|
416
|
-
if (result) {
|
|
417
|
-
const { allAccessRestrictions, ...rest } = result;
|
|
418
|
-
if (allAccessRestrictions) {
|
|
419
|
-
const accessRestrictions = allAccessRestrictions.get(
|
|
420
|
-
this.ownPluginId
|
|
421
|
-
);
|
|
422
|
-
if (!accessRestrictions) {
|
|
423
|
-
const valid = [...allAccessRestrictions.keys()].map((k) => `'${k}'`).join(", ");
|
|
424
|
-
throw new errors.NotAllowedError(
|
|
425
|
-
`This token's access is restricted to plugin(s) ${valid}`
|
|
426
|
-
);
|
|
427
|
-
}
|
|
428
|
-
return {
|
|
429
|
-
...rest,
|
|
430
|
-
accessRestrictions
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
return rest;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
return void 0;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
const CLOCK_MARGIN_S = 10;
|
|
441
|
-
class JwksClient {
|
|
442
|
-
constructor(getEndpoint) {
|
|
443
|
-
this.getEndpoint = getEndpoint;
|
|
444
|
-
}
|
|
445
|
-
#keyStore;
|
|
446
|
-
#keyStoreUpdated = 0;
|
|
447
|
-
get getKey() {
|
|
448
|
-
if (!this.#keyStore) {
|
|
449
|
-
throw new errors.AuthenticationError(
|
|
450
|
-
"refreshKeyStore must be called before jwksClient.getKey"
|
|
451
|
-
);
|
|
452
|
-
}
|
|
453
|
-
return this.#keyStore;
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
|
-
* If the last keystore refresh is stale, update the keystore URL to the latest
|
|
457
|
-
*/
|
|
458
|
-
async refreshKeyStore(rawJwtToken) {
|
|
459
|
-
const payload = await jose.decodeJwt(rawJwtToken);
|
|
460
|
-
const header = await jose.decodeProtectedHeader(rawJwtToken);
|
|
461
|
-
let keyStoreHasKey;
|
|
462
|
-
try {
|
|
463
|
-
if (this.#keyStore) {
|
|
464
|
-
const [_, rawPayload, rawSignature] = rawJwtToken.split(".");
|
|
465
|
-
keyStoreHasKey = await this.#keyStore(header, {
|
|
466
|
-
payload: rawPayload,
|
|
467
|
-
signature: rawSignature
|
|
468
|
-
});
|
|
469
|
-
}
|
|
470
|
-
} catch (error) {
|
|
471
|
-
keyStoreHasKey = false;
|
|
472
|
-
}
|
|
473
|
-
const issuedAfterLastRefresh = payload?.iat && payload.iat > this.#keyStoreUpdated - CLOCK_MARGIN_S;
|
|
474
|
-
if (!this.#keyStore || !keyStoreHasKey && issuedAfterLastRefresh) {
|
|
475
|
-
const endpoint = await this.getEndpoint();
|
|
476
|
-
this.#keyStore = jose.createRemoteJWKSet(endpoint);
|
|
477
|
-
this.#keyStoreUpdated = Date.now() / 1e3;
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
const SECONDS_IN_MS$2 = 1e3;
|
|
483
|
-
const ALLOWED_PLUGIN_ID_PATTERN = /^[a-z0-9_-]+$/i;
|
|
484
|
-
class PluginTokenHandler {
|
|
485
|
-
constructor(logger, ownPluginId, keySource, algorithm, keyDurationSeconds, discovery) {
|
|
486
|
-
this.logger = logger;
|
|
487
|
-
this.ownPluginId = ownPluginId;
|
|
488
|
-
this.keySource = keySource;
|
|
489
|
-
this.algorithm = algorithm;
|
|
490
|
-
this.keyDurationSeconds = keyDurationSeconds;
|
|
491
|
-
this.discovery = discovery;
|
|
492
|
-
}
|
|
493
|
-
jwksMap = /* @__PURE__ */ new Map();
|
|
494
|
-
// Tracking state for isTargetPluginSupported
|
|
495
|
-
supportedTargetPlugins = /* @__PURE__ */ new Set();
|
|
496
|
-
targetPluginInflightChecks = /* @__PURE__ */ new Map();
|
|
497
|
-
static create(options) {
|
|
498
|
-
return new PluginTokenHandler(
|
|
499
|
-
options.logger,
|
|
500
|
-
options.ownPluginId,
|
|
501
|
-
options.keySource,
|
|
502
|
-
options.algorithm ?? "ES256",
|
|
503
|
-
Math.round(types.durationToMilliseconds(options.keyDuration) / 1e3),
|
|
504
|
-
options.discovery
|
|
505
|
-
);
|
|
506
|
-
}
|
|
507
|
-
async verifyToken(token) {
|
|
508
|
-
try {
|
|
509
|
-
const { typ } = jose.decodeProtectedHeader(token);
|
|
510
|
-
if (typ !== pluginAuthNode.tokenTypes.plugin.typParam) {
|
|
511
|
-
return void 0;
|
|
512
|
-
}
|
|
513
|
-
} catch {
|
|
514
|
-
return void 0;
|
|
515
|
-
}
|
|
516
|
-
const pluginId = String(jose.decodeJwt(token).sub);
|
|
517
|
-
if (!pluginId) {
|
|
518
|
-
throw new errors.AuthenticationError("Invalid plugin token: missing subject");
|
|
519
|
-
}
|
|
520
|
-
if (!ALLOWED_PLUGIN_ID_PATTERN.test(pluginId)) {
|
|
521
|
-
throw new errors.AuthenticationError(
|
|
522
|
-
"Invalid plugin token: forbidden subject format"
|
|
523
|
-
);
|
|
524
|
-
}
|
|
525
|
-
const jwksClient = await this.getJwksClient(pluginId);
|
|
526
|
-
await jwksClient.refreshKeyStore(token);
|
|
527
|
-
const { payload } = await jose.jwtVerify(
|
|
528
|
-
token,
|
|
529
|
-
jwksClient.getKey,
|
|
530
|
-
{
|
|
531
|
-
typ: pluginAuthNode.tokenTypes.plugin.typParam,
|
|
532
|
-
audience: this.ownPluginId,
|
|
533
|
-
requiredClaims: ["iat", "exp", "sub", "aud"]
|
|
534
|
-
}
|
|
535
|
-
).catch((e) => {
|
|
536
|
-
throw new errors.AuthenticationError("Invalid plugin token", e);
|
|
537
|
-
});
|
|
538
|
-
return { subject: `plugin:${payload.sub}`, limitedUserToken: payload.obo };
|
|
539
|
-
}
|
|
540
|
-
async issueToken(options) {
|
|
541
|
-
const { pluginId, targetPluginId, onBehalfOf } = options;
|
|
542
|
-
const key = await this.keySource.getPrivateSigningKey();
|
|
543
|
-
const sub = pluginId;
|
|
544
|
-
const aud = targetPluginId;
|
|
545
|
-
const iat = Math.floor(Date.now() / SECONDS_IN_MS$2);
|
|
546
|
-
const ourExp = iat + this.keyDurationSeconds;
|
|
547
|
-
const exp = onBehalfOf ? Math.min(
|
|
548
|
-
ourExp,
|
|
549
|
-
Math.floor(onBehalfOf.expiresAt.getTime() / SECONDS_IN_MS$2)
|
|
550
|
-
) : ourExp;
|
|
551
|
-
const claims = { sub, aud, iat, exp, obo: onBehalfOf?.token };
|
|
552
|
-
const token = await new jose.SignJWT(claims).setProtectedHeader({
|
|
553
|
-
typ: pluginAuthNode.tokenTypes.plugin.typParam,
|
|
554
|
-
alg: this.algorithm,
|
|
555
|
-
kid: key.kid
|
|
556
|
-
}).setAudience(aud).setSubject(sub).setIssuedAt(iat).setExpirationTime(exp).sign(await jose.importJWK(key));
|
|
557
|
-
return { token };
|
|
558
|
-
}
|
|
559
|
-
async isTargetPluginSupported(targetPluginId) {
|
|
560
|
-
if (this.supportedTargetPlugins.has(targetPluginId)) {
|
|
561
|
-
return true;
|
|
562
|
-
}
|
|
563
|
-
const inFlight = this.targetPluginInflightChecks.get(targetPluginId);
|
|
564
|
-
if (inFlight) {
|
|
565
|
-
return inFlight;
|
|
566
|
-
}
|
|
567
|
-
const doCheck = async () => {
|
|
568
|
-
try {
|
|
569
|
-
const res = await fetch(
|
|
570
|
-
`${await this.discovery.getBaseUrl(
|
|
571
|
-
targetPluginId
|
|
572
|
-
)}/.backstage/auth/v1/jwks.json`
|
|
573
|
-
);
|
|
574
|
-
if (res.status === 404) {
|
|
575
|
-
return false;
|
|
576
|
-
}
|
|
577
|
-
if (!res.ok) {
|
|
578
|
-
throw new Error(`Failed to fetch jwks.json, ${res.status}`);
|
|
579
|
-
}
|
|
580
|
-
const data = await res.json();
|
|
581
|
-
if (!data.keys) {
|
|
582
|
-
throw new Error(`Invalid jwks.json response, missing keys`);
|
|
583
|
-
}
|
|
584
|
-
this.supportedTargetPlugins.add(targetPluginId);
|
|
585
|
-
return true;
|
|
586
|
-
} catch (error) {
|
|
587
|
-
this.logger.error("Unexpected failure for target JWKS check", error);
|
|
588
|
-
return false;
|
|
589
|
-
} finally {
|
|
590
|
-
this.targetPluginInflightChecks.delete(targetPluginId);
|
|
591
|
-
}
|
|
592
|
-
};
|
|
593
|
-
const check = doCheck();
|
|
594
|
-
this.targetPluginInflightChecks.set(targetPluginId, check);
|
|
595
|
-
return check;
|
|
596
|
-
}
|
|
597
|
-
async getJwksClient(pluginId) {
|
|
598
|
-
const client = this.jwksMap.get(pluginId);
|
|
599
|
-
if (client) {
|
|
600
|
-
return client;
|
|
601
|
-
}
|
|
602
|
-
if (!await this.isTargetPluginSupported(pluginId)) {
|
|
603
|
-
throw new errors.AuthenticationError(
|
|
604
|
-
`Received a plugin token where the source '${pluginId}' plugin unexpectedly does not have a JWKS endpoint. The target plugin needs to be migrated to be installed in an app using the new backend system.`
|
|
605
|
-
);
|
|
606
|
-
}
|
|
607
|
-
const newClient = new JwksClient(async () => {
|
|
608
|
-
return new URL(
|
|
609
|
-
`${await this.discovery.getBaseUrl(
|
|
610
|
-
pluginId
|
|
611
|
-
)}/.backstage/auth/v1/jwks.json`
|
|
612
|
-
);
|
|
613
|
-
});
|
|
614
|
-
this.jwksMap.set(pluginId, newClient);
|
|
615
|
-
return newClient;
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
const MIGRATIONS_TABLE = "backstage_backend_public_keys__knex_migrations";
|
|
620
|
-
const TABLE = "backstage_backend_public_keys__keys";
|
|
621
|
-
function applyDatabaseMigrations(knex) {
|
|
622
|
-
const migrationsDir = backendPluginApi.resolvePackagePath(
|
|
623
|
-
"@backstage/backend-defaults",
|
|
624
|
-
"migrations/auth"
|
|
625
|
-
);
|
|
626
|
-
return knex.migrate.latest({
|
|
627
|
-
directory: migrationsDir,
|
|
628
|
-
tableName: MIGRATIONS_TABLE
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
class DatabaseKeyStore {
|
|
632
|
-
constructor(client, logger) {
|
|
633
|
-
this.client = client;
|
|
634
|
-
this.logger = logger;
|
|
635
|
-
}
|
|
636
|
-
static async create(options) {
|
|
637
|
-
const { database, logger } = options;
|
|
638
|
-
const client = await database.getClient();
|
|
639
|
-
if (!database.migrations?.skip) {
|
|
640
|
-
await applyDatabaseMigrations(client);
|
|
641
|
-
}
|
|
642
|
-
return new DatabaseKeyStore(client, logger);
|
|
643
|
-
}
|
|
644
|
-
async addKey(options) {
|
|
645
|
-
await this.client(TABLE).insert({
|
|
646
|
-
id: options.key.kid,
|
|
647
|
-
key: JSON.stringify(options.key),
|
|
648
|
-
expires_at: options.expiresAt.toISOString()
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
async listKeys() {
|
|
652
|
-
const rows = await this.client(TABLE).select();
|
|
653
|
-
const keys = rows.map((row) => ({
|
|
654
|
-
id: row.id,
|
|
655
|
-
key: JSON.parse(row.key),
|
|
656
|
-
expiresAt: new Date(row.expires_at)
|
|
657
|
-
}));
|
|
658
|
-
const validKeys = [];
|
|
659
|
-
const expiredKeys = [];
|
|
660
|
-
for (const key of keys) {
|
|
661
|
-
if (luxon.DateTime.fromJSDate(key.expiresAt) < luxon.DateTime.local()) {
|
|
662
|
-
expiredKeys.push(key);
|
|
663
|
-
} else {
|
|
664
|
-
validKeys.push(key);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
if (expiredKeys.length > 0) {
|
|
668
|
-
const kids = expiredKeys.map(({ key }) => key.kid);
|
|
669
|
-
this.logger.info(
|
|
670
|
-
`Removing expired plugin service keys, '${kids.join("', '")}'`
|
|
671
|
-
);
|
|
672
|
-
this.client(TABLE).delete().whereIn("id", kids).catch((error) => {
|
|
673
|
-
this.logger.error(
|
|
674
|
-
"Failed to remove expired plugin service keys",
|
|
675
|
-
error
|
|
676
|
-
);
|
|
677
|
-
});
|
|
678
|
-
}
|
|
679
|
-
return { keys: validKeys };
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
const SECONDS_IN_MS$1 = 1e3;
|
|
684
|
-
const KEY_EXPIRATION_MARGIN_FACTOR = 3;
|
|
685
|
-
class DatabasePluginKeySource {
|
|
686
|
-
constructor(keyStore, logger, keyDurationSeconds, algorithm) {
|
|
687
|
-
this.keyStore = keyStore;
|
|
688
|
-
this.logger = logger;
|
|
689
|
-
this.keyDurationSeconds = keyDurationSeconds;
|
|
690
|
-
this.algorithm = algorithm;
|
|
691
|
-
}
|
|
692
|
-
privateKeyPromise;
|
|
693
|
-
keyExpiry;
|
|
694
|
-
static async create(options) {
|
|
695
|
-
const keyStore = await DatabaseKeyStore.create({
|
|
696
|
-
database: options.database,
|
|
697
|
-
logger: options.logger
|
|
698
|
-
});
|
|
699
|
-
return new DatabasePluginKeySource(
|
|
700
|
-
keyStore,
|
|
701
|
-
options.logger,
|
|
702
|
-
Math.round(types.durationToMilliseconds(options.keyDuration) / 1e3),
|
|
703
|
-
options.algorithm ?? "ES256"
|
|
704
|
-
);
|
|
705
|
-
}
|
|
706
|
-
async getPrivateSigningKey() {
|
|
707
|
-
if (this.privateKeyPromise) {
|
|
708
|
-
if (this.keyExpiry && this.keyExpiry.getTime() > Date.now()) {
|
|
709
|
-
return this.privateKeyPromise;
|
|
710
|
-
}
|
|
711
|
-
this.logger.info(`Signing key has expired, generating new key`);
|
|
712
|
-
delete this.privateKeyPromise;
|
|
713
|
-
}
|
|
714
|
-
this.keyExpiry = new Date(
|
|
715
|
-
Date.now() + this.keyDurationSeconds * SECONDS_IN_MS$1
|
|
716
|
-
);
|
|
717
|
-
const promise = (async () => {
|
|
718
|
-
const kid = uuid.v4();
|
|
719
|
-
const key = await jose.generateKeyPair(this.algorithm);
|
|
720
|
-
const publicKey = await jose.exportJWK(key.publicKey);
|
|
721
|
-
const privateKey = await jose.exportJWK(key.privateKey);
|
|
722
|
-
publicKey.kid = privateKey.kid = kid;
|
|
723
|
-
publicKey.alg = privateKey.alg = this.algorithm;
|
|
724
|
-
this.logger.info(`Created new signing key ${kid}`);
|
|
725
|
-
await this.keyStore.addKey({
|
|
726
|
-
id: kid,
|
|
727
|
-
key: publicKey,
|
|
728
|
-
expiresAt: new Date(
|
|
729
|
-
Date.now() + this.keyDurationSeconds * SECONDS_IN_MS$1 * KEY_EXPIRATION_MARGIN_FACTOR
|
|
730
|
-
)
|
|
731
|
-
});
|
|
732
|
-
return privateKey;
|
|
733
|
-
})();
|
|
734
|
-
this.privateKeyPromise = promise;
|
|
735
|
-
try {
|
|
736
|
-
await promise;
|
|
737
|
-
} catch (error) {
|
|
738
|
-
this.logger.error(`Failed to generate new signing key, ${error}`);
|
|
739
|
-
delete this.keyExpiry;
|
|
740
|
-
delete this.privateKeyPromise;
|
|
741
|
-
}
|
|
742
|
-
return promise;
|
|
743
|
-
}
|
|
744
|
-
listKeys() {
|
|
745
|
-
return this.keyStore.listKeys();
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
const DEFAULT_ALGORITHM = "ES256";
|
|
750
|
-
const SECONDS_IN_MS = 1e3;
|
|
751
|
-
class StaticConfigPluginKeySource {
|
|
752
|
-
constructor(keyPairs, keyDurationSeconds) {
|
|
753
|
-
this.keyPairs = keyPairs;
|
|
754
|
-
this.keyDurationSeconds = keyDurationSeconds;
|
|
755
|
-
}
|
|
756
|
-
static async create(options) {
|
|
757
|
-
const keyConfigs = options.sourceConfig.getConfigArray("static.keys").map((c) => {
|
|
758
|
-
const staticKeyConfig = {
|
|
759
|
-
publicKeyFile: c.getString("publicKeyFile"),
|
|
760
|
-
privateKeyFile: c.getOptionalString("privateKeyFile"),
|
|
761
|
-
keyId: c.getString("keyId"),
|
|
762
|
-
algorithm: c.getOptionalString("algorithm") ?? DEFAULT_ALGORITHM
|
|
763
|
-
};
|
|
764
|
-
return staticKeyConfig;
|
|
765
|
-
});
|
|
766
|
-
const keyPairs = await Promise.all(
|
|
767
|
-
keyConfigs.map(async (k) => await this.loadKeyPair(k))
|
|
768
|
-
);
|
|
769
|
-
if (keyPairs.length < 1) {
|
|
770
|
-
throw new Error(
|
|
771
|
-
"At least one key pair must be provided in static.keys, when the static key store type is used"
|
|
772
|
-
);
|
|
773
|
-
} else if (!keyPairs[0].privateKey) {
|
|
774
|
-
throw new Error(
|
|
775
|
-
"Private key for signing must be provided in the first key pair in static.keys, when the static key store type is used"
|
|
776
|
-
);
|
|
777
|
-
}
|
|
778
|
-
return new StaticConfigPluginKeySource(
|
|
779
|
-
keyPairs,
|
|
780
|
-
types.durationToMilliseconds(options.keyDuration) / SECONDS_IN_MS
|
|
781
|
-
);
|
|
782
|
-
}
|
|
783
|
-
async getPrivateSigningKey() {
|
|
784
|
-
return this.keyPairs[0].privateKey;
|
|
785
|
-
}
|
|
786
|
-
async listKeys() {
|
|
787
|
-
const keys = this.keyPairs.map((k) => this.keyPairToStoredKey(k));
|
|
788
|
-
return { keys };
|
|
789
|
-
}
|
|
790
|
-
static async loadKeyPair(options) {
|
|
791
|
-
const algorithm = options.algorithm;
|
|
792
|
-
const keyId = options.keyId;
|
|
793
|
-
const publicKey = await this.loadPublicKeyFromFile(
|
|
794
|
-
options.publicKeyFile,
|
|
795
|
-
keyId,
|
|
796
|
-
algorithm
|
|
797
|
-
);
|
|
798
|
-
const privateKey = options.privateKeyFile ? await this.loadPrivateKeyFromFile(
|
|
799
|
-
options.privateKeyFile,
|
|
800
|
-
keyId,
|
|
801
|
-
algorithm
|
|
802
|
-
) : void 0;
|
|
803
|
-
return { publicKey, privateKey, keyId };
|
|
804
|
-
}
|
|
805
|
-
static async loadPublicKeyFromFile(path, keyId, algorithm) {
|
|
806
|
-
return this.loadKeyFromFile(path, keyId, algorithm, jose.importSPKI);
|
|
807
|
-
}
|
|
808
|
-
static async loadPrivateKeyFromFile(path, keyId, algorithm) {
|
|
809
|
-
return this.loadKeyFromFile(path, keyId, algorithm, jose.importPKCS8);
|
|
810
|
-
}
|
|
811
|
-
static async loadKeyFromFile(path, keyId, algorithm, importer) {
|
|
812
|
-
const content = await fs.promises.readFile(path, { encoding: "utf8", flag: "r" });
|
|
813
|
-
const key = await importer(content, algorithm);
|
|
814
|
-
const jwk = await jose.exportJWK(key);
|
|
815
|
-
jwk.kid = keyId;
|
|
816
|
-
jwk.alg = algorithm;
|
|
817
|
-
return jwk;
|
|
818
|
-
}
|
|
819
|
-
keyPairToStoredKey(keyPair) {
|
|
820
|
-
const publicKey = {
|
|
821
|
-
...keyPair.publicKey,
|
|
822
|
-
kid: keyPair.keyId
|
|
823
|
-
};
|
|
824
|
-
return {
|
|
825
|
-
key: publicKey,
|
|
826
|
-
id: keyPair.keyId,
|
|
827
|
-
expiresAt: new Date(Date.now() + this.keyDurationSeconds * SECONDS_IN_MS)
|
|
828
|
-
};
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
const CONFIG_ROOT_KEY = "backend.auth.pluginKeyStore";
|
|
833
|
-
async function createPluginKeySource(options) {
|
|
834
|
-
const keyStoreConfig = options.config.getOptionalConfig(CONFIG_ROOT_KEY);
|
|
835
|
-
const type = keyStoreConfig?.getOptionalString("type") ?? "database";
|
|
836
|
-
if (!keyStoreConfig || type === "database") {
|
|
837
|
-
return DatabasePluginKeySource.create({
|
|
838
|
-
database: options.database,
|
|
839
|
-
logger: options.logger,
|
|
840
|
-
keyDuration: options.keyDuration,
|
|
841
|
-
algorithm: options.algorithm
|
|
842
|
-
});
|
|
843
|
-
} else if (type === "static") {
|
|
844
|
-
return StaticConfigPluginKeySource.create({
|
|
845
|
-
sourceConfig: keyStoreConfig,
|
|
846
|
-
keyDuration: options.keyDuration
|
|
847
|
-
});
|
|
848
|
-
}
|
|
849
|
-
throw new Error(
|
|
850
|
-
`Unsupported config value ${CONFIG_ROOT_KEY}.type '${type}'; expected one of 'database', 'static'`
|
|
851
|
-
);
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
class UserTokenHandler {
|
|
855
|
-
constructor(jwksClient) {
|
|
856
|
-
this.jwksClient = jwksClient;
|
|
857
|
-
}
|
|
858
|
-
static create(options) {
|
|
859
|
-
const jwksClient = new JwksClient(async () => {
|
|
860
|
-
const url = await options.discovery.getBaseUrl("auth");
|
|
861
|
-
return new URL(`${url}/.well-known/jwks.json`);
|
|
862
|
-
});
|
|
863
|
-
return new UserTokenHandler(jwksClient);
|
|
864
|
-
}
|
|
865
|
-
async verifyToken(token) {
|
|
866
|
-
const verifyOpts = this.#getTokenVerificationOptions(token);
|
|
867
|
-
if (!verifyOpts) {
|
|
868
|
-
return void 0;
|
|
869
|
-
}
|
|
870
|
-
await this.jwksClient.refreshKeyStore(token);
|
|
871
|
-
const { payload } = await jose.jwtVerify(
|
|
872
|
-
token,
|
|
873
|
-
this.jwksClient.getKey,
|
|
874
|
-
verifyOpts
|
|
875
|
-
).catch((e) => {
|
|
876
|
-
throw new errors.AuthenticationError("Invalid token", e);
|
|
877
|
-
});
|
|
878
|
-
const userEntityRef = payload.sub;
|
|
879
|
-
if (!userEntityRef) {
|
|
880
|
-
throw new errors.AuthenticationError("No user sub found in token");
|
|
881
|
-
}
|
|
882
|
-
return { userEntityRef };
|
|
883
|
-
}
|
|
884
|
-
#getTokenVerificationOptions(token) {
|
|
885
|
-
try {
|
|
886
|
-
const { typ } = jose.decodeProtectedHeader(token);
|
|
887
|
-
if (typ === pluginAuthNode.tokenTypes.user.typParam) {
|
|
888
|
-
return {
|
|
889
|
-
requiredClaims: ["iat", "exp", "sub"],
|
|
890
|
-
typ: pluginAuthNode.tokenTypes.user.typParam
|
|
891
|
-
};
|
|
892
|
-
}
|
|
893
|
-
if (typ === pluginAuthNode.tokenTypes.limitedUser.typParam) {
|
|
894
|
-
return {
|
|
895
|
-
requiredClaims: ["iat", "exp", "sub"],
|
|
896
|
-
typ: pluginAuthNode.tokenTypes.limitedUser.typParam
|
|
897
|
-
};
|
|
898
|
-
}
|
|
899
|
-
const { aud } = jose.decodeJwt(token);
|
|
900
|
-
if (aud === pluginAuthNode.tokenTypes.user.audClaim) {
|
|
901
|
-
return {
|
|
902
|
-
audience: pluginAuthNode.tokenTypes.user.audClaim
|
|
903
|
-
};
|
|
904
|
-
}
|
|
905
|
-
} catch {
|
|
906
|
-
}
|
|
907
|
-
return void 0;
|
|
908
|
-
}
|
|
909
|
-
createLimitedUserToken(backstageToken) {
|
|
910
|
-
const [headerRaw, payloadRaw] = backstageToken.split(".");
|
|
911
|
-
const header = JSON.parse(
|
|
912
|
-
new TextDecoder().decode(jose.base64url.decode(headerRaw))
|
|
913
|
-
);
|
|
914
|
-
const payload = JSON.parse(
|
|
915
|
-
new TextDecoder().decode(jose.base64url.decode(payloadRaw))
|
|
916
|
-
);
|
|
917
|
-
const tokenType = header.typ;
|
|
918
|
-
if (!tokenType || tokenType === pluginAuthNode.tokenTypes.limitedUser.typParam) {
|
|
919
|
-
return { token: backstageToken, expiresAt: new Date(payload.exp * 1e3) };
|
|
920
|
-
}
|
|
921
|
-
if (tokenType !== pluginAuthNode.tokenTypes.user.typParam) {
|
|
922
|
-
throw new errors.AuthenticationError(
|
|
923
|
-
"Failed to create limited user token, invalid token type"
|
|
924
|
-
);
|
|
925
|
-
}
|
|
926
|
-
const limitedUserToken = [
|
|
927
|
-
jose.base64url.encode(
|
|
928
|
-
JSON.stringify({
|
|
929
|
-
typ: pluginAuthNode.tokenTypes.limitedUser.typParam,
|
|
930
|
-
alg: header.alg,
|
|
931
|
-
kid: header.kid
|
|
932
|
-
})
|
|
933
|
-
),
|
|
934
|
-
jose.base64url.encode(
|
|
935
|
-
JSON.stringify({
|
|
936
|
-
sub: payload.sub,
|
|
937
|
-
iat: payload.iat,
|
|
938
|
-
exp: payload.exp
|
|
939
|
-
})
|
|
940
|
-
),
|
|
941
|
-
payload.uip
|
|
942
|
-
].join(".");
|
|
943
|
-
return { token: limitedUserToken, expiresAt: new Date(payload.exp * 1e3) };
|
|
944
|
-
}
|
|
945
|
-
isLimitedUserToken(token) {
|
|
946
|
-
try {
|
|
947
|
-
const { typ } = jose.decodeProtectedHeader(token);
|
|
948
|
-
return typ === pluginAuthNode.tokenTypes.limitedUser.typParam;
|
|
949
|
-
} catch {
|
|
950
|
-
return false;
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
const authServiceFactory = backendPluginApi.createServiceFactory({
|
|
956
|
-
service: backendPluginApi.coreServices.auth,
|
|
957
|
-
deps: {
|
|
958
|
-
config: backendPluginApi.coreServices.rootConfig,
|
|
959
|
-
logger: backendPluginApi.coreServices.rootLogger,
|
|
960
|
-
discovery: backendPluginApi.coreServices.discovery,
|
|
961
|
-
plugin: backendPluginApi.coreServices.pluginMetadata,
|
|
962
|
-
database: backendPluginApi.coreServices.database
|
|
963
|
-
},
|
|
964
|
-
async factory({ config, discovery, plugin, logger, database }) {
|
|
965
|
-
const disableDefaultAuthPolicy = config.getOptionalBoolean(
|
|
966
|
-
"backend.auth.dangerouslyDisableDefaultAuthPolicy"
|
|
967
|
-
) ?? false;
|
|
968
|
-
const keyDuration = { hours: 1 };
|
|
969
|
-
const keySource = await createPluginKeySource({
|
|
970
|
-
config,
|
|
971
|
-
database,
|
|
972
|
-
logger,
|
|
973
|
-
keyDuration
|
|
974
|
-
});
|
|
975
|
-
const userTokens = UserTokenHandler.create({
|
|
976
|
-
discovery
|
|
977
|
-
});
|
|
978
|
-
const pluginTokens = PluginTokenHandler.create({
|
|
979
|
-
ownPluginId: plugin.getId(),
|
|
980
|
-
logger,
|
|
981
|
-
keySource,
|
|
982
|
-
keyDuration,
|
|
983
|
-
discovery
|
|
984
|
-
});
|
|
985
|
-
const externalTokens = ExternalTokenHandler.create({
|
|
986
|
-
ownPluginId: plugin.getId(),
|
|
987
|
-
config,
|
|
988
|
-
logger
|
|
989
|
-
});
|
|
990
|
-
return new DefaultAuthService(
|
|
991
|
-
userTokens,
|
|
992
|
-
pluginTokens,
|
|
993
|
-
externalTokens,
|
|
994
|
-
plugin.getId(),
|
|
995
|
-
disableDefaultAuthPolicy,
|
|
996
|
-
keySource
|
|
997
|
-
);
|
|
998
|
-
}
|
|
999
|
-
});
|
|
1000
|
-
|
|
1001
|
-
exports.authServiceFactory = authServiceFactory;
|
|
7
|
+
exports.authServiceFactory = authServiceFactory.authServiceFactory;
|
|
1002
8
|
//# sourceMappingURL=auth.cjs.js.map
|