@backstage/backend-defaults 0.5.1-next.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/auth/package.json +1 -1
  3. package/cache/package.json +1 -1
  4. package/database/package.json +1 -1
  5. package/discovery/package.json +1 -1
  6. package/dist/CreateBackend.cjs.js +49 -0
  7. package/dist/CreateBackend.cjs.js.map +1 -0
  8. package/dist/PackageDiscoveryService.cjs.js +109 -0
  9. package/dist/PackageDiscoveryService.cjs.js.map +1 -0
  10. package/dist/auth.cjs.js +2 -996
  11. package/dist/auth.cjs.js.map +1 -1
  12. package/dist/cache.cjs.js +4 -204
  13. package/dist/cache.cjs.js.map +1 -1
  14. package/dist/database.cjs.js +4 -957
  15. package/dist/database.cjs.js.map +1 -1
  16. package/dist/database.d.ts +4 -1
  17. package/dist/discovery.cjs.js +4 -92
  18. package/dist/discovery.cjs.js.map +1 -1
  19. package/dist/discoveryFeatureLoader.cjs.js +19 -0
  20. package/dist/discoveryFeatureLoader.cjs.js.map +1 -0
  21. package/dist/entrypoints/auth/DefaultAuthService.cjs.js +130 -0
  22. package/dist/entrypoints/auth/DefaultAuthService.cjs.js.map +1 -0
  23. package/dist/entrypoints/auth/JwksClient.cjs.js +49 -0
  24. package/dist/entrypoints/auth/JwksClient.cjs.js.map +1 -0
  25. package/dist/entrypoints/auth/authServiceFactory.cjs.js +57 -0
  26. package/dist/entrypoints/auth/authServiceFactory.cjs.js.map +1 -0
  27. package/dist/entrypoints/auth/external/ExternalTokenHandler.cjs.js +78 -0
  28. package/dist/entrypoints/auth/external/ExternalTokenHandler.cjs.js.map +1 -0
  29. package/dist/entrypoints/auth/external/helpers.cjs.js +92 -0
  30. package/dist/entrypoints/auth/external/helpers.cjs.js.map +1 -0
  31. package/dist/entrypoints/auth/external/jwks.cjs.js +63 -0
  32. package/dist/entrypoints/auth/external/jwks.cjs.js.map +1 -0
  33. package/dist/entrypoints/auth/external/legacy.cjs.js +73 -0
  34. package/dist/entrypoints/auth/external/legacy.cjs.js.map +1 -0
  35. package/dist/entrypoints/auth/external/static.cjs.js +33 -0
  36. package/dist/entrypoints/auth/external/static.cjs.js.map +1 -0
  37. package/dist/{cjs/helpers-D2f1CG0o.cjs.js → entrypoints/auth/helpers.cjs.js} +33 -19
  38. package/dist/entrypoints/auth/helpers.cjs.js.map +1 -0
  39. package/dist/entrypoints/auth/plugin/PluginTokenHandler.cjs.js +147 -0
  40. package/dist/entrypoints/auth/plugin/PluginTokenHandler.cjs.js.map +1 -0
  41. package/dist/entrypoints/auth/plugin/keys/DatabaseKeyStore.cjs.js +73 -0
  42. package/dist/entrypoints/auth/plugin/keys/DatabaseKeyStore.cjs.js.map +1 -0
  43. package/dist/entrypoints/auth/plugin/keys/DatabasePluginKeySource.cjs.js +75 -0
  44. package/dist/entrypoints/auth/plugin/keys/DatabasePluginKeySource.cjs.js.map +1 -0
  45. package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js +91 -0
  46. package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js.map +1 -0
  47. package/dist/entrypoints/auth/plugin/keys/createPluginKeySource.cjs.js +29 -0
  48. package/dist/entrypoints/auth/plugin/keys/createPluginKeySource.cjs.js.map +1 -0
  49. package/dist/entrypoints/auth/user/UserTokenHandler.cjs.js +110 -0
  50. package/dist/entrypoints/auth/user/UserTokenHandler.cjs.js.map +1 -0
  51. package/dist/entrypoints/cache/CacheClient.cjs.js +50 -0
  52. package/dist/entrypoints/cache/CacheClient.cjs.js.map +1 -0
  53. package/dist/entrypoints/cache/CacheManager.cjs.js +147 -0
  54. package/dist/entrypoints/cache/CacheManager.cjs.js.map +1 -0
  55. package/dist/entrypoints/cache/cacheServiceFactory.cjs.js +22 -0
  56. package/dist/entrypoints/cache/cacheServiceFactory.cjs.js.map +1 -0
  57. package/dist/entrypoints/cache/types.cjs.js +10 -0
  58. package/dist/entrypoints/cache/types.cjs.js.map +1 -0
  59. package/dist/entrypoints/database/DatabaseManager.cjs.js +176 -0
  60. package/dist/entrypoints/database/DatabaseManager.cjs.js.map +1 -0
  61. package/dist/entrypoints/database/connectors/defaultNameOverride.cjs.js +14 -0
  62. package/dist/entrypoints/database/connectors/defaultNameOverride.cjs.js.map +1 -0
  63. package/dist/entrypoints/database/connectors/defaultSchemaOverride.cjs.js +12 -0
  64. package/dist/entrypoints/database/connectors/defaultSchemaOverride.cjs.js.map +1 -0
  65. package/dist/entrypoints/database/connectors/mergeDatabaseConfig.cjs.js +10 -0
  66. package/dist/entrypoints/database/connectors/mergeDatabaseConfig.cjs.js.map +1 -0
  67. package/dist/entrypoints/database/connectors/mysql.cjs.js +278 -0
  68. package/dist/entrypoints/database/connectors/mysql.cjs.js.map +1 -0
  69. package/dist/entrypoints/database/connectors/postgres.cjs.js +304 -0
  70. package/dist/entrypoints/database/connectors/postgres.cjs.js.map +1 -0
  71. package/dist/entrypoints/database/connectors/sqlite3.cjs.js +251 -0
  72. package/dist/entrypoints/database/connectors/sqlite3.cjs.js.map +1 -0
  73. package/dist/entrypoints/database/databaseServiceFactory.cjs.js +36 -0
  74. package/dist/entrypoints/database/databaseServiceFactory.cjs.js.map +1 -0
  75. package/dist/entrypoints/discovery/HostDiscovery.cjs.js +86 -0
  76. package/dist/entrypoints/discovery/HostDiscovery.cjs.js.map +1 -0
  77. package/dist/entrypoints/discovery/discoveryServiceFactory.cjs.js +17 -0
  78. package/dist/entrypoints/discovery/discoveryServiceFactory.cjs.js.map +1 -0
  79. package/dist/entrypoints/httpAuth/httpAuthServiceFactory.cjs.js +192 -0
  80. package/dist/entrypoints/httpAuth/httpAuthServiceFactory.cjs.js.map +1 -0
  81. package/dist/entrypoints/httpRouter/createAuthIntegrationRouter.cjs.js +19 -0
  82. package/dist/entrypoints/httpRouter/createAuthIntegrationRouter.cjs.js.map +1 -0
  83. package/dist/entrypoints/httpRouter/createCookieAuthRefreshMiddleware.cjs.js +26 -0
  84. package/dist/entrypoints/httpRouter/createCookieAuthRefreshMiddleware.cjs.js.map +1 -0
  85. package/dist/entrypoints/httpRouter/createCredentialsBarrier.cjs.js +63 -0
  86. package/dist/entrypoints/httpRouter/createCredentialsBarrier.cjs.js.map +1 -0
  87. package/dist/entrypoints/httpRouter/createLifecycleMiddleware.cjs.js +52 -0
  88. package/dist/entrypoints/httpRouter/createLifecycleMiddleware.cjs.js.map +1 -0
  89. package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js +48 -0
  90. package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js.map +1 -0
  91. package/dist/entrypoints/lifecycle/lifecycleServiceFactory.cjs.js +88 -0
  92. package/dist/entrypoints/lifecycle/lifecycleServiceFactory.cjs.js.map +1 -0
  93. package/dist/entrypoints/logger/loggerServiceFactory.cjs.js +17 -0
  94. package/dist/entrypoints/logger/loggerServiceFactory.cjs.js.map +1 -0
  95. package/dist/entrypoints/permissions/permissionsServiceFactory.cjs.js +22 -0
  96. package/dist/entrypoints/permissions/permissionsServiceFactory.cjs.js.map +1 -0
  97. package/dist/{cjs/createConfigSecretEnumerator-DShyoWWL.cjs.js → entrypoints/rootConfig/createConfigSecretEnumerator.cjs.js} +1 -1
  98. package/dist/entrypoints/rootConfig/createConfigSecretEnumerator.cjs.js.map +1 -0
  99. package/dist/entrypoints/rootConfig/rootConfigServiceFactory.cjs.js +26 -0
  100. package/dist/entrypoints/rootConfig/rootConfigServiceFactory.cjs.js.map +1 -0
  101. package/dist/entrypoints/rootHealth/rootHealthServiceFactory.cjs.js +41 -0
  102. package/dist/entrypoints/rootHealth/rootHealthServiceFactory.cjs.js.map +1 -0
  103. package/dist/entrypoints/rootHttpRouter/DefaultRootHttpRouter.cjs.js +77 -0
  104. package/dist/entrypoints/rootHttpRouter/DefaultRootHttpRouter.cjs.js.map +1 -0
  105. package/dist/entrypoints/rootHttpRouter/createHealthRouter.cjs.js +29 -0
  106. package/dist/entrypoints/rootHttpRouter/createHealthRouter.cjs.js.map +1 -0
  107. package/dist/entrypoints/rootHttpRouter/http/MiddlewareFactory.cjs.js +187 -0
  108. package/dist/entrypoints/rootHttpRouter/http/MiddlewareFactory.cjs.js.map +1 -0
  109. package/dist/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.cjs.js +28 -0
  110. package/dist/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.cjs.js.map +1 -0
  111. package/dist/{cjs/config-BDOwXIyo.cjs.js → entrypoints/rootHttpRouter/http/config.cjs.js} +1 -1
  112. package/dist/entrypoints/rootHttpRouter/http/config.cjs.js.map +1 -0
  113. package/dist/entrypoints/rootHttpRouter/http/createHttpServer.cjs.js +88 -0
  114. package/dist/entrypoints/rootHttpRouter/http/createHttpServer.cjs.js.map +1 -0
  115. package/dist/entrypoints/rootHttpRouter/http/getGeneratedCertificate.cjs.js +130 -0
  116. package/dist/entrypoints/rootHttpRouter/http/getGeneratedCertificate.cjs.js.map +1 -0
  117. package/dist/entrypoints/rootHttpRouter/http/readCorsOptions.cjs.js +51 -0
  118. package/dist/entrypoints/rootHttpRouter/http/readCorsOptions.cjs.js.map +1 -0
  119. package/dist/entrypoints/rootHttpRouter/http/readHelmetOptions.cjs.js +62 -0
  120. package/dist/entrypoints/rootHttpRouter/http/readHelmetOptions.cjs.js.map +1 -0
  121. package/dist/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.cjs.js +76 -0
  122. package/dist/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.cjs.js.map +1 -0
  123. package/dist/entrypoints/rootLifecycle/rootLifecycleServiceFactory.cjs.js +76 -0
  124. package/dist/entrypoints/rootLifecycle/rootLifecycleServiceFactory.cjs.js.map +1 -0
  125. package/dist/entrypoints/rootLogger/WinstonLogger.cjs.js +114 -0
  126. package/dist/entrypoints/rootLogger/WinstonLogger.cjs.js.map +1 -0
  127. package/dist/entrypoints/rootLogger/rootLoggerServiceFactory.cjs.js +30 -0
  128. package/dist/entrypoints/rootLogger/rootLoggerServiceFactory.cjs.js.map +1 -0
  129. package/dist/entrypoints/scheduler/database/migrateBackendTasks.cjs.js +18 -0
  130. package/dist/entrypoints/scheduler/database/migrateBackendTasks.cjs.js.map +1 -0
  131. package/dist/entrypoints/scheduler/database/tables.cjs.js +8 -0
  132. package/dist/entrypoints/scheduler/database/tables.cjs.js.map +1 -0
  133. package/dist/entrypoints/scheduler/lib/DefaultSchedulerService.cjs.js +37 -0
  134. package/dist/entrypoints/scheduler/lib/DefaultSchedulerService.cjs.js.map +1 -0
  135. package/dist/entrypoints/scheduler/lib/LocalTaskWorker.cjs.js +105 -0
  136. package/dist/entrypoints/scheduler/lib/LocalTaskWorker.cjs.js.map +1 -0
  137. package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.cjs.js +138 -0
  138. package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.cjs.js.map +1 -0
  139. package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.cjs.js +59 -0
  140. package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.cjs.js.map +1 -0
  141. package/dist/entrypoints/scheduler/lib/TaskWorker.cjs.js +275 -0
  142. package/dist/entrypoints/scheduler/lib/TaskWorker.cjs.js.map +1 -0
  143. package/dist/entrypoints/scheduler/lib/types.cjs.js +60 -0
  144. package/dist/entrypoints/scheduler/lib/types.cjs.js.map +1 -0
  145. package/dist/entrypoints/scheduler/lib/util.cjs.js +66 -0
  146. package/dist/entrypoints/scheduler/lib/util.cjs.js.map +1 -0
  147. package/dist/entrypoints/scheduler/schedulerServiceFactory.cjs.js +19 -0
  148. package/dist/entrypoints/scheduler/schedulerServiceFactory.cjs.js.map +1 -0
  149. package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js +274 -0
  150. package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js.map +1 -0
  151. package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js +261 -0
  152. package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js.map +1 -0
  153. package/dist/entrypoints/urlReader/lib/AzureUrlReader.cjs.js +148 -0
  154. package/dist/entrypoints/urlReader/lib/AzureUrlReader.cjs.js.map +1 -0
  155. package/dist/entrypoints/urlReader/lib/BitbucketCloudUrlReader.cjs.js +174 -0
  156. package/dist/entrypoints/urlReader/lib/BitbucketCloudUrlReader.cjs.js.map +1 -0
  157. package/dist/entrypoints/urlReader/lib/BitbucketServerUrlReader.cjs.js +170 -0
  158. package/dist/entrypoints/urlReader/lib/BitbucketServerUrlReader.cjs.js.map +1 -0
  159. package/dist/entrypoints/urlReader/lib/BitbucketUrlReader.cjs.js +182 -0
  160. package/dist/entrypoints/urlReader/lib/BitbucketUrlReader.cjs.js.map +1 -0
  161. package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js +132 -0
  162. package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js.map +1 -0
  163. package/dist/entrypoints/urlReader/lib/GerritUrlReader.cjs.js +147 -0
  164. package/dist/entrypoints/urlReader/lib/GerritUrlReader.cjs.js.map +1 -0
  165. package/dist/entrypoints/urlReader/lib/GiteaUrlReader.cjs.js +122 -0
  166. package/dist/entrypoints/urlReader/lib/GiteaUrlReader.cjs.js.map +1 -0
  167. package/dist/entrypoints/urlReader/lib/GithubUrlReader.cjs.js +226 -0
  168. package/dist/entrypoints/urlReader/lib/GithubUrlReader.cjs.js.map +1 -0
  169. package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js +276 -0
  170. package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js.map +1 -0
  171. package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js +129 -0
  172. package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js.map +1 -0
  173. package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js +120 -0
  174. package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js.map +1 -0
  175. package/dist/entrypoints/urlReader/lib/ReadUrlResponseFactory.cjs.js +49 -0
  176. package/dist/entrypoints/urlReader/lib/ReadUrlResponseFactory.cjs.js.map +1 -0
  177. package/dist/entrypoints/urlReader/lib/UrlReaderPredicateMux.cjs.js +46 -0
  178. package/dist/entrypoints/urlReader/lib/UrlReaderPredicateMux.cjs.js.map +1 -0
  179. package/dist/entrypoints/urlReader/lib/UrlReaders.cjs.js +68 -0
  180. package/dist/entrypoints/urlReader/lib/UrlReaders.cjs.js.map +1 -0
  181. package/dist/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.cjs.js +46 -0
  182. package/dist/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.cjs.js.map +1 -0
  183. package/dist/entrypoints/urlReader/lib/tree/ReadableArrayResponse.cjs.js +78 -0
  184. package/dist/entrypoints/urlReader/lib/tree/ReadableArrayResponse.cjs.js.map +1 -0
  185. package/dist/entrypoints/urlReader/lib/tree/TarArchiveResponse.cjs.js +147 -0
  186. package/dist/entrypoints/urlReader/lib/tree/TarArchiveResponse.cjs.js.map +1 -0
  187. package/dist/entrypoints/urlReader/lib/tree/ZipArchiveResponse.cjs.js +161 -0
  188. package/dist/entrypoints/urlReader/lib/tree/ZipArchiveResponse.cjs.js.map +1 -0
  189. package/dist/entrypoints/urlReader/lib/tree/util.cjs.js +28 -0
  190. package/dist/entrypoints/urlReader/lib/tree/util.cjs.js.map +1 -0
  191. package/dist/entrypoints/urlReader/lib/util.cjs.js +11 -0
  192. package/dist/entrypoints/urlReader/lib/util.cjs.js.map +1 -0
  193. package/dist/entrypoints/urlReader/urlReaderServiceFactory.cjs.js +29 -0
  194. package/dist/entrypoints/urlReader/urlReaderServiceFactory.cjs.js.map +1 -0
  195. package/dist/entrypoints/userInfo/DefaultUserInfoService.cjs.js +59 -0
  196. package/dist/entrypoints/userInfo/DefaultUserInfoService.cjs.js.map +1 -0
  197. package/dist/entrypoints/userInfo/userInfoServiceFactory.cjs.js +17 -0
  198. package/dist/entrypoints/userInfo/userInfoServiceFactory.cjs.js.map +1 -0
  199. package/dist/httpAuth.cjs.js +3 -187
  200. package/dist/httpAuth.cjs.js.map +1 -1
  201. package/dist/httpRouter.cjs.js +2 -166
  202. package/dist/httpRouter.cjs.js.map +1 -1
  203. package/dist/index.cjs.js +4 -160
  204. package/dist/index.cjs.js.map +1 -1
  205. package/dist/lib/escapeRegExp.cjs.js +8 -0
  206. package/dist/lib/escapeRegExp.cjs.js.map +1 -0
  207. package/dist/lifecycle.cjs.js +3 -58
  208. package/dist/lifecycle.cjs.js.map +1 -1
  209. package/dist/logger.cjs.js +3 -12
  210. package/dist/logger.cjs.js.map +1 -1
  211. package/dist/package.json.cjs.js +252 -0
  212. package/dist/package.json.cjs.js.map +1 -0
  213. package/dist/permissions.cjs.js +3 -17
  214. package/dist/permissions.cjs.js.map +1 -1
  215. package/dist/rootConfig.cjs.js +4 -22
  216. package/dist/rootConfig.cjs.js.map +1 -1
  217. package/dist/rootHealth.cjs.js +3 -35
  218. package/dist/rootHealth.cjs.js.map +1 -1
  219. package/dist/rootHttpRouter.cjs.js +15 -651
  220. package/dist/rootHttpRouter.cjs.js.map +1 -1
  221. package/dist/rootLifecycle.cjs.js +3 -70
  222. package/dist/rootLifecycle.cjs.js.map +1 -1
  223. package/dist/rootLogger.cjs.js +4 -137
  224. package/dist/rootLogger.cjs.js.map +1 -1
  225. package/dist/scheduler.cjs.js +4 -693
  226. package/dist/scheduler.cjs.js.map +1 -1
  227. package/dist/scheduler.d.ts +2 -1
  228. package/dist/urlReader.cjs.js +32 -2962
  229. package/dist/urlReader.cjs.js.map +1 -1
  230. package/dist/urlReader.d.ts +1 -2
  231. package/dist/userInfo.cjs.js +2 -64
  232. package/dist/userInfo.cjs.js.map +1 -1
  233. package/httpAuth/package.json +1 -1
  234. package/httpRouter/package.json +1 -1
  235. package/lifecycle/package.json +1 -1
  236. package/logger/package.json +1 -1
  237. package/package.json +20 -20
  238. package/permissions/package.json +1 -1
  239. package/rootConfig/package.json +1 -1
  240. package/rootHealth/package.json +1 -1
  241. package/rootHttpRouter/package.json +1 -1
  242. package/rootLifecycle/package.json +1 -1
  243. package/rootLogger/package.json +1 -1
  244. package/scheduler/package.json +1 -1
  245. package/urlReader/package.json +1 -1
  246. package/userInfo/package.json +1 -1
  247. package/dist/cjs/config-BDOwXIyo.cjs.js.map +0 -1
  248. package/dist/cjs/createConfigSecretEnumerator-DShyoWWL.cjs.js.map +0 -1
  249. 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 backendPluginApi = require('@backstage/backend-plugin-api');
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
- class LegacyTokenHandler {
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