@backstage/backend-defaults 0.9.0-next.1 → 0.9.0
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 +61 -0
- package/config.d.ts +88 -5
- package/dist/discovery.d.ts +105 -36
- package/dist/entrypoints/auditor/auditorServiceFactory.cjs.js +33 -7
- package/dist/entrypoints/auditor/auditorServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/auth/DefaultAuthService.cjs.js +2 -1
- package/dist/entrypoints/auth/DefaultAuthService.cjs.js.map +1 -1
- package/dist/entrypoints/auth/helpers.cjs.js +5 -2
- package/dist/entrypoints/auth/helpers.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/HostDiscovery.cjs.js +128 -53
- package/dist/entrypoints/discovery/HostDiscovery.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/SrvResolvers.cjs.js +148 -0
- package/dist/entrypoints/discovery/SrvResolvers.cjs.js.map +1 -0
- package/dist/entrypoints/discovery/discoveryServiceFactory.cjs.js +7 -3
- package/dist/entrypoints/discovery/discoveryServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.cjs.js +23 -1
- package/dist/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.cjs.js +4 -0
- package/dist/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/BitbucketServerUrlReader.cjs.js +3 -14
- package/dist/entrypoints/urlReader/lib/BitbucketServerUrlReader.cjs.js.map +1 -1
- package/dist/package.json.cjs.js +1 -2
- package/dist/package.json.cjs.js.map +1 -1
- package/package.json +20 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# @backstage/backend-defaults
|
|
2
2
|
|
|
3
|
+
## 0.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 1daedce: Remove Throttle of Bitbucket Server API calls
|
|
8
|
+
- 01edf6e: Allow pass through of redis client and cluster options to Cache core service
|
|
9
|
+
- cf4eb13: Added `actor` property to `BackstageUserPrincipal` containing the subject of the last service (if any) who performed authentication on behalf of the user.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 7c6740e: Implemented SRV lookup support in the default `HostDiscovery`. You can now specify internal URLs on the form `http+srv://some-srv-name/api/{{pluginId}}` and they will be resolved in real time.
|
|
14
|
+
- 939116c: Added an optional `backend.trustProxy` app config value, which sets the
|
|
15
|
+
corresponding [Express.js `trust proxy`](https://expressjs.com/en/guide/behind-proxies.html) setting. This lets
|
|
16
|
+
you easily configure proxy trust without making a custom `configure` callback
|
|
17
|
+
for the `rootHttpRouter` service.
|
|
18
|
+
|
|
19
|
+
If you already are using a custom `configure` callback, and if that also _does not_ call `applyDefaults()`, you may want to add the following to it:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
const trustProxy = config.getOptional('backend.trustProxy');
|
|
23
|
+
if (trustProxy !== undefined) {
|
|
24
|
+
app.set('trust proxy', trustProxy);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- 175528c: Adds `backend.auditor.severityLogLevelMappings` to map severity levels to log levels.
|
|
29
|
+
- Updated dependencies
|
|
30
|
+
- @backstage/backend-plugin-api@1.3.0
|
|
31
|
+
- @backstage/integration@1.16.3
|
|
32
|
+
- @backstage/backend-app-api@1.2.2
|
|
33
|
+
- @backstage/plugin-auth-node@0.6.2
|
|
34
|
+
- @backstage/plugin-permission-node@0.9.1
|
|
35
|
+
- @backstage/backend-dev-utils@0.1.5
|
|
36
|
+
- @backstage/cli-node@0.2.13
|
|
37
|
+
- @backstage/config@1.3.2
|
|
38
|
+
- @backstage/config-loader@1.10.0
|
|
39
|
+
- @backstage/errors@1.2.7
|
|
40
|
+
- @backstage/integration-aws-node@0.1.15
|
|
41
|
+
- @backstage/types@1.2.1
|
|
42
|
+
- @backstage/plugin-events-node@0.4.10
|
|
43
|
+
|
|
44
|
+
## 0.9.0-next.2
|
|
45
|
+
|
|
46
|
+
### Patch Changes
|
|
47
|
+
|
|
48
|
+
- 175528c: Adds `backend.auditor.severityLogLevelMappings` to map severity levels to log levels.
|
|
49
|
+
- Updated dependencies
|
|
50
|
+
- @backstage/backend-app-api@1.2.1
|
|
51
|
+
- @backstage/backend-dev-utils@0.1.5
|
|
52
|
+
- @backstage/backend-plugin-api@1.2.1
|
|
53
|
+
- @backstage/cli-node@0.2.13
|
|
54
|
+
- @backstage/config@1.3.2
|
|
55
|
+
- @backstage/config-loader@1.10.0
|
|
56
|
+
- @backstage/errors@1.2.7
|
|
57
|
+
- @backstage/integration@1.16.3-next.0
|
|
58
|
+
- @backstage/integration-aws-node@0.1.15
|
|
59
|
+
- @backstage/types@1.2.1
|
|
60
|
+
- @backstage/plugin-auth-node@0.6.1
|
|
61
|
+
- @backstage/plugin-events-node@0.4.9
|
|
62
|
+
- @backstage/plugin-permission-node@0.9.0
|
|
63
|
+
|
|
3
64
|
## 0.9.0-next.1
|
|
4
65
|
|
|
5
66
|
### Patch Changes
|
package/config.d.ts
CHANGED
|
@@ -51,6 +51,19 @@ export interface Config {
|
|
|
51
51
|
serverShutdownDelay?: string | HumanDuration;
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Corresponds to the Express `trust proxy` setting.
|
|
56
|
+
*
|
|
57
|
+
* @see https://expressjs.com/en/guide/behind-proxies.html
|
|
58
|
+
* @remarks
|
|
59
|
+
*
|
|
60
|
+
* This setting is used to determine whether the backend should trust the
|
|
61
|
+
* `X-Forwarded-*` headers that are set by proxies. This is important for
|
|
62
|
+
* determining the original client IP address and protocol (HTTP/HTTPS) when
|
|
63
|
+
* the backend is behind a reverse proxy or load balancer.
|
|
64
|
+
*/
|
|
65
|
+
trustProxy?: boolean | number | string | string[];
|
|
66
|
+
|
|
54
67
|
/** Address that the backend should listen to. */
|
|
55
68
|
listen?:
|
|
56
69
|
| string
|
|
@@ -82,6 +95,32 @@ export interface Config {
|
|
|
82
95
|
};
|
|
83
96
|
};
|
|
84
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Options used by the default auditor service.
|
|
100
|
+
*/
|
|
101
|
+
auditor?: {
|
|
102
|
+
/**
|
|
103
|
+
* Defines how audit event severity levels are mapped to log levels.
|
|
104
|
+
* This allows you to control the verbosity of audit logs based on the
|
|
105
|
+
* severity of the event. For example, you might want to log 'low' severity
|
|
106
|
+
* events as 'debug' messages, while logging 'critical' events as 'error'
|
|
107
|
+
* messages. Each severity level ('low', 'medium', 'high', 'critical')
|
|
108
|
+
* can be mapped to one of the standard log levels ('debug', 'info', 'warn', 'error').
|
|
109
|
+
*
|
|
110
|
+
* By default, audit events are mapped to log levels as follows:
|
|
111
|
+
* - `low`: `debug`
|
|
112
|
+
* - `medium`: `info`
|
|
113
|
+
* - `high`: `info`
|
|
114
|
+
* - `critical`: `info`
|
|
115
|
+
*/
|
|
116
|
+
severityLogLevelMappings?: {
|
|
117
|
+
low?: 'debug' | 'info' | 'warn' | 'error';
|
|
118
|
+
medium?: 'debug' | 'info' | 'warn' | 'error';
|
|
119
|
+
high?: 'debug' | 'info' | 'warn' | 'error';
|
|
120
|
+
critical?: 'debug' | 'info' | 'warn' | 'error';
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
|
|
85
124
|
/**
|
|
86
125
|
* Options used by the default auth, httpAuth and userInfo services.
|
|
87
126
|
*/
|
|
@@ -704,18 +743,62 @@ export interface Config {
|
|
|
704
743
|
*/
|
|
705
744
|
discovery?: {
|
|
706
745
|
/**
|
|
707
|
-
* A list of target
|
|
746
|
+
* A list of target base URLs and their associated plugins.
|
|
747
|
+
*
|
|
748
|
+
* @example
|
|
749
|
+
*
|
|
750
|
+
* ```yaml
|
|
751
|
+
* discovery:
|
|
752
|
+
* endpoints:
|
|
753
|
+
* - target: https://internal.example.com/internal-catalog
|
|
754
|
+
* plugins: [catalog]
|
|
755
|
+
* - target: https://internal.example.com/secure/api/{{pluginId}}
|
|
756
|
+
* plugins: [auth, permission]
|
|
757
|
+
* - target:
|
|
758
|
+
* internal: http+srv://backstage-plugin-{{pluginId}}.http.${SERVICE_DOMAIN}/search
|
|
759
|
+
* external: https://example.com/search
|
|
760
|
+
* plugins: [search]
|
|
761
|
+
* ```
|
|
708
762
|
*/
|
|
709
763
|
endpoints: Array<{
|
|
710
764
|
/**
|
|
711
|
-
* The target base URL to use for the
|
|
765
|
+
* The target base URL to use for the given set of plugins. Note that this
|
|
766
|
+
* needs to be a full URL including the protocol and path parts that fully
|
|
767
|
+
* address the root of a plugin's API endpoints.
|
|
768
|
+
*
|
|
769
|
+
* @remarks
|
|
770
|
+
*
|
|
771
|
+
* Can be either a single URL or an object where you can explicitly give a
|
|
772
|
+
* dedicated URL for internal (as seen from the backend) and/or external (as
|
|
773
|
+
* seen from the frontend) lookups.
|
|
712
774
|
*
|
|
713
|
-
*
|
|
714
|
-
*
|
|
775
|
+
* The default behavior is to use the backend base URL for external lookups,
|
|
776
|
+
* and a URL formed from the `.listen` and `.https` configs for internal
|
|
777
|
+
* lookups. Adding discovery endpoints as described here overrides one or both
|
|
778
|
+
* of those behaviors for a given set of plugins.
|
|
779
|
+
*
|
|
780
|
+
* URLs can be in the form of a regular HTTP or HTTPS URL if you are using
|
|
781
|
+
* A/AAAA/CNAME records or IP addresses. Specifically for internal URLs, if
|
|
782
|
+
* you add `+src` to the protocol part then the hostname is treated as an SRV
|
|
783
|
+
* record name and resolved. For example, if you pass in
|
|
784
|
+
* `http+srv://<srv-record>/path` then the record part is resolved into an
|
|
785
|
+
* actual host and port (with random weighted choice as usual when there is
|
|
786
|
+
* more than one match).
|
|
787
|
+
*
|
|
788
|
+
* Any strings with `{{pluginId}}` or `{{ pluginId }}` placeholders in them
|
|
789
|
+
* will have them replaced with the plugin ID.
|
|
790
|
+
*
|
|
791
|
+
* Example URLs:
|
|
792
|
+
*
|
|
793
|
+
* - `https://internal.example.com/secure/api/{{pluginId}}`
|
|
794
|
+
* - `http+srv://backstage-plugin-{{pluginId}}.http.${SERVICE_DOMAIN}/api/{{pluginId}}`
|
|
795
|
+
* (can only be used in the `internal` key)
|
|
715
796
|
*/
|
|
716
797
|
target: string | { internal?: string; external?: string };
|
|
717
798
|
/**
|
|
718
|
-
* Array of plugins which use
|
|
799
|
+
* Array of plugins which use that target base URL.
|
|
800
|
+
*
|
|
801
|
+
* The special value `*` can be used to match all plugins.
|
|
719
802
|
*/
|
|
720
803
|
plugins: string[];
|
|
721
804
|
}>;
|
package/dist/discovery.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
|
-
import { DiscoveryService, RootConfigService } from '@backstage/backend-plugin-api';
|
|
2
|
+
import { LoggerService, DiscoveryService, RootConfigService } from '@backstage/backend-plugin-api';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Service discovery for inter-plugin communication.
|
|
@@ -13,49 +13,118 @@ import { DiscoveryService, RootConfigService } from '@backstage/backend-plugin-a
|
|
|
13
13
|
declare const discoveryServiceFactory: _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api.DiscoveryService, "plugin", "singleton">;
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
* that can handle plugins that are hosted in a single or multiple deployments.
|
|
16
|
+
* A list of target base URLs and their associated plugins.
|
|
18
17
|
*
|
|
19
|
-
*
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
interface HostDiscoveryEndpoint {
|
|
21
|
+
/**
|
|
22
|
+
* The target base URL to use for the given set of plugins. Note that this
|
|
23
|
+
* needs to be a full URL _including_ the protocol and path parts that fully
|
|
24
|
+
* address the root of a plugin's API endpoints.
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
*
|
|
28
|
+
* Can be either a single URL or an object where you can explicitly give a
|
|
29
|
+
* dedicated URL for internal (as seen from the backend) and/or external (as
|
|
30
|
+
* seen from the frontend) lookups.
|
|
31
|
+
*
|
|
32
|
+
* The default behavior is to use the backend base URL for external lookups,
|
|
33
|
+
* and a URL formed from the `.listen` and `.https` configs for internal
|
|
34
|
+
* lookups. Adding discovery endpoints as described here overrides one or both
|
|
35
|
+
* of those behaviors for a given set of plugins.
|
|
36
|
+
*
|
|
37
|
+
* URLs can be in the form of a regular HTTP or HTTPS URL if you are using
|
|
38
|
+
* A/AAAA/CNAME records or IP addresses. Specifically for internal URLs, if
|
|
39
|
+
* you add `+src` to the protocol part then the hostname is treated as an SRV
|
|
40
|
+
* record name and resolved. For example, if you pass in
|
|
41
|
+
* `http+srv://<record>/path` then the record part is resolved into an
|
|
42
|
+
* actual host and port (with random weighted choice as usual when there is
|
|
43
|
+
* more than one match).
|
|
44
|
+
*
|
|
45
|
+
* Any strings with `{{pluginId}}` or `{{ pluginId }}` placeholders in them
|
|
46
|
+
* will have them replaced with the plugin ID.
|
|
47
|
+
*
|
|
48
|
+
* Example URLs:
|
|
49
|
+
*
|
|
50
|
+
* - `https://internal.example.com/secure/api/{{ pluginId }}`
|
|
51
|
+
* - `http+srv://backstage-plugin-{{pluginId}}.http.services.company.net/api/{{pluginId}}`
|
|
52
|
+
* (can only be used in the `internal` key)
|
|
53
|
+
*/
|
|
54
|
+
target: string | {
|
|
55
|
+
internal?: string;
|
|
56
|
+
external?: string;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Array of plugins which use that target base URL.
|
|
60
|
+
*
|
|
61
|
+
* The special value `*` can be used to match all plugins.
|
|
62
|
+
*/
|
|
63
|
+
plugins: string[];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Options for the {@link HostDiscovery} class.
|
|
22
67
|
*
|
|
23
68
|
* @public
|
|
24
69
|
*/
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
70
|
+
interface HostDiscoveryOptions {
|
|
71
|
+
/**
|
|
72
|
+
* The logger to use.
|
|
73
|
+
*/
|
|
74
|
+
logger: LoggerService;
|
|
29
75
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* - target: https://internal.example.com/internal-catalog
|
|
42
|
-
* plugins: [catalog]
|
|
43
|
-
* - target: https://internal.example.com/secure/api/{{pluginId}}
|
|
44
|
-
* plugins: [auth, permission]
|
|
45
|
-
* - target:
|
|
46
|
-
* internal: https://internal.example.com/search
|
|
47
|
-
* external: https://example.com/search
|
|
48
|
-
* plugins: [search]
|
|
49
|
-
* ```
|
|
50
|
-
*
|
|
51
|
-
* The fixed base path is `/api`, meaning the default full internal
|
|
52
|
-
* path for the `catalog` plugin will be `http://localhost:7007/api/catalog`.
|
|
76
|
+
* A default set of endpoints to use.
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
*
|
|
80
|
+
* These endpoints have lower priority than any that are defined in
|
|
81
|
+
* app-config, but higher priority than the fallback ones.
|
|
82
|
+
*
|
|
83
|
+
* This parameter is usedful for example if you want to provide a shared
|
|
84
|
+
* library of core services to your plugin developers, which is set up for the
|
|
85
|
+
* default behaviors in your org. This alleviates the need for replicating any
|
|
86
|
+
* given set of endpoint config in every backend that you deploy.
|
|
53
87
|
*/
|
|
54
|
-
|
|
88
|
+
defaultEndpoints?: HostDiscoveryEndpoint[];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* A basic {@link @backstage/backend-plugin-api#DiscoveryService} implementation
|
|
92
|
+
* that can handle plugins that are hosted in a single or multiple deployments.
|
|
93
|
+
*
|
|
94
|
+
* @public
|
|
95
|
+
* @remarks
|
|
96
|
+
*
|
|
97
|
+
* Configuration is read from the `backend` config section, specifically the
|
|
98
|
+
* `.baseUrl` for discovering the external URL, and the `.listen` and `.https`
|
|
99
|
+
* config for the internal one. The fixed base path for these is `/api`, meaning
|
|
100
|
+
* for example the default full internal path for the `catalog` plugin typically
|
|
101
|
+
* will be `http://localhost:7007/api/catalog`.
|
|
102
|
+
*
|
|
103
|
+
* Those defaults can be overridden by providing a target and corresponding
|
|
104
|
+
* plugins in `discovery.endpoints`, e.g.:
|
|
105
|
+
*
|
|
106
|
+
* ```yaml
|
|
107
|
+
* discovery:
|
|
108
|
+
* endpoints:
|
|
109
|
+
* # Set a static internal and external base URL for a plugin
|
|
110
|
+
* - target: https://internal.example.com/internal-catalog
|
|
111
|
+
* plugins: [catalog]
|
|
112
|
+
* # Sets a dynamic internal and external base URL pattern for two plugins
|
|
113
|
+
* - target: https://internal.example.com/secure/api/{{pluginId}}
|
|
114
|
+
* plugins: [auth, permission]
|
|
115
|
+
* # Sets a dynamic base URL pattern for only the internal resolution for all
|
|
116
|
+
* # other plugins, while leaving the external resolution unaffected
|
|
117
|
+
* - target:
|
|
118
|
+
* internal: http+srv://backstage-plugin-{{pluginId}}.http.${SERVICE_DOMAIN}/api/{{pluginId}}
|
|
119
|
+
* plugins: [*]
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
declare class HostDiscovery implements DiscoveryService {
|
|
123
|
+
#private;
|
|
124
|
+
static fromConfig(config: RootConfigService, options?: HostDiscoveryOptions): HostDiscovery;
|
|
55
125
|
private constructor();
|
|
56
|
-
private getTargetFromConfig;
|
|
57
126
|
getBaseUrl(pluginId: string): Promise<string>;
|
|
58
127
|
getExternalBaseUrl(pluginId: string): Promise<string>;
|
|
59
128
|
}
|
|
60
129
|
|
|
61
|
-
export { HostDiscovery, discoveryServiceFactory };
|
|
130
|
+
export { HostDiscovery, type HostDiscoveryEndpoint, type HostDiscoveryOptions, discoveryServiceFactory };
|
|
@@ -2,25 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
4
|
var DefaultAuditorService = require('./DefaultAuditorService.cjs.js');
|
|
5
|
+
var zod = require('zod');
|
|
6
|
+
var errors = require('@backstage/errors');
|
|
5
7
|
|
|
8
|
+
const CONFIG_ROOT_KEY = "backend.auditor";
|
|
9
|
+
const severityLogLevelMappingsSchema = zod.z.record(
|
|
10
|
+
zod.z.enum(["low", "medium", "high", "critical"]),
|
|
11
|
+
zod.z.enum(["debug", "info", "warn", "error"])
|
|
12
|
+
);
|
|
6
13
|
const auditorServiceFactory = backendPluginApi.createServiceFactory({
|
|
7
14
|
service: backendPluginApi.coreServices.auditor,
|
|
8
15
|
deps: {
|
|
16
|
+
config: backendPluginApi.coreServices.rootConfig,
|
|
9
17
|
logger: backendPluginApi.coreServices.logger,
|
|
10
18
|
auth: backendPluginApi.coreServices.auth,
|
|
11
19
|
httpAuth: backendPluginApi.coreServices.httpAuth,
|
|
12
20
|
plugin: backendPluginApi.coreServices.pluginMetadata
|
|
13
21
|
},
|
|
14
|
-
factory({ logger, plugin, auth, httpAuth }) {
|
|
22
|
+
factory({ config, logger, plugin, auth, httpAuth }) {
|
|
15
23
|
const auditLogger = logger.child({ isAuditEvent: true });
|
|
24
|
+
const auditorConfig = config.getOptionalConfig(CONFIG_ROOT_KEY);
|
|
25
|
+
const severityLogLevelMappings = {
|
|
26
|
+
low: auditorConfig?.getOptionalString("severityLogLevelMappings.low") ?? "debug",
|
|
27
|
+
medium: auditorConfig?.getOptionalString("severityLogLevelMappings.medium") ?? "info",
|
|
28
|
+
high: auditorConfig?.getOptionalString("severityLogLevelMappings.high") ?? "info",
|
|
29
|
+
critical: auditorConfig?.getOptionalString("severityLogLevelMappings.critical") ?? "info"
|
|
30
|
+
};
|
|
31
|
+
const res = severityLogLevelMappingsSchema.safeParse(
|
|
32
|
+
severityLogLevelMappings
|
|
33
|
+
);
|
|
34
|
+
if (!res.success) {
|
|
35
|
+
const key = res.error.issues.at(0)?.path.at(0);
|
|
36
|
+
const value = res.error.issues.at(0).received;
|
|
37
|
+
const validKeys = res.error.issues.at(0).options;
|
|
38
|
+
throw new errors.InputError(
|
|
39
|
+
`The configuration value for 'backend.auditor.severityLogLevelMappings.${key}' was given an invalid value: '${value}'. Expected one of the following valid values: '${validKeys.join(
|
|
40
|
+
", "
|
|
41
|
+
)}'.`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
16
44
|
return DefaultAuditorService.DefaultAuditorService.create(
|
|
17
45
|
(event) => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
auditLogger.info(message, event);
|
|
23
|
-
}
|
|
46
|
+
auditLogger[severityLogLevelMappings[event.severityLevel]](
|
|
47
|
+
`${event.plugin}.${event.eventId}`,
|
|
48
|
+
event
|
|
49
|
+
);
|
|
24
50
|
},
|
|
25
51
|
{ plugin, auth, httpAuth }
|
|
26
52
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auditorServiceFactory.cjs.js","sources":["../../../src/entrypoints/auditor/auditorServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { DefaultAuditorService } from './DefaultAuditorService';\n\n/**\n * Plugin-level auditing.\n *\n * See {@link @backstage/code-plugin-api#AuditorService}\n * and {@link https://backstage.io/docs/backend-system/core-services/auditor | the service docs}\n * for more information.\n *\n * @public\n */\nexport const auditorServiceFactory = createServiceFactory({\n service: coreServices.auditor,\n deps: {\n logger: coreServices.logger,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n plugin: coreServices.pluginMetadata,\n },\n factory({ logger, plugin, auth, httpAuth }) {\n const auditLogger = logger.child({ isAuditEvent: true });\n
|
|
1
|
+
{"version":3,"file":"auditorServiceFactory.cjs.js","sources":["../../../src/entrypoints/auditor/auditorServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { DefaultAuditorService } from './DefaultAuditorService';\nimport { z } from 'zod';\nimport { InputError } from '@backstage/errors';\n\nconst CONFIG_ROOT_KEY = 'backend.auditor';\n\nconst severityLogLevelMappingsSchema = z.record(\n z.enum(['low', 'medium', 'high', 'critical']),\n z.enum(['debug', 'info', 'warn', 'error']),\n);\n\n/**\n * Plugin-level auditing.\n *\n * See {@link @backstage/code-plugin-api#AuditorService}\n * and {@link https://backstage.io/docs/backend-system/core-services/auditor | the service docs}\n * for more information.\n *\n * @public\n */\nexport const auditorServiceFactory = createServiceFactory({\n service: coreServices.auditor,\n deps: {\n config: coreServices.rootConfig,\n logger: coreServices.logger,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n plugin: coreServices.pluginMetadata,\n },\n factory({ config, logger, plugin, auth, httpAuth }) {\n const auditLogger = logger.child({ isAuditEvent: true });\n const auditorConfig = config.getOptionalConfig(CONFIG_ROOT_KEY);\n\n const severityLogLevelMappings = {\n low:\n auditorConfig?.getOptionalString('severityLogLevelMappings.low') ??\n 'debug',\n medium:\n auditorConfig?.getOptionalString('severityLogLevelMappings.medium') ??\n 'info',\n high:\n auditorConfig?.getOptionalString('severityLogLevelMappings.high') ??\n 'info',\n critical:\n auditorConfig?.getOptionalString('severityLogLevelMappings.critical') ??\n 'info',\n } as Required<z.infer<typeof severityLogLevelMappingsSchema>>;\n\n const res = severityLogLevelMappingsSchema.safeParse(\n severityLogLevelMappings,\n );\n if (!res.success) {\n const key = res.error.issues.at(0)?.path.at(0) as string;\n const value = (\n res.error.issues.at(0) as unknown as Record<PropertyKey, unknown>\n ).received as string;\n const validKeys = (\n res.error.issues.at(0) as unknown as Record<PropertyKey, unknown>\n ).options as string[];\n throw new InputError(\n `The configuration value for 'backend.auditor.severityLogLevelMappings.${key}' was given an invalid value: '${value}'. Expected one of the following valid values: '${validKeys.join(\n ', ',\n )}'.`,\n );\n }\n\n return DefaultAuditorService.create(\n event => {\n auditLogger[severityLogLevelMappings[event.severityLevel]](\n `${event.plugin}.${event.eventId}`,\n event,\n );\n },\n { plugin, auth, httpAuth },\n );\n },\n});\n"],"names":["z","createServiceFactory","coreServices","InputError","DefaultAuditorService"],"mappings":";;;;;;;AAwBA,MAAM,eAAkB,GAAA,iBAAA;AAExB,MAAM,iCAAiCA,KAAE,CAAA,MAAA;AAAA,EACvCA,MAAE,IAAK,CAAA,CAAC,OAAO,QAAU,EAAA,MAAA,EAAQ,UAAU,CAAC,CAAA;AAAA,EAC5CA,MAAE,IAAK,CAAA,CAAC,SAAS,MAAQ,EAAA,MAAA,EAAQ,OAAO,CAAC;AAC3C,CAAA;AAWO,MAAM,wBAAwBC,qCAAqB,CAAA;AAAA,EACxD,SAASC,6BAAa,CAAA,OAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACJ,QAAQA,6BAAa,CAAA,UAAA;AAAA,IACrB,QAAQA,6BAAa,CAAA,MAAA;AAAA,IACrB,MAAMA,6BAAa,CAAA,IAAA;AAAA,IACnB,UAAUA,6BAAa,CAAA,QAAA;AAAA,IACvB,QAAQA,6BAAa,CAAA;AAAA,GACvB;AAAA,EACA,QAAQ,EAAE,MAAA,EAAQ,QAAQ,MAAQ,EAAA,IAAA,EAAM,UAAY,EAAA;AAClD,IAAA,MAAM,cAAc,MAAO,CAAA,KAAA,CAAM,EAAE,YAAA,EAAc,MAAM,CAAA;AACvD,IAAM,MAAA,aAAA,GAAgB,MAAO,CAAA,iBAAA,CAAkB,eAAe,CAAA;AAE9D,IAAA,MAAM,wBAA2B,GAAA;AAAA,MAC/B,GACE,EAAA,aAAA,EAAe,iBAAkB,CAAA,8BAA8B,CAC/D,IAAA,OAAA;AAAA,MACF,MACE,EAAA,aAAA,EAAe,iBAAkB,CAAA,iCAAiC,CAClE,IAAA,MAAA;AAAA,MACF,IACE,EAAA,aAAA,EAAe,iBAAkB,CAAA,+BAA+B,CAChE,IAAA,MAAA;AAAA,MACF,QACE,EAAA,aAAA,EAAe,iBAAkB,CAAA,mCAAmC,CACpE,IAAA;AAAA,KACJ;AAEA,IAAA,MAAM,MAAM,8BAA+B,CAAA,SAAA;AAAA,MACzC;AAAA,KACF;AACA,IAAI,IAAA,CAAC,IAAI,OAAS,EAAA;AAChB,MAAM,MAAA,GAAA,GAAM,IAAI,KAAM,CAAA,MAAA,CAAO,GAAG,CAAC,CAAA,EAAG,IAAK,CAAA,EAAA,CAAG,CAAC,CAAA;AAC7C,MAAA,MAAM,QACJ,GAAI,CAAA,KAAA,CAAM,MAAO,CAAA,EAAA,CAAG,CAAC,CACrB,CAAA,QAAA;AACF,MAAA,MAAM,YACJ,GAAI,CAAA,KAAA,CAAM,MAAO,CAAA,EAAA,CAAG,CAAC,CACrB,CAAA,OAAA;AACF,MAAA,MAAM,IAAIC,iBAAA;AAAA,QACR,CAAyE,sEAAA,EAAA,GAAG,CAAkC,+BAAA,EAAA,KAAK,mDAAmD,SAAU,CAAA,IAAA;AAAA,UAC9K;AAAA,SACD,CAAA,EAAA;AAAA,OACH;AAAA;AAGF,IAAA,OAAOC,2CAAsB,CAAA,MAAA;AAAA,MAC3B,CAAS,KAAA,KAAA;AACP,QAAY,WAAA,CAAA,wBAAA,CAAyB,KAAM,CAAA,aAAa,CAAC,CAAA;AAAA,UACvD,CAAG,EAAA,KAAA,CAAM,MAAM,CAAA,CAAA,EAAI,MAAM,OAAO,CAAA,CAAA;AAAA,UAChC;AAAA,SACF;AAAA,OACF;AAAA,MACA,EAAE,MAAQ,EAAA,IAAA,EAAM,QAAS;AAAA,KAC3B;AAAA;AAEJ,CAAC;;;;"}
|
|
@@ -28,7 +28,8 @@ class DefaultAuthService {
|
|
|
28
28
|
return helpers.createCredentialsWithUserPrincipal(
|
|
29
29
|
userResult2.userEntityRef,
|
|
30
30
|
pluginResult.limitedUserToken,
|
|
31
|
-
this.#getJwtExpiration(pluginResult.limitedUserToken)
|
|
31
|
+
this.#getJwtExpiration(pluginResult.limitedUserToken),
|
|
32
|
+
pluginResult.subject
|
|
32
33
|
);
|
|
33
34
|
}
|
|
34
35
|
return helpers.createCredentialsWithServicePrincipal(pluginResult.subject);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultAuthService.cjs.js","sources":["../../../src/entrypoints/auth/DefaultAuthService.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AuthService,\n BackstageCredentials,\n BackstageNonePrincipal,\n BackstagePrincipalTypes,\n BackstageServicePrincipal,\n BackstageUserPrincipal,\n} from '@backstage/backend-plugin-api';\nimport { AuthenticationError } from '@backstage/errors';\nimport { JsonObject } from '@backstage/types';\nimport { decodeJwt } from 'jose';\nimport { ExternalTokenHandler } from './external/ExternalTokenHandler';\nimport {\n createCredentialsWithNonePrincipal,\n createCredentialsWithServicePrincipal,\n createCredentialsWithUserPrincipal,\n toInternalBackstageCredentials,\n} from './helpers';\nimport { PluginTokenHandler } from './plugin/PluginTokenHandler';\nimport { PluginKeySource } from './plugin/keys/types';\nimport { UserTokenHandler } from './user/UserTokenHandler';\n\n/** @internal */\nexport class DefaultAuthService implements AuthService {\n constructor(\n private readonly userTokenHandler: UserTokenHandler,\n private readonly pluginTokenHandler: PluginTokenHandler,\n private readonly externalTokenHandler: ExternalTokenHandler,\n private readonly pluginId: string,\n private readonly disableDefaultAuthPolicy: boolean,\n private readonly pluginKeySource: PluginKeySource,\n ) {}\n\n async authenticate(\n token: string,\n options?: {\n allowLimitedAccess?: boolean;\n },\n ): Promise<BackstageCredentials> {\n const pluginResult = await this.pluginTokenHandler.verifyToken(token);\n if (pluginResult) {\n if (pluginResult.limitedUserToken) {\n const userResult = await this.userTokenHandler.verifyToken(\n pluginResult.limitedUserToken,\n );\n if (!userResult) {\n throw new AuthenticationError(\n 'Invalid user token in plugin token obo claim',\n );\n }\n return createCredentialsWithUserPrincipal(\n userResult.userEntityRef,\n pluginResult.limitedUserToken,\n this.#getJwtExpiration(pluginResult.limitedUserToken),\n );\n }\n return createCredentialsWithServicePrincipal(pluginResult.subject);\n }\n\n const userResult = await this.userTokenHandler.verifyToken(token);\n if (userResult) {\n if (\n !options?.allowLimitedAccess &&\n this.userTokenHandler.isLimitedUserToken(token)\n ) {\n throw new AuthenticationError('Illegal limited user token');\n }\n\n return createCredentialsWithUserPrincipal(\n userResult.userEntityRef,\n token,\n this.#getJwtExpiration(token),\n );\n }\n\n const externalResult = await this.externalTokenHandler.verifyToken(token);\n if (externalResult) {\n return createCredentialsWithServicePrincipal(\n externalResult.subject,\n undefined,\n externalResult.accessRestrictions,\n );\n }\n\n throw new AuthenticationError('Illegal token');\n }\n\n isPrincipal<TType extends keyof BackstagePrincipalTypes>(\n credentials: BackstageCredentials,\n type: TType,\n ): credentials is BackstageCredentials<BackstagePrincipalTypes[TType]> {\n const principal = credentials.principal as\n | BackstageUserPrincipal\n | BackstageServicePrincipal;\n\n if (type === 'unknown') {\n return true;\n }\n\n if (principal.type !== type) {\n return false;\n }\n\n return true;\n }\n\n async getNoneCredentials(): Promise<\n BackstageCredentials<BackstageNonePrincipal>\n > {\n return createCredentialsWithNonePrincipal();\n }\n\n async getOwnServiceCredentials(): Promise<\n BackstageCredentials<BackstageServicePrincipal>\n > {\n return createCredentialsWithServicePrincipal(`plugin:${this.pluginId}`);\n }\n\n async getPluginRequestToken(options: {\n onBehalfOf: BackstageCredentials;\n targetPluginId: string;\n }): Promise<{ token: string }> {\n const { targetPluginId } = options;\n const internalForward = toInternalBackstageCredentials(options.onBehalfOf);\n const { type } = internalForward.principal;\n\n // Since disabling the default policy means we'll be allowing\n // unauthenticated requests through, we might have unauthenticated\n // credentials from service calls that reach this point. If that's the case,\n // we'll want to keep \"forwarding\" the unauthenticated credentials, which we\n // do by returning an empty token.\n if (type === 'none' && this.disableDefaultAuthPolicy) {\n return { token: '' };\n }\n\n // check whether a plugin support the new auth system\n // by checking the public keys endpoint existance.\n switch (type) {\n // TODO: Check whether the principal is ourselves\n case 'service':\n return this.pluginTokenHandler.issueToken({\n pluginId: this.pluginId,\n targetPluginId,\n });\n case 'user': {\n const { token } = internalForward;\n if (!token) {\n throw new Error('User credentials is unexpectedly missing token');\n }\n const onBehalfOf = await this.userTokenHandler.createLimitedUserToken(\n token,\n );\n return this.pluginTokenHandler.issueToken({\n pluginId: this.pluginId,\n targetPluginId,\n onBehalfOf: {\n limitedUserToken: onBehalfOf.token,\n expiresAt: onBehalfOf.expiresAt,\n },\n });\n }\n default:\n throw new AuthenticationError(\n `Refused to issue service token for credential type '${type}'`,\n );\n }\n }\n\n async getLimitedUserToken(\n credentials: BackstageCredentials<BackstageUserPrincipal>,\n ): Promise<{ token: string; expiresAt: Date }> {\n const { token: backstageToken } =\n toInternalBackstageCredentials(credentials);\n if (!backstageToken) {\n throw new AuthenticationError(\n 'User credentials is unexpectedly missing token',\n );\n }\n\n return this.userTokenHandler.createLimitedUserToken(backstageToken);\n }\n\n async listPublicServiceKeys(): Promise<{ keys: JsonObject[] }> {\n const { keys } = await this.pluginKeySource.listKeys();\n return { keys: keys.map(({ key }) => key) };\n }\n\n #getJwtExpiration(token: string) {\n const { exp } = decodeJwt(token);\n if (!exp) {\n throw new AuthenticationError('User token is missing expiration');\n }\n return new Date(exp * 1000);\n }\n}\n"],"names":["userResult","AuthenticationError","createCredentialsWithUserPrincipal","createCredentialsWithServicePrincipal","createCredentialsWithNonePrincipal","toInternalBackstageCredentials","decodeJwt"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DefaultAuthService.cjs.js","sources":["../../../src/entrypoints/auth/DefaultAuthService.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AuthService,\n BackstageCredentials,\n BackstageNonePrincipal,\n BackstagePrincipalTypes,\n BackstageServicePrincipal,\n BackstageUserPrincipal,\n} from '@backstage/backend-plugin-api';\nimport { AuthenticationError } from '@backstage/errors';\nimport { JsonObject } from '@backstage/types';\nimport { decodeJwt } from 'jose';\nimport { ExternalTokenHandler } from './external/ExternalTokenHandler';\nimport {\n createCredentialsWithNonePrincipal,\n createCredentialsWithServicePrincipal,\n createCredentialsWithUserPrincipal,\n toInternalBackstageCredentials,\n} from './helpers';\nimport { PluginTokenHandler } from './plugin/PluginTokenHandler';\nimport { PluginKeySource } from './plugin/keys/types';\nimport { UserTokenHandler } from './user/UserTokenHandler';\n\n/** @internal */\nexport class DefaultAuthService implements AuthService {\n constructor(\n private readonly userTokenHandler: UserTokenHandler,\n private readonly pluginTokenHandler: PluginTokenHandler,\n private readonly externalTokenHandler: ExternalTokenHandler,\n private readonly pluginId: string,\n private readonly disableDefaultAuthPolicy: boolean,\n private readonly pluginKeySource: PluginKeySource,\n ) {}\n\n async authenticate(\n token: string,\n options?: {\n allowLimitedAccess?: boolean;\n },\n ): Promise<BackstageCredentials> {\n const pluginResult = await this.pluginTokenHandler.verifyToken(token);\n if (pluginResult) {\n if (pluginResult.limitedUserToken) {\n const userResult = await this.userTokenHandler.verifyToken(\n pluginResult.limitedUserToken,\n );\n if (!userResult) {\n throw new AuthenticationError(\n 'Invalid user token in plugin token obo claim',\n );\n }\n return createCredentialsWithUserPrincipal(\n userResult.userEntityRef,\n pluginResult.limitedUserToken,\n this.#getJwtExpiration(pluginResult.limitedUserToken),\n pluginResult.subject,\n );\n }\n return createCredentialsWithServicePrincipal(pluginResult.subject);\n }\n\n const userResult = await this.userTokenHandler.verifyToken(token);\n if (userResult) {\n if (\n !options?.allowLimitedAccess &&\n this.userTokenHandler.isLimitedUserToken(token)\n ) {\n throw new AuthenticationError('Illegal limited user token');\n }\n\n return createCredentialsWithUserPrincipal(\n userResult.userEntityRef,\n token,\n this.#getJwtExpiration(token),\n );\n }\n\n const externalResult = await this.externalTokenHandler.verifyToken(token);\n if (externalResult) {\n return createCredentialsWithServicePrincipal(\n externalResult.subject,\n undefined,\n externalResult.accessRestrictions,\n );\n }\n\n throw new AuthenticationError('Illegal token');\n }\n\n isPrincipal<TType extends keyof BackstagePrincipalTypes>(\n credentials: BackstageCredentials,\n type: TType,\n ): credentials is BackstageCredentials<BackstagePrincipalTypes[TType]> {\n const principal = credentials.principal as\n | BackstageUserPrincipal\n | BackstageServicePrincipal;\n\n if (type === 'unknown') {\n return true;\n }\n\n if (principal.type !== type) {\n return false;\n }\n\n return true;\n }\n\n async getNoneCredentials(): Promise<\n BackstageCredentials<BackstageNonePrincipal>\n > {\n return createCredentialsWithNonePrincipal();\n }\n\n async getOwnServiceCredentials(): Promise<\n BackstageCredentials<BackstageServicePrincipal>\n > {\n return createCredentialsWithServicePrincipal(`plugin:${this.pluginId}`);\n }\n\n async getPluginRequestToken(options: {\n onBehalfOf: BackstageCredentials;\n targetPluginId: string;\n }): Promise<{ token: string }> {\n const { targetPluginId } = options;\n const internalForward = toInternalBackstageCredentials(options.onBehalfOf);\n const { type } = internalForward.principal;\n\n // Since disabling the default policy means we'll be allowing\n // unauthenticated requests through, we might have unauthenticated\n // credentials from service calls that reach this point. If that's the case,\n // we'll want to keep \"forwarding\" the unauthenticated credentials, which we\n // do by returning an empty token.\n if (type === 'none' && this.disableDefaultAuthPolicy) {\n return { token: '' };\n }\n\n // check whether a plugin support the new auth system\n // by checking the public keys endpoint existance.\n switch (type) {\n // TODO: Check whether the principal is ourselves\n case 'service':\n return this.pluginTokenHandler.issueToken({\n pluginId: this.pluginId,\n targetPluginId,\n });\n case 'user': {\n const { token } = internalForward;\n if (!token) {\n throw new Error('User credentials is unexpectedly missing token');\n }\n const onBehalfOf = await this.userTokenHandler.createLimitedUserToken(\n token,\n );\n return this.pluginTokenHandler.issueToken({\n pluginId: this.pluginId,\n targetPluginId,\n onBehalfOf: {\n limitedUserToken: onBehalfOf.token,\n expiresAt: onBehalfOf.expiresAt,\n },\n });\n }\n default:\n throw new AuthenticationError(\n `Refused to issue service token for credential type '${type}'`,\n );\n }\n }\n\n async getLimitedUserToken(\n credentials: BackstageCredentials<BackstageUserPrincipal>,\n ): Promise<{ token: string; expiresAt: Date }> {\n const { token: backstageToken } =\n toInternalBackstageCredentials(credentials);\n if (!backstageToken) {\n throw new AuthenticationError(\n 'User credentials is unexpectedly missing token',\n );\n }\n\n return this.userTokenHandler.createLimitedUserToken(backstageToken);\n }\n\n async listPublicServiceKeys(): Promise<{ keys: JsonObject[] }> {\n const { keys } = await this.pluginKeySource.listKeys();\n return { keys: keys.map(({ key }) => key) };\n }\n\n #getJwtExpiration(token: string) {\n const { exp } = decodeJwt(token);\n if (!exp) {\n throw new AuthenticationError('User token is missing expiration');\n }\n return new Date(exp * 1000);\n }\n}\n"],"names":["userResult","AuthenticationError","createCredentialsWithUserPrincipal","createCredentialsWithServicePrincipal","createCredentialsWithNonePrincipal","toInternalBackstageCredentials","decodeJwt"],"mappings":"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"}
|
|
@@ -19,7 +19,7 @@ function createCredentialsWithServicePrincipal(sub, token, accessRestrictions) {
|
|
|
19
19
|
}
|
|
20
20
|
);
|
|
21
21
|
}
|
|
22
|
-
function createCredentialsWithUserPrincipal(sub, token, expiresAt) {
|
|
22
|
+
function createCredentialsWithUserPrincipal(sub, token, expiresAt, actor) {
|
|
23
23
|
return Object.defineProperty(
|
|
24
24
|
{
|
|
25
25
|
$$type: "@backstage/BackstageCredentials",
|
|
@@ -27,7 +27,10 @@ function createCredentialsWithUserPrincipal(sub, token, expiresAt) {
|
|
|
27
27
|
expiresAt,
|
|
28
28
|
principal: {
|
|
29
29
|
type: "user",
|
|
30
|
-
userEntityRef: sub
|
|
30
|
+
userEntityRef: sub,
|
|
31
|
+
...actor && {
|
|
32
|
+
actor: { type: "service", subject: actor }
|
|
33
|
+
}
|
|
31
34
|
}
|
|
32
35
|
},
|
|
33
36
|
"token",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.cjs.js","sources":["../../../src/entrypoints/auth/helpers.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n BackstageCredentials,\n BackstageNonePrincipal,\n BackstagePrincipalAccessRestrictions,\n BackstageServicePrincipal,\n BackstageUserPrincipal,\n} from '@backstage/backend-plugin-api';\nimport { InternalBackstageCredentials } from './types';\n\nexport function createCredentialsWithServicePrincipal(\n sub: string,\n token?: string,\n accessRestrictions?: BackstagePrincipalAccessRestrictions,\n): InternalBackstageCredentials<BackstageServicePrincipal> {\n return Object.defineProperty(\n {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n principal: {\n type: 'service',\n subject: sub,\n accessRestrictions,\n },\n },\n 'token',\n {\n enumerable: false,\n configurable: true,\n value: token,\n },\n );\n}\n\nexport function createCredentialsWithUserPrincipal(\n sub: string,\n token: string,\n expiresAt?: Date,\n): InternalBackstageCredentials<BackstageUserPrincipal> {\n return Object.defineProperty(\n {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n expiresAt,\n principal: {\n type: 'user',\n userEntityRef: sub,\n },\n },\n 'token',\n {\n enumerable: false,\n configurable: true,\n value: token,\n },\n );\n}\n\nexport function createCredentialsWithNonePrincipal(): InternalBackstageCredentials<BackstageNonePrincipal> {\n return {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n principal: {\n type: 'none',\n },\n };\n}\n\nexport function toInternalBackstageCredentials(\n credentials: BackstageCredentials,\n): InternalBackstageCredentials<\n BackstageUserPrincipal | BackstageServicePrincipal | BackstageNonePrincipal\n> {\n if (credentials.$$type !== '@backstage/BackstageCredentials') {\n throw new Error('Invalid credential type');\n }\n\n const internalCredentials = credentials as InternalBackstageCredentials<\n BackstageUserPrincipal | BackstageServicePrincipal | BackstageNonePrincipal\n >;\n\n if (internalCredentials.version !== 'v1') {\n throw new Error(\n `Invalid credential version ${internalCredentials.version}`,\n );\n }\n\n return internalCredentials;\n}\n"],"names":[],"mappings":";;AAyBgB,SAAA,qCAAA,CACd,GACA,EAAA,KAAA,EACA,kBACyD,EAAA;AACzD,EAAA,OAAO,MAAO,CAAA,cAAA;AAAA,IACZ;AAAA,MACE,MAAQ,EAAA,iCAAA;AAAA,MACR,OAAS,EAAA,IAAA;AAAA,MACT,SAAW,EAAA;AAAA,QACT,IAAM,EAAA,SAAA;AAAA,QACN,OAAS,EAAA,GAAA;AAAA,QACT;AAAA;AACF,KACF;AAAA,IACA,OAAA;AAAA,IACA;AAAA,MACE,UAAY,EAAA,KAAA;AAAA,MACZ,YAAc,EAAA,IAAA;AAAA,MACd,KAAO,EAAA;AAAA;AACT,GACF;AACF;
|
|
1
|
+
{"version":3,"file":"helpers.cjs.js","sources":["../../../src/entrypoints/auth/helpers.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n BackstageCredentials,\n BackstageNonePrincipal,\n BackstagePrincipalAccessRestrictions,\n BackstageServicePrincipal,\n BackstageUserPrincipal,\n} from '@backstage/backend-plugin-api';\nimport { InternalBackstageCredentials } from './types';\n\nexport function createCredentialsWithServicePrincipal(\n sub: string,\n token?: string,\n accessRestrictions?: BackstagePrincipalAccessRestrictions,\n): InternalBackstageCredentials<BackstageServicePrincipal> {\n return Object.defineProperty(\n {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n principal: {\n type: 'service',\n subject: sub,\n accessRestrictions,\n },\n },\n 'token',\n {\n enumerable: false,\n configurable: true,\n value: token,\n },\n );\n}\n\nexport function createCredentialsWithUserPrincipal(\n sub: string,\n token: string,\n expiresAt?: Date,\n actor?: string,\n): InternalBackstageCredentials<BackstageUserPrincipal> {\n return Object.defineProperty(\n {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n expiresAt,\n principal: {\n type: 'user',\n userEntityRef: sub,\n ...(actor && {\n actor: { type: 'service', subject: actor },\n }),\n },\n },\n 'token',\n {\n enumerable: false,\n configurable: true,\n value: token,\n },\n );\n}\n\nexport function createCredentialsWithNonePrincipal(): InternalBackstageCredentials<BackstageNonePrincipal> {\n return {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n principal: {\n type: 'none',\n },\n };\n}\n\nexport function toInternalBackstageCredentials(\n credentials: BackstageCredentials,\n): InternalBackstageCredentials<\n BackstageUserPrincipal | BackstageServicePrincipal | BackstageNonePrincipal\n> {\n if (credentials.$$type !== '@backstage/BackstageCredentials') {\n throw new Error('Invalid credential type');\n }\n\n const internalCredentials = credentials as InternalBackstageCredentials<\n BackstageUserPrincipal | BackstageServicePrincipal | BackstageNonePrincipal\n >;\n\n if (internalCredentials.version !== 'v1') {\n throw new Error(\n `Invalid credential version ${internalCredentials.version}`,\n );\n }\n\n return internalCredentials;\n}\n"],"names":[],"mappings":";;AAyBgB,SAAA,qCAAA,CACd,GACA,EAAA,KAAA,EACA,kBACyD,EAAA;AACzD,EAAA,OAAO,MAAO,CAAA,cAAA;AAAA,IACZ;AAAA,MACE,MAAQ,EAAA,iCAAA;AAAA,MACR,OAAS,EAAA,IAAA;AAAA,MACT,SAAW,EAAA;AAAA,QACT,IAAM,EAAA,SAAA;AAAA,QACN,OAAS,EAAA,GAAA;AAAA,QACT;AAAA;AACF,KACF;AAAA,IACA,OAAA;AAAA,IACA;AAAA,MACE,UAAY,EAAA,KAAA;AAAA,MACZ,YAAc,EAAA,IAAA;AAAA,MACd,KAAO,EAAA;AAAA;AACT,GACF;AACF;AAEO,SAAS,kCACd,CAAA,GAAA,EACA,KACA,EAAA,SAAA,EACA,KACsD,EAAA;AACtD,EAAA,OAAO,MAAO,CAAA,cAAA;AAAA,IACZ;AAAA,MACE,MAAQ,EAAA,iCAAA;AAAA,MACR,OAAS,EAAA,IAAA;AAAA,MACT,SAAA;AAAA,MACA,SAAW,EAAA;AAAA,QACT,IAAM,EAAA,MAAA;AAAA,QACN,aAAe,EAAA,GAAA;AAAA,QACf,GAAI,KAAS,IAAA;AAAA,UACX,KAAO,EAAA,EAAE,IAAM,EAAA,SAAA,EAAW,SAAS,KAAM;AAAA;AAC3C;AACF,KACF;AAAA,IACA,OAAA;AAAA,IACA;AAAA,MACE,UAAY,EAAA,KAAA;AAAA,MACZ,YAAc,EAAA,IAAA;AAAA,MACd,KAAO,EAAA;AAAA;AACT,GACF;AACF;AAEO,SAAS,kCAA2F,GAAA;AACzG,EAAO,OAAA;AAAA,IACL,MAAQ,EAAA,iCAAA;AAAA,IACR,OAAS,EAAA,IAAA;AAAA,IACT,SAAW,EAAA;AAAA,MACT,IAAM,EAAA;AAAA;AACR,GACF;AACF;AAEO,SAAS,+BACd,WAGA,EAAA;AACA,EAAI,IAAA,WAAA,CAAY,WAAW,iCAAmC,EAAA;AAC5D,IAAM,MAAA,IAAI,MAAM,yBAAyB,CAAA;AAAA;AAG3C,EAAA,MAAM,mBAAsB,GAAA,WAAA;AAI5B,EAAI,IAAA,mBAAA,CAAoB,YAAY,IAAM,EAAA;AACxC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,2BAAA,EAA8B,oBAAoB,OAAO,CAAA;AAAA,KAC3D;AAAA;AAGF,EAAO,OAAA,mBAAA;AACT;;;;;;;"}
|