@backstage/plugin-permission-node 0.8.8-next.0 → 0.8.8-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/index.cjs.js +2 -0
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +100 -7
- package/dist/integration/createConditionExports.cjs.js +4 -3
- package/dist/integration/createConditionExports.cjs.js.map +1 -1
- package/dist/integration/createConditionFactory.cjs.js.map +1 -1
- package/dist/integration/createConditionTransformer.cjs.js +3 -3
- package/dist/integration/createConditionTransformer.cjs.js.map +1 -1
- package/dist/integration/createPermissionIntegrationRouter.cjs.js +8 -3
- package/dist/integration/createPermissionIntegrationRouter.cjs.js.map +1 -1
- package/dist/integration/createPermissionResourceRef.cjs.js +18 -0
- package/dist/integration/createPermissionResourceRef.cjs.js.map +1 -0
- package/dist/integration/createPermissionRule.cjs.js +6 -1
- package/dist/integration/createPermissionRule.cjs.js.map +1 -1
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @backstage/plugin-permission-node
|
|
2
2
|
|
|
3
|
+
## 0.8.8-next.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b71f634: Added a new `PermissionRuleset` type that encapsulates a lookup function for permission rules, which can be created by the new `PermissionsRegistryService` via the `getPermissionRuleset` method. The `createConditionTransformer` and `createConditionAuthorizer` functions have been adapted to receive these accessors as arguments, with their older counterparts being deprecated.
|
|
8
|
+
- a9621de: Added a new `createPermissionResourceRef` utility that encapsulates the constants and types related to a permission resource types. The `createConditionExports` and `createPermissionRule` functions have also been adapted to accept these references as arguments, deprecating their older counterparts.
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
- @backstage/backend-plugin-api@1.2.0-next.2
|
|
11
|
+
- @backstage/plugin-auth-node@0.6.0-next.2
|
|
12
|
+
- @backstage/config@1.3.2
|
|
13
|
+
- @backstage/errors@1.2.7
|
|
14
|
+
- @backstage/plugin-permission-common@0.8.4
|
|
15
|
+
|
|
16
|
+
## 0.8.8-next.1
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Updated dependencies
|
|
21
|
+
- @backstage/backend-plugin-api@1.2.0-next.1
|
|
22
|
+
- @backstage/plugin-auth-node@0.6.0-next.1
|
|
23
|
+
- @backstage/config@1.3.2
|
|
24
|
+
- @backstage/errors@1.2.7
|
|
25
|
+
- @backstage/plugin-permission-common@0.8.4
|
|
26
|
+
|
|
3
27
|
## 0.8.8-next.0
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/dist/index.cjs.js
CHANGED
|
@@ -5,6 +5,7 @@ var createConditionExports = require('./integration/createConditionExports.cjs.j
|
|
|
5
5
|
var createConditionTransformer = require('./integration/createConditionTransformer.cjs.js');
|
|
6
6
|
var createPermissionIntegrationRouter = require('./integration/createPermissionIntegrationRouter.cjs.js');
|
|
7
7
|
var createPermissionRule = require('./integration/createPermissionRule.cjs.js');
|
|
8
|
+
var createPermissionResourceRef = require('./integration/createPermissionResourceRef.cjs.js');
|
|
8
9
|
var util = require('./integration/util.cjs.js');
|
|
9
10
|
var ServerPermissionClient = require('./ServerPermissionClient.cjs.js');
|
|
10
11
|
|
|
@@ -17,6 +18,7 @@ exports.createConditionAuthorizer = createPermissionIntegrationRouter.createCond
|
|
|
17
18
|
exports.createPermissionIntegrationRouter = createPermissionIntegrationRouter.createPermissionIntegrationRouter;
|
|
18
19
|
exports.createPermissionRule = createPermissionRule.createPermissionRule;
|
|
19
20
|
exports.makeCreatePermissionRule = createPermissionRule.makeCreatePermissionRule;
|
|
21
|
+
exports.createPermissionResourceRef = createPermissionResourceRef.createPermissionResourceRef;
|
|
20
22
|
exports.isAndCriteria = util.isAndCriteria;
|
|
21
23
|
exports.isNotCriteria = util.isNotCriteria;
|
|
22
24
|
exports.isOrCriteria = util.isOrCriteria;
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -78,6 +78,25 @@ type PermissionRule<TResource, TQuery, TResourceType extends string, TParams ext
|
|
|
78
78
|
*/
|
|
79
79
|
toQuery(params: NoInfer<TParams>): PermissionCriteria<TQuery>;
|
|
80
80
|
};
|
|
81
|
+
/**
|
|
82
|
+
* A set of registered rules for a particular resource type.
|
|
83
|
+
*
|
|
84
|
+
* @remarks
|
|
85
|
+
*
|
|
86
|
+
* Accessed via {@link @backstage/backend-plugin-api#PermissionsRegistryService.getPermissionRuleset}.
|
|
87
|
+
*
|
|
88
|
+
* @public
|
|
89
|
+
*/
|
|
90
|
+
type PermissionRuleset<TResource = unknown, TQuery = unknown, TResourceType extends string = string> = {
|
|
91
|
+
/**
|
|
92
|
+
* Returns a resource permission rule by name.
|
|
93
|
+
*
|
|
94
|
+
* @remarks
|
|
95
|
+
*
|
|
96
|
+
* Will throw an error if a rule with the provided name does not exist.
|
|
97
|
+
*/
|
|
98
|
+
getRuleByName(name: string): PermissionRule<TResource, TQuery, TResourceType>;
|
|
99
|
+
};
|
|
81
100
|
|
|
82
101
|
/**
|
|
83
102
|
* Creates a condition factory function for a given authorization rule and parameter types.
|
|
@@ -88,7 +107,7 @@ type PermissionRule<TResource, TQuery, TResourceType extends string, TParams ext
|
|
|
88
107
|
* The rule itself defines _how_ to check a given resource, whereas a condition also includes _what_
|
|
89
108
|
* to verify.
|
|
90
109
|
*
|
|
91
|
-
* Plugin authors should generally use the {@link createConditionExports} in order to efficiently
|
|
110
|
+
* Plugin authors should generally use the {@link (createConditionExports:1)} in order to efficiently
|
|
92
111
|
* create multiple condition factories. This helper should generally only be used to construct
|
|
93
112
|
* condition factories for third-party rules that aren't part of the backend plugin with which
|
|
94
113
|
* they're intended to integrate.
|
|
@@ -97,6 +116,26 @@ type PermissionRule<TResource, TQuery, TResourceType extends string, TParams ext
|
|
|
97
116
|
*/
|
|
98
117
|
declare const createConditionFactory: <TResourceType extends string, TParams extends PermissionRuleParams = PermissionRuleParams>(rule: PermissionRule<unknown, unknown, TResourceType, TParams>) => (params: TParams) => PermissionCondition<TResourceType, TParams>;
|
|
99
118
|
|
|
119
|
+
/**
|
|
120
|
+
* @public
|
|
121
|
+
*/
|
|
122
|
+
type PermissionResourceRef<TResource = unknown, TQuery = unknown, TResourceType extends string = string, TPluginId extends string = string> = {
|
|
123
|
+
readonly $$type: '@backstage/PermissionResourceRef';
|
|
124
|
+
readonly pluginId: TPluginId;
|
|
125
|
+
readonly resourceType: TResourceType;
|
|
126
|
+
readonly TQuery: TQuery;
|
|
127
|
+
readonly TResource: TResource;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* @public
|
|
131
|
+
*/
|
|
132
|
+
declare function createPermissionResourceRef<TResource, TQuery>(): {
|
|
133
|
+
with<TPluginId extends string, TResourceType extends string>(options: {
|
|
134
|
+
pluginId: TPluginId;
|
|
135
|
+
resourceType: TResourceType;
|
|
136
|
+
}): PermissionResourceRef<TResource, TQuery, TResourceType, TPluginId>;
|
|
137
|
+
};
|
|
138
|
+
|
|
100
139
|
/**
|
|
101
140
|
* A utility type for mapping a single {@link PermissionRule} to its
|
|
102
141
|
* corresponding {@link @backstage/plugin-permission-common#PermissionCondition}.
|
|
@@ -133,11 +172,22 @@ type Conditions<TRules extends Record<string, PermissionRule<any, any, any>>> =
|
|
|
133
172
|
*
|
|
134
173
|
* @public
|
|
135
174
|
*/
|
|
136
|
-
declare
|
|
175
|
+
declare function createConditionExports<TResourceType extends string, TResource, TRules extends Record<string, PermissionRule<TResource, any, TResourceType>>>(options: {
|
|
176
|
+
resourceRef: PermissionResourceRef<TResource, any, TResourceType>;
|
|
177
|
+
rules: TRules;
|
|
178
|
+
}): {
|
|
179
|
+
conditions: Conditions<TRules>;
|
|
180
|
+
createConditionalDecision: (permission: ResourcePermission<TResourceType>, conditions: PermissionCriteria<PermissionCondition<TResourceType>>) => ConditionalPolicyDecision;
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* @public
|
|
184
|
+
* @deprecated Use the version of `createConditionExports` that accepts a `resourceRef` option instead.
|
|
185
|
+
*/
|
|
186
|
+
declare function createConditionExports<TResourceType extends string, TResource, TRules extends Record<string, PermissionRule<TResource, any, TResourceType>>>(options: {
|
|
137
187
|
pluginId: string;
|
|
138
188
|
resourceType: TResourceType;
|
|
139
189
|
rules: TRules;
|
|
140
|
-
})
|
|
190
|
+
}): {
|
|
141
191
|
conditions: Conditions<TRules>;
|
|
142
192
|
createConditionalDecision: (permission: ResourcePermission<TResourceType>, conditions: PermissionCriteria<PermissionCondition<TResourceType>>) => ConditionalPolicyDecision;
|
|
143
193
|
};
|
|
@@ -159,7 +209,12 @@ type ConditionTransformer<TQuery> = (conditions: PermissionCriteria<PermissionCo
|
|
|
159
209
|
*
|
|
160
210
|
* @public
|
|
161
211
|
*/
|
|
162
|
-
declare
|
|
212
|
+
declare function createConditionTransformer<TQuery>(permissionRuleset: PermissionRuleset<any, TQuery>): ConditionTransformer<TQuery>;
|
|
213
|
+
/**
|
|
214
|
+
* @public
|
|
215
|
+
* @deprecated Use the version of `createConditionTransformer` that accepts a `PermissionRuleset` instead.
|
|
216
|
+
*/
|
|
217
|
+
declare function createConditionTransformer<TQuery, TRules extends PermissionRule<any, TQuery, string>[]>(permissionRules: [...TRules]): ConditionTransformer<TQuery>;
|
|
163
218
|
|
|
164
219
|
/**
|
|
165
220
|
* A request to load the referenced resource and apply conditions in order to
|
|
@@ -216,7 +271,12 @@ type MetadataResponse = MetadataResponse$1;
|
|
|
216
271
|
*
|
|
217
272
|
* @public
|
|
218
273
|
*/
|
|
219
|
-
declare
|
|
274
|
+
declare function createConditionAuthorizer<TResource>(permissionRuleset: PermissionRuleset<TResource>): (decision: PolicyDecision, resource: TResource | undefined) => boolean;
|
|
275
|
+
/**
|
|
276
|
+
* @public
|
|
277
|
+
* @deprecated Use the version of `createConditionAuthorizer` that accepts a `PermissionRuleset` instead.
|
|
278
|
+
*/
|
|
279
|
+
declare function createConditionAuthorizer<TResource, TQuery>(rules: PermissionRule<TResource, TQuery, string>[]): (decision: PolicyDecision, resource: TResource | undefined) => boolean;
|
|
220
280
|
/**
|
|
221
281
|
* Options for creating a permission integration router specific
|
|
222
282
|
* for a particular resource type.
|
|
@@ -294,14 +354,46 @@ declare function createPermissionIntegrationRouter<TResourceType1 extends string
|
|
|
294
354
|
addPermissions(permissions: Permission[]): void;
|
|
295
355
|
addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]): void;
|
|
296
356
|
addResourceType<const TResourceType extends string, TResource>(resource: CreatePermissionIntegrationRouterResourceOptions<TResourceType, TResource>): void;
|
|
357
|
+
getPermissionRuleset<TResource, TQuery, TResourceType extends string>(resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>): PermissionRuleset<TResource, TQuery, TResourceType>;
|
|
297
358
|
};
|
|
298
359
|
|
|
360
|
+
/**
|
|
361
|
+
* @public
|
|
362
|
+
*/
|
|
363
|
+
type CreatePermissionRuleOptions<TResource, TQuery, TQueryOutput extends TQuery, TResourceType extends string, TParams extends PermissionRuleParams> = {
|
|
364
|
+
name: string;
|
|
365
|
+
description: string;
|
|
366
|
+
resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>;
|
|
367
|
+
/**
|
|
368
|
+
* A ZodSchema that reflects the structure of the parameters that are passed to
|
|
369
|
+
*/
|
|
370
|
+
paramsSchema?: z.ZodSchema<TParams>;
|
|
371
|
+
/**
|
|
372
|
+
* Apply this rule to a resource already loaded from a backing data source. The params are
|
|
373
|
+
* arguments supplied for the rule; for example, a rule could be `isOwner` with entityRefs as the
|
|
374
|
+
* params.
|
|
375
|
+
*/
|
|
376
|
+
apply(resource: TResource, params: NoInfer<TParams>): boolean;
|
|
377
|
+
/**
|
|
378
|
+
* Translate this rule to criteria suitable for use in querying a backing data store. The criteria
|
|
379
|
+
* can be used for loading a collection of resources efficiently with conditional criteria already
|
|
380
|
+
* applied.
|
|
381
|
+
*/
|
|
382
|
+
toQuery(params: NoInfer<TParams>): PermissionCriteria<TQueryOutput>;
|
|
383
|
+
};
|
|
384
|
+
/**
|
|
385
|
+
* Helper function to create a {@link PermissionRule} for a specific resource type using a {@link PermissionResourceRef}.
|
|
386
|
+
*
|
|
387
|
+
* @public
|
|
388
|
+
*/
|
|
389
|
+
declare function createPermissionRule<TResource, TQuery, TQueryOutput extends TQuery, TResourceType extends string, TParams extends PermissionRuleParams = undefined>(rule: CreatePermissionRuleOptions<TResource, TQuery, TQueryOutput, TResourceType, TParams>): PermissionRule<TResource, TQuery, TResourceType, TParams>;
|
|
299
390
|
/**
|
|
300
391
|
* Helper function to ensure that {@link PermissionRule} definitions are typed correctly.
|
|
301
392
|
*
|
|
393
|
+
* @deprecated Use the version of `createPermissionRule` that accepts a `resourceRef` option instead.
|
|
302
394
|
* @public
|
|
303
395
|
*/
|
|
304
|
-
declare
|
|
396
|
+
declare function createPermissionRule<TResource, TQuery, TResourceType extends string, TParams extends PermissionRuleParams = undefined>(rule: PermissionRule<TResource, TQuery, TResourceType, TParams>): PermissionRule<TResource, TQuery, TResourceType, TParams>;
|
|
305
397
|
/**
|
|
306
398
|
* Helper for making plugin-specific createPermissionRule functions, that have
|
|
307
399
|
* the TResource and TQuery type parameters populated but infer the params from
|
|
@@ -309,6 +401,7 @@ declare const createPermissionRule: <TResource, TQuery, TResourceType extends st
|
|
|
309
401
|
* consistent types for the resource and query.
|
|
310
402
|
*
|
|
311
403
|
* @public
|
|
404
|
+
* @deprecated Use {@link (createPermissionRule:1)} directly instead with the resourceRef option.
|
|
312
405
|
*/
|
|
313
406
|
declare const makeCreatePermissionRule: <TResource, TQuery, TResourceType extends string>() => <TParams extends PermissionRuleParams = undefined>(rule: PermissionRule<TResource, TQuery, TResourceType, TParams>) => PermissionRule<TResource, TQuery, TResourceType, TParams>;
|
|
314
407
|
|
|
@@ -397,4 +490,4 @@ declare class ServerPermissionClient implements PermissionsService {
|
|
|
397
490
|
authorize(requests: AuthorizePermissionRequest[], options?: PermissionsServiceRequestOptions): Promise<AuthorizePermissionResponse[]>;
|
|
398
491
|
}
|
|
399
492
|
|
|
400
|
-
export { type ApplyConditionsRequest, type ApplyConditionsRequestEntry, type ApplyConditionsResponse, type ApplyConditionsResponseEntry, type Condition, type ConditionTransformer, type Conditions, type CreatePermissionIntegrationRouterResourceOptions, type MetadataResponse, type MetadataResponseSerializedRule, type PermissionIntegrationRouterOptions, type PermissionPolicy, type PermissionRule, type PolicyQuery, type PolicyQueryUser, ServerPermissionClient, createConditionAuthorizer, createConditionExports, createConditionFactory, createConditionTransformer, createPermissionIntegrationRouter, createPermissionRule, isAndCriteria, isNotCriteria, isOrCriteria, makeCreatePermissionRule };
|
|
493
|
+
export { type ApplyConditionsRequest, type ApplyConditionsRequestEntry, type ApplyConditionsResponse, type ApplyConditionsResponseEntry, type Condition, type ConditionTransformer, type Conditions, type CreatePermissionIntegrationRouterResourceOptions, type CreatePermissionRuleOptions, type MetadataResponse, type MetadataResponseSerializedRule, type PermissionIntegrationRouterOptions, type PermissionPolicy, type PermissionResourceRef, type PermissionRule, type PermissionRuleset, type PolicyQuery, type PolicyQueryUser, ServerPermissionClient, createConditionAuthorizer, createConditionExports, createConditionFactory, createConditionTransformer, createPermissionIntegrationRouter, createPermissionResourceRef, createPermissionRule, isAndCriteria, isNotCriteria, isOrCriteria, makeCreatePermissionRule };
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
var pluginPermissionCommon = require('@backstage/plugin-permission-common');
|
|
4
4
|
var createConditionFactory = require('./createConditionFactory.cjs.js');
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
const {
|
|
6
|
+
function createConditionExports(options) {
|
|
7
|
+
const { rules } = options;
|
|
8
|
+
const { pluginId, resourceType } = "resourceRef" in options ? options.resourceRef : options;
|
|
8
9
|
return {
|
|
9
10
|
conditions: Object.entries(rules).reduce(
|
|
10
11
|
(acc, [key, rule]) => ({
|
|
@@ -20,7 +21,7 @@ const createConditionExports = (options) => {
|
|
|
20
21
|
conditions
|
|
21
22
|
})
|
|
22
23
|
};
|
|
23
|
-
}
|
|
24
|
+
}
|
|
24
25
|
|
|
25
26
|
exports.createConditionExports = createConditionExports;
|
|
26
27
|
//# sourceMappingURL=createConditionExports.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createConditionExports.cjs.js","sources":["../../src/integration/createConditionExports.ts"],"sourcesContent":["/*\n * Copyright 2021 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 AuthorizeResult,\n ConditionalPolicyDecision,\n PermissionCondition,\n PermissionCriteria,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\nimport { createConditionFactory } from './createConditionFactory';\n\n/**\n * A utility type for mapping a single {@link PermissionRule} to its\n * corresponding {@link @backstage/plugin-permission-common#PermissionCondition}.\n *\n * @public\n */\nexport type Condition<TRule> = TRule extends PermissionRule<\n any,\n any,\n infer TResourceType,\n infer TParams\n>\n ? undefined extends TParams\n ? () => PermissionCondition<TResourceType, TParams>\n : (params: TParams) => PermissionCondition<TResourceType, TParams>\n : never;\n\n/**\n * A utility type for mapping {@link PermissionRule}s to their corresponding\n * {@link @backstage/plugin-permission-common#PermissionCondition}s.\n *\n * @public\n */\nexport type Conditions<\n TRules extends Record<string, PermissionRule<any, any, any>>,\n> = {\n [Name in keyof TRules]: Condition<TRules[Name]>;\n};\n\n/**\n * Creates the recommended condition-related exports for a given plugin based on\n * the built-in {@link PermissionRule}s it supports.\n *\n * @remarks\n *\n * The function returns a `conditions` object containing a\n * {@link @backstage/plugin-permission-common#PermissionCondition} factory for\n * each of the supplied {@link PermissionRule}s, along with a\n * `createConditionalDecision` function which builds the wrapper object needed\n * to enclose conditions when authoring {@link PermissionPolicy}\n * implementations.\n *\n * Plugin authors should generally call this method with all the built-in\n * {@link PermissionRule}s the plugin supports, and export the resulting\n * `conditions` object and `createConditionalDecision` function so that they can\n * be used by {@link PermissionPolicy} authors.\n *\n * @public\n */\nexport
|
|
1
|
+
{"version":3,"file":"createConditionExports.cjs.js","sources":["../../src/integration/createConditionExports.ts"],"sourcesContent":["/*\n * Copyright 2021 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 AuthorizeResult,\n ConditionalPolicyDecision,\n PermissionCondition,\n PermissionCriteria,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\nimport { createConditionFactory } from './createConditionFactory';\nimport { PermissionResourceRef } from './createPermissionResourceRef';\n\n/**\n * A utility type for mapping a single {@link PermissionRule} to its\n * corresponding {@link @backstage/plugin-permission-common#PermissionCondition}.\n *\n * @public\n */\nexport type Condition<TRule> = TRule extends PermissionRule<\n any,\n any,\n infer TResourceType,\n infer TParams\n>\n ? undefined extends TParams\n ? () => PermissionCondition<TResourceType, TParams>\n : (params: TParams) => PermissionCondition<TResourceType, TParams>\n : never;\n\n/**\n * A utility type for mapping {@link PermissionRule}s to their corresponding\n * {@link @backstage/plugin-permission-common#PermissionCondition}s.\n *\n * @public\n */\nexport type Conditions<\n TRules extends Record<string, PermissionRule<any, any, any>>,\n> = {\n [Name in keyof TRules]: Condition<TRules[Name]>;\n};\n\n/**\n * Creates the recommended condition-related exports for a given plugin based on\n * the built-in {@link PermissionRule}s it supports.\n *\n * @remarks\n *\n * The function returns a `conditions` object containing a\n * {@link @backstage/plugin-permission-common#PermissionCondition} factory for\n * each of the supplied {@link PermissionRule}s, along with a\n * `createConditionalDecision` function which builds the wrapper object needed\n * to enclose conditions when authoring {@link PermissionPolicy}\n * implementations.\n *\n * Plugin authors should generally call this method with all the built-in\n * {@link PermissionRule}s the plugin supports, and export the resulting\n * `conditions` object and `createConditionalDecision` function so that they can\n * be used by {@link PermissionPolicy} authors.\n *\n * @public\n */\nexport function createConditionExports<\n TResourceType extends string,\n TResource,\n TRules extends Record<string, PermissionRule<TResource, any, TResourceType>>,\n>(options: {\n resourceRef: PermissionResourceRef<TResource, any, TResourceType>;\n rules: TRules;\n}): {\n conditions: Conditions<TRules>;\n createConditionalDecision: (\n permission: ResourcePermission<TResourceType>,\n conditions: PermissionCriteria<PermissionCondition<TResourceType>>,\n ) => ConditionalPolicyDecision;\n};\n/**\n * @public\n * @deprecated Use the version of `createConditionExports` that accepts a `resourceRef` option instead.\n */\nexport function createConditionExports<\n TResourceType extends string,\n TResource,\n TRules extends Record<string, PermissionRule<TResource, any, TResourceType>>,\n>(options: {\n pluginId: string;\n resourceType: TResourceType;\n rules: TRules;\n}): {\n conditions: Conditions<TRules>;\n createConditionalDecision: (\n permission: ResourcePermission<TResourceType>,\n conditions: PermissionCriteria<PermissionCondition<TResourceType>>,\n ) => ConditionalPolicyDecision;\n};\nexport function createConditionExports<\n TResourceType extends string,\n TResource,\n TRules extends Record<string, PermissionRule<TResource, any, TResourceType>>,\n>(\n options:\n | {\n resourceRef: PermissionResourceRef<TResource, any, TResourceType>;\n rules: TRules;\n }\n | {\n pluginId: string;\n resourceType: TResourceType;\n rules: TRules;\n },\n): {\n conditions: Conditions<TRules>;\n createConditionalDecision: (\n permission: ResourcePermission<TResourceType>,\n conditions: PermissionCriteria<PermissionCondition<TResourceType>>,\n ) => ConditionalPolicyDecision;\n} {\n const { rules } = options;\n const { pluginId, resourceType } =\n 'resourceRef' in options ? options.resourceRef : options;\n\n return {\n conditions: Object.entries(rules).reduce(\n (acc, [key, rule]) => ({\n ...acc,\n [key]: createConditionFactory(rule),\n }),\n {} as Conditions<TRules>,\n ),\n createConditionalDecision: (\n _permission: ResourcePermission<TResourceType>,\n conditions: PermissionCriteria<PermissionCondition>,\n ) => ({\n result: AuthorizeResult.CONDITIONAL,\n pluginId,\n resourceType,\n conditions,\n }),\n };\n}\n"],"names":["createConditionFactory","AuthorizeResult"],"mappings":";;;;;AA6GO,SAAS,uBAKd,OAgBA,EAAA;AACA,EAAM,MAAA,EAAE,OAAU,GAAA,OAAA;AAClB,EAAA,MAAM,EAAE,QAAU,EAAA,YAAA,KAChB,aAAiB,IAAA,OAAA,GAAU,QAAQ,WAAc,GAAA,OAAA;AAEnD,EAAO,OAAA;AAAA,IACL,UAAY,EAAA,MAAA,CAAO,OAAQ,CAAA,KAAK,CAAE,CAAA,MAAA;AAAA,MAChC,CAAC,GAAA,EAAK,CAAC,GAAA,EAAK,IAAI,CAAO,MAAA;AAAA,QACrB,GAAG,GAAA;AAAA,QACH,CAAC,GAAG,GAAGA,6CAAA,CAAuB,IAAI;AAAA,OACpC,CAAA;AAAA,MACA;AAAC,KACH;AAAA,IACA,yBAAA,EAA2B,CACzB,WAAA,EACA,UACI,MAAA;AAAA,MACJ,QAAQC,sCAAgB,CAAA,WAAA;AAAA,MACxB,QAAA;AAAA,MACA,YAAA;AAAA,MACA;AAAA,KACF;AAAA,GACF;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createConditionFactory.cjs.js","sources":["../../src/integration/createConditionFactory.ts"],"sourcesContent":["/*\n * Copyright 2021 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 PermissionCondition,\n PermissionRuleParams,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\n\n/**\n * Creates a condition factory function for a given authorization rule and parameter types.\n *\n * @remarks\n *\n * For example, an isEntityOwner rule for catalog entities might take an array of entityRef strings.\n * The rule itself defines _how_ to check a given resource, whereas a condition also includes _what_\n * to verify.\n *\n * Plugin authors should generally use the {@link createConditionExports} in order to efficiently\n * create multiple condition factories. This helper should generally only be used to construct\n * condition factories for third-party rules that aren't part of the backend plugin with which\n * they're intended to integrate.\n *\n * @public\n */\nexport const createConditionFactory = <\n TResourceType extends string,\n TParams extends PermissionRuleParams = PermissionRuleParams,\n>(\n rule: PermissionRule<unknown, unknown, TResourceType, TParams>,\n) => {\n return (params: TParams): PermissionCondition<TResourceType, TParams> => {\n return {\n rule: rule.name,\n resourceType: rule.resourceType,\n params,\n };\n };\n};\n"],"names":[],"mappings":";;AAsCa,MAAA,sBAAA,GAAyB,CAIpC,IACG,KAAA;AACH,EAAA,OAAO,CAAC,MAAiE,KAAA;AACvE,IAAO,OAAA;AAAA,MACL,MAAM,IAAK,CAAA,IAAA;AAAA,MACX,cAAc,IAAK,CAAA,YAAA;AAAA,MACnB;AAAA,KACF;AAAA,GACF;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"createConditionFactory.cjs.js","sources":["../../src/integration/createConditionFactory.ts"],"sourcesContent":["/*\n * Copyright 2021 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 PermissionCondition,\n PermissionRuleParams,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\n\n/**\n * Creates a condition factory function for a given authorization rule and parameter types.\n *\n * @remarks\n *\n * For example, an isEntityOwner rule for catalog entities might take an array of entityRef strings.\n * The rule itself defines _how_ to check a given resource, whereas a condition also includes _what_\n * to verify.\n *\n * Plugin authors should generally use the {@link (createConditionExports:1)} in order to efficiently\n * create multiple condition factories. This helper should generally only be used to construct\n * condition factories for third-party rules that aren't part of the backend plugin with which\n * they're intended to integrate.\n *\n * @public\n */\nexport const createConditionFactory = <\n TResourceType extends string,\n TParams extends PermissionRuleParams = PermissionRuleParams,\n>(\n rule: PermissionRule<unknown, unknown, TResourceType, TParams>,\n) => {\n return (params: TParams): PermissionCondition<TResourceType, TParams> => {\n return {\n rule: rule.name,\n resourceType: rule.resourceType,\n params,\n };\n };\n};\n"],"names":[],"mappings":";;AAsCa,MAAA,sBAAA,GAAyB,CAIpC,IACG,KAAA;AACH,EAAA,OAAO,CAAC,MAAiE,KAAA;AACvE,IAAO,OAAA;AAAA,MACL,MAAM,IAAK,CAAA,IAAA;AAAA,MACX,cAAc,IAAK,CAAA,YAAA;AAAA,MACnB;AAAA,KACF;AAAA,GACF;AACF;;;;"}
|
|
@@ -24,10 +24,10 @@ const mapConditions = (criteria, getRule) => {
|
|
|
24
24
|
}
|
|
25
25
|
return rule.toQuery(criteria.params ?? {});
|
|
26
26
|
};
|
|
27
|
-
|
|
28
|
-
const getRule = util.createGetRule(permissionRules);
|
|
27
|
+
function createConditionTransformer(permissionRules) {
|
|
28
|
+
const getRule = "getRuleByName" in permissionRules ? (n) => permissionRules.getRuleByName(n) : util.createGetRule(permissionRules);
|
|
29
29
|
return (conditions) => mapConditions(conditions, getRule);
|
|
30
|
-
}
|
|
30
|
+
}
|
|
31
31
|
|
|
32
32
|
exports.createConditionTransformer = createConditionTransformer;
|
|
33
33
|
//# sourceMappingURL=createConditionTransformer.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createConditionTransformer.cjs.js","sources":["../../src/integration/createConditionTransformer.ts"],"sourcesContent":["/*\n * Copyright 2021 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 */\nimport { InputError } from '@backstage/errors';\nimport {\n AllOfCriteria,\n AnyOfCriteria,\n PermissionCondition,\n PermissionCriteria,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\nimport {\n createGetRule,\n isAndCriteria,\n isNotCriteria,\n isOrCriteria,\n} from './util';\n\nconst mapConditions = <TQuery>(\n criteria: PermissionCriteria<PermissionCondition>,\n getRule: (name: string) => PermissionRule<unknown, TQuery, string>,\n): PermissionCriteria<TQuery> => {\n if (isAndCriteria(criteria)) {\n return {\n allOf: criteria.allOf.map(child => mapConditions(child, getRule)),\n } as AllOfCriteria<TQuery>;\n } else if (isOrCriteria(criteria)) {\n return {\n anyOf: criteria.anyOf.map(child => mapConditions(child, getRule)),\n } as AnyOfCriteria<TQuery>;\n } else if (isNotCriteria(criteria)) {\n return {\n not: mapConditions(criteria.not, getRule),\n };\n }\n\n const rule = getRule(criteria.rule);\n const result = rule.paramsSchema?.safeParse(criteria.params);\n\n if (result && !result.success) {\n throw new InputError(`Parameters to rule are invalid`, result.error);\n }\n\n return rule.toQuery(criteria.params ?? {});\n};\n\n/**\n * A function which accepts {@link @backstage/plugin-permission-common#PermissionCondition}s\n * logically grouped in a {@link @backstage/plugin-permission-common#PermissionCriteria}\n * object, and transforms the {@link @backstage/plugin-permission-common#PermissionCondition}s\n * into plugin specific query fragments while retaining the enclosing criteria shape.\n *\n * @public\n */\nexport type ConditionTransformer<TQuery> = (\n conditions: PermissionCriteria<PermissionCondition>,\n) => PermissionCriteria<TQuery>;\n\n/**\n * A higher-order helper function which accepts an array of\n * {@link PermissionRule}s, and returns a {@link ConditionTransformer}\n * which transforms input conditions into equivalent plugin-specific\n * query fragments using the supplied rules.\n *\n * @public\n */\nexport
|
|
1
|
+
{"version":3,"file":"createConditionTransformer.cjs.js","sources":["../../src/integration/createConditionTransformer.ts"],"sourcesContent":["/*\n * Copyright 2021 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 */\nimport { InputError } from '@backstage/errors';\nimport {\n AllOfCriteria,\n AnyOfCriteria,\n PermissionCondition,\n PermissionCriteria,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule, PermissionRuleset } from '../types';\nimport {\n createGetRule,\n isAndCriteria,\n isNotCriteria,\n isOrCriteria,\n} from './util';\n\nconst mapConditions = <TQuery>(\n criteria: PermissionCriteria<PermissionCondition>,\n getRule: (name: string) => PermissionRule<unknown, TQuery, string>,\n): PermissionCriteria<TQuery> => {\n if (isAndCriteria(criteria)) {\n return {\n allOf: criteria.allOf.map(child => mapConditions(child, getRule)),\n } as AllOfCriteria<TQuery>;\n } else if (isOrCriteria(criteria)) {\n return {\n anyOf: criteria.anyOf.map(child => mapConditions(child, getRule)),\n } as AnyOfCriteria<TQuery>;\n } else if (isNotCriteria(criteria)) {\n return {\n not: mapConditions(criteria.not, getRule),\n };\n }\n\n const rule = getRule(criteria.rule);\n const result = rule.paramsSchema?.safeParse(criteria.params);\n\n if (result && !result.success) {\n throw new InputError(`Parameters to rule are invalid`, result.error);\n }\n\n return rule.toQuery(criteria.params ?? {});\n};\n\n/**\n * A function which accepts {@link @backstage/plugin-permission-common#PermissionCondition}s\n * logically grouped in a {@link @backstage/plugin-permission-common#PermissionCriteria}\n * object, and transforms the {@link @backstage/plugin-permission-common#PermissionCondition}s\n * into plugin specific query fragments while retaining the enclosing criteria shape.\n *\n * @public\n */\nexport type ConditionTransformer<TQuery> = (\n conditions: PermissionCriteria<PermissionCondition>,\n) => PermissionCriteria<TQuery>;\n\n/**\n * A higher-order helper function which accepts an array of\n * {@link PermissionRule}s, and returns a {@link ConditionTransformer}\n * which transforms input conditions into equivalent plugin-specific\n * query fragments using the supplied rules.\n *\n * @public\n */\nexport function createConditionTransformer<TQuery>(\n permissionRuleset: PermissionRuleset<any, TQuery>,\n): ConditionTransformer<TQuery>;\n/**\n * @public\n * @deprecated Use the version of `createConditionTransformer` that accepts a `PermissionRuleset` instead.\n */\nexport function createConditionTransformer<\n TQuery,\n TRules extends PermissionRule<any, TQuery, string>[],\n>(permissionRules: [...TRules]): ConditionTransformer<TQuery>;\nexport function createConditionTransformer<TQuery>(\n permissionRules:\n | PermissionRule<any, TQuery, string>[]\n | PermissionRuleset<any, TQuery>,\n): ConditionTransformer<TQuery> {\n const getRule =\n 'getRuleByName' in permissionRules\n ? (n: string) => permissionRules.getRuleByName(n)\n : createGetRule(permissionRules);\n\n return conditions => mapConditions(conditions, getRule);\n}\n"],"names":["isAndCriteria","isOrCriteria","isNotCriteria","InputError","createGetRule"],"mappings":";;;;;AA8BA,MAAM,aAAA,GAAgB,CACpB,QAAA,EACA,OAC+B,KAAA;AAC/B,EAAI,IAAAA,kBAAA,CAAc,QAAQ,CAAG,EAAA;AAC3B,IAAO,OAAA;AAAA,MACL,KAAA,EAAO,SAAS,KAAM,CAAA,GAAA,CAAI,WAAS,aAAc,CAAA,KAAA,EAAO,OAAO,CAAC;AAAA,KAClE;AAAA,GACF,MAAA,IAAWC,iBAAa,CAAA,QAAQ,CAAG,EAAA;AACjC,IAAO,OAAA;AAAA,MACL,KAAA,EAAO,SAAS,KAAM,CAAA,GAAA,CAAI,WAAS,aAAc,CAAA,KAAA,EAAO,OAAO,CAAC;AAAA,KAClE;AAAA,GACF,MAAA,IAAWC,kBAAc,CAAA,QAAQ,CAAG,EAAA;AAClC,IAAO,OAAA;AAAA,MACL,GAAK,EAAA,aAAA,CAAc,QAAS,CAAA,GAAA,EAAK,OAAO;AAAA,KAC1C;AAAA;AAGF,EAAM,MAAA,IAAA,GAAO,OAAQ,CAAA,QAAA,CAAS,IAAI,CAAA;AAClC,EAAA,MAAM,MAAS,GAAA,IAAA,CAAK,YAAc,EAAA,SAAA,CAAU,SAAS,MAAM,CAAA;AAE3D,EAAI,IAAA,MAAA,IAAU,CAAC,MAAA,CAAO,OAAS,EAAA;AAC7B,IAAA,MAAM,IAAIC,iBAAA,CAAW,CAAkC,8BAAA,CAAA,EAAA,MAAA,CAAO,KAAK,CAAA;AAAA;AAGrE,EAAA,OAAO,IAAK,CAAA,OAAA,CAAQ,QAAS,CAAA,MAAA,IAAU,EAAE,CAAA;AAC3C,CAAA;AAiCO,SAAS,2BACd,eAG8B,EAAA;AAC9B,EAAM,MAAA,OAAA,GACJ,eAAmB,IAAA,eAAA,GACf,CAAC,CAAA,KAAc,gBAAgB,aAAc,CAAA,CAAC,CAC9C,GAAAC,kBAAA,CAAc,eAAe,CAAA;AAEnC,EAAO,OAAA,CAAA,UAAA,KAAc,aAAc,CAAA,UAAA,EAAY,OAAO,CAAA;AACxD;;;;"}
|
|
@@ -58,15 +58,15 @@ const applyConditions = (criteria, resource, getRule) => {
|
|
|
58
58
|
}
|
|
59
59
|
return rule.apply(resource, criteria.params ?? {});
|
|
60
60
|
};
|
|
61
|
-
|
|
62
|
-
const getRule = util.createGetRule(rules);
|
|
61
|
+
function createConditionAuthorizer(rules) {
|
|
62
|
+
const getRule = "getRuleByName" in rules ? (n) => rules.getRuleByName(n) : util.createGetRule(rules);
|
|
63
63
|
return (decision, resource) => {
|
|
64
64
|
if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
|
|
65
65
|
return applyConditions(decision.conditions, resource, getRule);
|
|
66
66
|
}
|
|
67
67
|
return decision.result === pluginPermissionCommon.AuthorizeResult.ALLOW;
|
|
68
68
|
};
|
|
69
|
-
}
|
|
69
|
+
}
|
|
70
70
|
class PermissionIntegrationMetadataStore {
|
|
71
71
|
#rulesByTypeByName = /* @__PURE__ */ new Map();
|
|
72
72
|
#permissionsByName = /* @__PURE__ */ new Map();
|
|
@@ -209,6 +209,11 @@ function createPermissionIntegrationRouter(options) {
|
|
|
209
209
|
},
|
|
210
210
|
addResourceType(resource) {
|
|
211
211
|
store.addResourceType(resource);
|
|
212
|
+
},
|
|
213
|
+
getPermissionRuleset(resourceRef) {
|
|
214
|
+
return {
|
|
215
|
+
getRuleByName: store.getRuleMapper(resourceRef.resourceType)
|
|
216
|
+
};
|
|
212
217
|
}
|
|
213
218
|
});
|
|
214
219
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createPermissionIntegrationRouter.cjs.js","sources":["../../src/integration/createPermissionIntegrationRouter.ts"],"sourcesContent":["/*\n * Copyright 2021 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 express, { Response } from 'express';\nimport Router from 'express-promise-router';\nimport { z } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { InputError } from '@backstage/errors';\nimport {\n AuthorizeResult,\n DefinitivePolicyDecision,\n IdentifiedPermissionMessage,\n MetadataResponse as CommonMetadataResponse,\n MetadataResponseSerializedRule as CommonMetadataResponseSerializedRule,\n Permission,\n PermissionCondition,\n PermissionCriteria,\n PolicyDecision,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\nimport {\n NoInfer,\n createGetRule,\n isAndCriteria,\n isNotCriteria,\n isOrCriteria,\n} from './util';\nimport { NotImplementedError } from '@backstage/errors';\n\nconst permissionCriteriaSchema: z.ZodSchema<\n PermissionCriteria<PermissionCondition>\n> = z.lazy(() =>\n z.union([\n z.object({ anyOf: z.array(permissionCriteriaSchema).nonempty() }),\n z.object({ allOf: z.array(permissionCriteriaSchema).nonempty() }),\n z.object({ not: permissionCriteriaSchema }),\n z.object({\n rule: z.string(),\n resourceType: z.string(),\n params: z.record(z.any()).optional(),\n }),\n ]),\n);\n\nconst applyConditionsRequestSchema = z.object({\n items: z.array(\n z.object({\n id: z.string(),\n resourceRef: z.string(),\n resourceType: z.string(),\n conditions: permissionCriteriaSchema,\n }),\n ),\n});\n\n/**\n * A request to load the referenced resource and apply conditions in order to\n * finalize a conditional authorization response.\n *\n * @public\n */\nexport type ApplyConditionsRequestEntry = IdentifiedPermissionMessage<{\n resourceRef: string;\n resourceType: string;\n conditions: PermissionCriteria<PermissionCondition>;\n}>;\n\n/**\n * A batch of {@link ApplyConditionsRequestEntry} objects.\n *\n * @public\n */\nexport type ApplyConditionsRequest = {\n items: ApplyConditionsRequestEntry[];\n};\n\n/**\n * The result of applying the conditions, expressed as a definitive authorize\n * result of ALLOW or DENY.\n *\n * @public\n */\nexport type ApplyConditionsResponseEntry =\n IdentifiedPermissionMessage<DefinitivePolicyDecision>;\n\n/**\n * A batch of {@link ApplyConditionsResponseEntry} objects.\n *\n * @public\n */\nexport type ApplyConditionsResponse = {\n items: ApplyConditionsResponseEntry[];\n};\n\n/**\n * Serialized permission rules, with the paramsSchema\n * converted from a ZodSchema to a JsonSchema.\n *\n * @public\n * @deprecated Please import from `@backstage/plugin-permission-common` instead.\n */\nexport type MetadataResponseSerializedRule =\n CommonMetadataResponseSerializedRule;\n\n/**\n * Response type for the .metadata endpoint.\n *\n * @public\n * @deprecated Please import from `@backstage/plugin-permission-common` instead.\n */\nexport type MetadataResponse = CommonMetadataResponse;\n\nconst applyConditions = <TResourceType extends string, TResource>(\n criteria: PermissionCriteria<PermissionCondition<TResourceType>>,\n resource: TResource | undefined,\n getRule: (name: string) => PermissionRule<TResource, unknown, TResourceType>,\n): boolean => {\n // If resource was not found, deny. This avoids leaking information from the\n // apply-conditions API which would allow a user to differentiate between\n // non-existent resources and resources to which they do not have access.\n if (resource === undefined) {\n return false;\n }\n\n if (isAndCriteria(criteria)) {\n return criteria.allOf.every(child =>\n applyConditions(child, resource, getRule),\n );\n } else if (isOrCriteria(criteria)) {\n return criteria.anyOf.some(child =>\n applyConditions(child, resource, getRule),\n );\n } else if (isNotCriteria(criteria)) {\n return !applyConditions(criteria.not, resource, getRule);\n }\n\n const rule = getRule(criteria.rule);\n const result = rule.paramsSchema?.safeParse(criteria.params);\n\n if (result && !result.success) {\n throw new InputError(`Parameters to rule are invalid`, result.error);\n }\n\n return rule.apply(resource, criteria.params ?? {});\n};\n\n/**\n * Takes some permission conditions and returns a definitive authorization result\n * on the resource to which they apply.\n *\n * @public\n */\nexport const createConditionAuthorizer = <TResource, TQuery>(\n rules: PermissionRule<TResource, TQuery, string>[],\n) => {\n const getRule = createGetRule(rules);\n\n return (\n decision: PolicyDecision,\n resource: TResource | undefined,\n ): boolean => {\n if (decision.result === AuthorizeResult.CONDITIONAL) {\n return applyConditions(decision.conditions, resource, getRule);\n }\n\n return decision.result === AuthorizeResult.ALLOW;\n };\n};\n\n/**\n * Options for creating a permission integration router specific\n * for a particular resource type.\n *\n * @public\n */\nexport type CreatePermissionIntegrationRouterResourceOptions<\n TResourceType extends string,\n TResource,\n> = {\n resourceType: TResourceType;\n permissions?: Array<Permission>;\n // Do not infer value of TResourceType from supplied rules.\n // instead only consider the resourceType parameter, and\n // consider any rules whose resource type does not match\n // to be an error.\n rules: PermissionRule<TResource, any, NoInfer<TResourceType>>[];\n getResources?: (\n resourceRefs: string[],\n ) => Promise<Array<TResource | undefined>>;\n};\n\n/**\n * Options for creating a permission integration router exposing\n * permissions and rules from multiple resource types.\n *\n * @public\n */\nexport type PermissionIntegrationRouterOptions<\n TResourceType1 extends string = string,\n TResource1 = any,\n TResourceType2 extends string = string,\n TResource2 = any,\n TResourceType3 extends string = string,\n TResource3 = any,\n> = {\n resources: Readonly<\n | [\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >,\n ]\n | [\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >,\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType2,\n TResource2\n >,\n ]\n | [\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >,\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType2,\n TResource2\n >,\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType3,\n TResource3\n >,\n ]\n >;\n};\n\nclass PermissionIntegrationMetadataStore {\n readonly #rulesByTypeByName = new Map<\n string,\n Map<string, PermissionRule<unknown, unknown, string>>\n >();\n readonly #permissionsByName = new Map<string, Permission>();\n readonly #resourcesByType = new Map<\n string,\n CreatePermissionIntegrationRouterResourceOptions<string, unknown>\n >();\n readonly #serializedRules = new Array<MetadataResponseSerializedRule>();\n\n getSerializedMetadata(): MetadataResponse {\n return {\n permissions: Array.from(this.#permissionsByName.values()),\n rules: this.#serializedRules,\n };\n }\n\n hasResourceType(type: string): boolean {\n return this.#resourcesByType.has(type);\n }\n\n async getResources(\n resourceType: string,\n refs: string[],\n ): Promise<Record<string, unknown>> {\n const resource = this.#resourcesByType.get(resourceType);\n if (!resource?.getResources) {\n throw new NotImplementedError(\n `This plugin does not expose any permission rule or can't evaluate the conditions request for ${resourceType}`,\n );\n }\n\n const uniqueRefs = Array.from(new Set(refs));\n const resources = await resource.getResources(uniqueRefs);\n return Object.fromEntries(\n uniqueRefs.map((ref, index) => [ref, resources[index]]),\n );\n }\n\n getRuleMapper(resourceType: string) {\n return (name: string): PermissionRule<unknown, unknown, string> => {\n const rule = this.#rulesByTypeByName.get(resourceType)?.get(name);\n if (!rule) {\n throw new Error(\n `Permission rule '${name}' does not exist for resource type '${resourceType}'`,\n );\n }\n return rule;\n };\n }\n\n addPermissions(permissions: Permission[]) {\n for (const permission of permissions) {\n // Permission naming conflicts are silently ignored\n this.#permissionsByName.set(permission.name, permission);\n }\n }\n\n addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]) {\n for (const rule of rules) {\n const rulesByName =\n this.#rulesByTypeByName.get(rule.resourceType) ?? new Map();\n this.#rulesByTypeByName.set(rule.resourceType, rulesByName);\n\n if (rulesByName.has(rule.name)) {\n throw new Error(\n `Refused to add permission rule for type '${rule.resourceType}' with name '${rule.name}' because it already exists`,\n );\n }\n rulesByName.set(rule.name, rule);\n\n this.#serializedRules.push({\n name: rule.name,\n description: rule.description,\n resourceType: rule.resourceType,\n paramsSchema: zodToJsonSchema(rule.paramsSchema ?? z.object({})),\n });\n }\n }\n\n addResourceType(\n resource: CreatePermissionIntegrationRouterResourceOptions<string, unknown>,\n ) {\n const { resourceType } = resource;\n\n if (this.#resourcesByType.has(resourceType)) {\n throw new Error(\n `Refused to add permission resource with type '${resourceType}' because it already exists`,\n );\n }\n this.#resourcesByType.set(resourceType, resource);\n\n if (resource.rules) {\n this.addPermissionRules(resource.rules);\n }\n\n if (resource.permissions) {\n this.addPermissions(resource.permissions);\n }\n }\n}\n\n/**\n * Create an express Router which provides an authorization route to allow\n * integration between the permission backend and other Backstage backend\n * plugins. Plugin owners that wish to support conditional authorization for\n * their resources should add the router created by this function to their\n * express app inside their `createRouter` implementation.\n *\n * In case the `permissions` option is provided, the router also\n * provides a route that exposes permissions and routes of a plugin.\n *\n * In case resources is provided, the routes can handle permissions\n * for multiple resource types.\n *\n * @remarks\n *\n * To make this concrete, we can use the Backstage software catalog as an\n * example. The catalog has conditional rules around access to specific\n * _entities_ in the catalog. The _type_ of resource is captured here as\n * `resourceType`, a string identifier (`catalog-entity` in this example) that\n * can be provided with permission definitions. This is merely a _type_ to\n * verify that conditions in an authorization policy are constructed correctly,\n * not a reference to a specific resource.\n *\n * The `rules` parameter is an array of {@link PermissionRule}s that introduce\n * conditional filtering logic for resources; for the catalog, these are things\n * like `isEntityOwner` or `hasAnnotation`. Rules describe how to filter a list\n * of resources, and the `conditions` returned allow these rules to be applied\n * with specific parameters (such as 'group:default/team-a', or\n * 'backstage.io/edit-url').\n *\n * The `getResources` argument should load resources based on a reference\n * identifier. For the catalog, this is an\n * {@link @backstage/catalog-model#EntityRef}. For other plugins, this can be\n * any serialized format. This is used to construct the\n * `createPermissionIntegrationRouter`, a function to add an authorization route\n * to your backend plugin. This function will be called by the\n * `permission-backend` when authorization conditions relating to this plugin\n * need to be evaluated.\n *\n * @public\n */\nexport function createPermissionIntegrationRouter<\n TResourceType1 extends string,\n TResource1,\n TResourceType2 extends string,\n TResource2,\n TResourceType3 extends string,\n TResource3,\n>(\n options?:\n | { permissions: Array<Permission> }\n | CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >\n | PermissionIntegrationRouterOptions<\n TResourceType1,\n TResource1,\n TResourceType2,\n TResource2,\n TResourceType3,\n TResource3\n >,\n): express.Router & {\n addPermissions(permissions: Permission[]): void;\n addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]): void;\n addResourceType<const TResourceType extends string, TResource>(\n resource: CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n ): void;\n} {\n const store = new PermissionIntegrationMetadataStore();\n\n if (options) {\n if ('resources' in options) {\n // Not technically allowed by types, but it's historically been covered by tests\n if ('permissions' in options) {\n store.addPermissions(options.permissions as Permission[]);\n }\n\n for (const resource of options.resources) {\n store.addResourceType(resource);\n }\n } else if ('resourceType' in options) {\n store.addResourceType(options);\n } else {\n store.addPermissions(options.permissions);\n }\n }\n\n const router = Router();\n\n router.use('/.well-known/backstage/permissions/', express.json());\n\n router.get('/.well-known/backstage/permissions/metadata', (_, res) => {\n res.json(store.getSerializedMetadata());\n });\n\n router.post(\n '/.well-known/backstage/permissions/apply-conditions',\n async (req, res: Response<ApplyConditionsResponse | string>) => {\n const parseResult = applyConditionsRequestSchema.safeParse(req.body);\n if (!parseResult.success) {\n throw new InputError(parseResult.error.toString());\n }\n\n const { items: requests } = parseResult.data;\n\n const invalidResourceTypes = requests.filter(\n i => !store.hasResourceType(i.resourceType),\n );\n if (invalidResourceTypes.length) {\n throw new InputError(\n `Unexpected resource types: ${invalidResourceTypes\n .map(i => i.resourceType)\n .join(', ')}.`,\n );\n }\n\n const resourcesByType: Record<string, Record<string, any>> = {};\n for (const requestedType of new Set(requests.map(i => i.resourceType))) {\n resourcesByType[requestedType] = await store.getResources(\n requestedType,\n requests\n .filter(r => r.resourceType === requestedType)\n .map(i => i.resourceRef),\n );\n }\n\n res.json({\n items: requests.map(request => ({\n id: request.id,\n result: applyConditions(\n request.conditions,\n resourcesByType[request.resourceType][request.resourceRef],\n store.getRuleMapper(request.resourceType),\n )\n ? AuthorizeResult.ALLOW\n : AuthorizeResult.DENY,\n })),\n });\n },\n );\n\n return Object.assign(router, {\n addPermissions(permissions: Permission[]) {\n store.addPermissions(permissions);\n },\n addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]) {\n store.addPermissionRules(rules);\n },\n addResourceType<const TResourceType extends string, TResource>(\n resource: CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n ) {\n store.addResourceType(resource);\n },\n });\n}\n"],"names":["z","isAndCriteria","isOrCriteria","isNotCriteria","InputError","createGetRule","AuthorizeResult","NotImplementedError","zodToJsonSchema","Router","express"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createPermissionIntegrationRouter.cjs.js","sources":["../../src/integration/createPermissionIntegrationRouter.ts"],"sourcesContent":["/*\n * Copyright 2021 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 express, { Response } from 'express';\nimport Router from 'express-promise-router';\nimport { z } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { InputError } from '@backstage/errors';\nimport {\n AuthorizeResult,\n DefinitivePolicyDecision,\n IdentifiedPermissionMessage,\n MetadataResponse as CommonMetadataResponse,\n MetadataResponseSerializedRule as CommonMetadataResponseSerializedRule,\n Permission,\n PermissionCondition,\n PermissionCriteria,\n PolicyDecision,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule, PermissionRuleset } from '../types';\nimport {\n NoInfer,\n createGetRule,\n isAndCriteria,\n isNotCriteria,\n isOrCriteria,\n} from './util';\nimport { NotImplementedError } from '@backstage/errors';\nimport { PermissionResourceRef } from './createPermissionResourceRef';\n\nconst permissionCriteriaSchema: z.ZodSchema<\n PermissionCriteria<PermissionCondition>\n> = z.lazy(() =>\n z.union([\n z.object({ anyOf: z.array(permissionCriteriaSchema).nonempty() }),\n z.object({ allOf: z.array(permissionCriteriaSchema).nonempty() }),\n z.object({ not: permissionCriteriaSchema }),\n z.object({\n rule: z.string(),\n resourceType: z.string(),\n params: z.record(z.any()).optional(),\n }),\n ]),\n);\n\nconst applyConditionsRequestSchema = z.object({\n items: z.array(\n z.object({\n id: z.string(),\n resourceRef: z.string(),\n resourceType: z.string(),\n conditions: permissionCriteriaSchema,\n }),\n ),\n});\n\n/**\n * A request to load the referenced resource and apply conditions in order to\n * finalize a conditional authorization response.\n *\n * @public\n */\nexport type ApplyConditionsRequestEntry = IdentifiedPermissionMessage<{\n resourceRef: string;\n resourceType: string;\n conditions: PermissionCriteria<PermissionCondition>;\n}>;\n\n/**\n * A batch of {@link ApplyConditionsRequestEntry} objects.\n *\n * @public\n */\nexport type ApplyConditionsRequest = {\n items: ApplyConditionsRequestEntry[];\n};\n\n/**\n * The result of applying the conditions, expressed as a definitive authorize\n * result of ALLOW or DENY.\n *\n * @public\n */\nexport type ApplyConditionsResponseEntry =\n IdentifiedPermissionMessage<DefinitivePolicyDecision>;\n\n/**\n * A batch of {@link ApplyConditionsResponseEntry} objects.\n *\n * @public\n */\nexport type ApplyConditionsResponse = {\n items: ApplyConditionsResponseEntry[];\n};\n\n/**\n * Serialized permission rules, with the paramsSchema\n * converted from a ZodSchema to a JsonSchema.\n *\n * @public\n * @deprecated Please import from `@backstage/plugin-permission-common` instead.\n */\nexport type MetadataResponseSerializedRule =\n CommonMetadataResponseSerializedRule;\n\n/**\n * Response type for the .metadata endpoint.\n *\n * @public\n * @deprecated Please import from `@backstage/plugin-permission-common` instead.\n */\nexport type MetadataResponse = CommonMetadataResponse;\n\nconst applyConditions = <TResourceType extends string, TResource>(\n criteria: PermissionCriteria<PermissionCondition<TResourceType>>,\n resource: TResource | undefined,\n getRule: (name: string) => PermissionRule<TResource, unknown, TResourceType>,\n): boolean => {\n // If resource was not found, deny. This avoids leaking information from the\n // apply-conditions API which would allow a user to differentiate between\n // non-existent resources and resources to which they do not have access.\n if (resource === undefined) {\n return false;\n }\n\n if (isAndCriteria(criteria)) {\n return criteria.allOf.every(child =>\n applyConditions(child, resource, getRule),\n );\n } else if (isOrCriteria(criteria)) {\n return criteria.anyOf.some(child =>\n applyConditions(child, resource, getRule),\n );\n } else if (isNotCriteria(criteria)) {\n return !applyConditions(criteria.not, resource, getRule);\n }\n\n const rule = getRule(criteria.rule);\n const result = rule.paramsSchema?.safeParse(criteria.params);\n\n if (result && !result.success) {\n throw new InputError(`Parameters to rule are invalid`, result.error);\n }\n\n return rule.apply(resource, criteria.params ?? {});\n};\n\n/**\n * Takes some permission conditions and returns a definitive authorization result\n * on the resource to which they apply.\n *\n * @public\n */\nexport function createConditionAuthorizer<TResource>(\n permissionRuleset: PermissionRuleset<TResource>,\n): (decision: PolicyDecision, resource: TResource | undefined) => boolean;\n/**\n * @public\n * @deprecated Use the version of `createConditionAuthorizer` that accepts a `PermissionRuleset` instead.\n */\nexport function createConditionAuthorizer<TResource, TQuery>(\n rules: PermissionRule<TResource, TQuery, string>[],\n): (decision: PolicyDecision, resource: TResource | undefined) => boolean;\nexport function createConditionAuthorizer<TResource, TQuery>(\n rules:\n | PermissionRule<TResource, TQuery, string>[]\n | PermissionRuleset<TResource>,\n): (decision: PolicyDecision, resource: TResource | undefined) => boolean {\n const getRule =\n 'getRuleByName' in rules\n ? (n: string) => rules.getRuleByName(n)\n : createGetRule(rules);\n\n return (\n decision: PolicyDecision,\n resource: TResource | undefined,\n ): boolean => {\n if (decision.result === AuthorizeResult.CONDITIONAL) {\n return applyConditions(decision.conditions, resource, getRule);\n }\n\n return decision.result === AuthorizeResult.ALLOW;\n };\n}\n\n/**\n * Options for creating a permission integration router specific\n * for a particular resource type.\n *\n * @public\n */\nexport type CreatePermissionIntegrationRouterResourceOptions<\n TResourceType extends string,\n TResource,\n> = {\n resourceType: TResourceType;\n permissions?: Array<Permission>;\n // Do not infer value of TResourceType from supplied rules.\n // instead only consider the resourceType parameter, and\n // consider any rules whose resource type does not match\n // to be an error.\n rules: PermissionRule<TResource, any, NoInfer<TResourceType>>[];\n getResources?: (\n resourceRefs: string[],\n ) => Promise<Array<TResource | undefined>>;\n};\n\n/**\n * Options for creating a permission integration router exposing\n * permissions and rules from multiple resource types.\n *\n * @public\n */\nexport type PermissionIntegrationRouterOptions<\n TResourceType1 extends string = string,\n TResource1 = any,\n TResourceType2 extends string = string,\n TResource2 = any,\n TResourceType3 extends string = string,\n TResource3 = any,\n> = {\n resources: Readonly<\n | [\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >,\n ]\n | [\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >,\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType2,\n TResource2\n >,\n ]\n | [\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >,\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType2,\n TResource2\n >,\n CreatePermissionIntegrationRouterResourceOptions<\n TResourceType3,\n TResource3\n >,\n ]\n >;\n};\n\nclass PermissionIntegrationMetadataStore {\n readonly #rulesByTypeByName = new Map<\n string,\n Map<string, PermissionRule<unknown, unknown, string>>\n >();\n readonly #permissionsByName = new Map<string, Permission>();\n readonly #resourcesByType = new Map<\n string,\n CreatePermissionIntegrationRouterResourceOptions<string, unknown>\n >();\n readonly #serializedRules = new Array<MetadataResponseSerializedRule>();\n\n getSerializedMetadata(): MetadataResponse {\n return {\n permissions: Array.from(this.#permissionsByName.values()),\n rules: this.#serializedRules,\n };\n }\n\n hasResourceType(type: string): boolean {\n return this.#resourcesByType.has(type);\n }\n\n async getResources(\n resourceType: string,\n refs: string[],\n ): Promise<Record<string, unknown>> {\n const resource = this.#resourcesByType.get(resourceType);\n if (!resource?.getResources) {\n throw new NotImplementedError(\n `This plugin does not expose any permission rule or can't evaluate the conditions request for ${resourceType}`,\n );\n }\n\n const uniqueRefs = Array.from(new Set(refs));\n const resources = await resource.getResources(uniqueRefs);\n return Object.fromEntries(\n uniqueRefs.map((ref, index) => [ref, resources[index]]),\n );\n }\n\n getRuleMapper(resourceType: string) {\n return (name: string): PermissionRule<unknown, unknown, string> => {\n const rule = this.#rulesByTypeByName.get(resourceType)?.get(name);\n if (!rule) {\n throw new Error(\n `Permission rule '${name}' does not exist for resource type '${resourceType}'`,\n );\n }\n return rule;\n };\n }\n\n addPermissions(permissions: Permission[]) {\n for (const permission of permissions) {\n // Permission naming conflicts are silently ignored\n this.#permissionsByName.set(permission.name, permission);\n }\n }\n\n addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]) {\n for (const rule of rules) {\n const rulesByName =\n this.#rulesByTypeByName.get(rule.resourceType) ?? new Map();\n this.#rulesByTypeByName.set(rule.resourceType, rulesByName);\n\n if (rulesByName.has(rule.name)) {\n throw new Error(\n `Refused to add permission rule for type '${rule.resourceType}' with name '${rule.name}' because it already exists`,\n );\n }\n rulesByName.set(rule.name, rule);\n\n this.#serializedRules.push({\n name: rule.name,\n description: rule.description,\n resourceType: rule.resourceType,\n paramsSchema: zodToJsonSchema(rule.paramsSchema ?? z.object({})),\n });\n }\n }\n\n addResourceType(\n resource: CreatePermissionIntegrationRouterResourceOptions<string, unknown>,\n ) {\n const { resourceType } = resource;\n\n if (this.#resourcesByType.has(resourceType)) {\n throw new Error(\n `Refused to add permission resource with type '${resourceType}' because it already exists`,\n );\n }\n this.#resourcesByType.set(resourceType, resource);\n\n if (resource.rules) {\n this.addPermissionRules(resource.rules);\n }\n\n if (resource.permissions) {\n this.addPermissions(resource.permissions);\n }\n }\n}\n\n/**\n * Create an express Router which provides an authorization route to allow\n * integration between the permission backend and other Backstage backend\n * plugins. Plugin owners that wish to support conditional authorization for\n * their resources should add the router created by this function to their\n * express app inside their `createRouter` implementation.\n *\n * In case the `permissions` option is provided, the router also\n * provides a route that exposes permissions and routes of a plugin.\n *\n * In case resources is provided, the routes can handle permissions\n * for multiple resource types.\n *\n * @remarks\n *\n * To make this concrete, we can use the Backstage software catalog as an\n * example. The catalog has conditional rules around access to specific\n * _entities_ in the catalog. The _type_ of resource is captured here as\n * `resourceType`, a string identifier (`catalog-entity` in this example) that\n * can be provided with permission definitions. This is merely a _type_ to\n * verify that conditions in an authorization policy are constructed correctly,\n * not a reference to a specific resource.\n *\n * The `rules` parameter is an array of {@link PermissionRule}s that introduce\n * conditional filtering logic for resources; for the catalog, these are things\n * like `isEntityOwner` or `hasAnnotation`. Rules describe how to filter a list\n * of resources, and the `conditions` returned allow these rules to be applied\n * with specific parameters (such as 'group:default/team-a', or\n * 'backstage.io/edit-url').\n *\n * The `getResources` argument should load resources based on a reference\n * identifier. For the catalog, this is an\n * {@link @backstage/catalog-model#EntityRef}. For other plugins, this can be\n * any serialized format. This is used to construct the\n * `createPermissionIntegrationRouter`, a function to add an authorization route\n * to your backend plugin. This function will be called by the\n * `permission-backend` when authorization conditions relating to this plugin\n * need to be evaluated.\n *\n * @public\n */\nexport function createPermissionIntegrationRouter<\n TResourceType1 extends string,\n TResource1,\n TResourceType2 extends string,\n TResource2,\n TResourceType3 extends string,\n TResource3,\n>(\n options?:\n | { permissions: Array<Permission> }\n | CreatePermissionIntegrationRouterResourceOptions<\n TResourceType1,\n TResource1\n >\n | PermissionIntegrationRouterOptions<\n TResourceType1,\n TResource1,\n TResourceType2,\n TResource2,\n TResourceType3,\n TResource3\n >,\n): express.Router & {\n addPermissions(permissions: Permission[]): void;\n addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]): void;\n addResourceType<const TResourceType extends string, TResource>(\n resource: CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n ): void;\n getPermissionRuleset<TResource, TQuery, TResourceType extends string>(\n resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>,\n ): PermissionRuleset<TResource, TQuery, TResourceType>;\n} {\n const store = new PermissionIntegrationMetadataStore();\n\n if (options) {\n if ('resources' in options) {\n // Not technically allowed by types, but it's historically been covered by tests\n if ('permissions' in options) {\n store.addPermissions(options.permissions as Permission[]);\n }\n\n for (const resource of options.resources) {\n store.addResourceType(resource);\n }\n } else if ('resourceType' in options) {\n store.addResourceType(options);\n } else {\n store.addPermissions(options.permissions);\n }\n }\n\n const router = Router();\n\n router.use('/.well-known/backstage/permissions/', express.json());\n\n router.get('/.well-known/backstage/permissions/metadata', (_, res) => {\n res.json(store.getSerializedMetadata());\n });\n\n router.post(\n '/.well-known/backstage/permissions/apply-conditions',\n async (req, res: Response<ApplyConditionsResponse | string>) => {\n const parseResult = applyConditionsRequestSchema.safeParse(req.body);\n if (!parseResult.success) {\n throw new InputError(parseResult.error.toString());\n }\n\n const { items: requests } = parseResult.data;\n\n const invalidResourceTypes = requests.filter(\n i => !store.hasResourceType(i.resourceType),\n );\n if (invalidResourceTypes.length) {\n throw new InputError(\n `Unexpected resource types: ${invalidResourceTypes\n .map(i => i.resourceType)\n .join(', ')}.`,\n );\n }\n\n const resourcesByType: Record<string, Record<string, any>> = {};\n for (const requestedType of new Set(requests.map(i => i.resourceType))) {\n resourcesByType[requestedType] = await store.getResources(\n requestedType,\n requests\n .filter(r => r.resourceType === requestedType)\n .map(i => i.resourceRef),\n );\n }\n\n res.json({\n items: requests.map(request => ({\n id: request.id,\n result: applyConditions(\n request.conditions,\n resourcesByType[request.resourceType][request.resourceRef],\n store.getRuleMapper(request.resourceType),\n )\n ? AuthorizeResult.ALLOW\n : AuthorizeResult.DENY,\n })),\n });\n },\n );\n\n return Object.assign(router, {\n addPermissions(permissions: Permission[]) {\n store.addPermissions(permissions);\n },\n addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]) {\n store.addPermissionRules(rules);\n },\n addResourceType<const TResourceType extends string, TResource>(\n resource: CreatePermissionIntegrationRouterResourceOptions<\n TResourceType,\n TResource\n >,\n ) {\n store.addResourceType(resource);\n },\n getPermissionRuleset<TResource, TQuery, TResourceType extends string>(\n resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>,\n ): PermissionRuleset<TResource, TQuery, TResourceType> {\n return {\n getRuleByName: store.getRuleMapper(resourceRef.resourceType),\n } as PermissionRuleset<TResource, TQuery, TResourceType>;\n },\n });\n}\n"],"names":["z","isAndCriteria","isOrCriteria","isNotCriteria","InputError","createGetRule","AuthorizeResult","NotImplementedError","zodToJsonSchema","Router","express"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function createPermissionResourceRef() {
|
|
4
|
+
return {
|
|
5
|
+
with(options) {
|
|
6
|
+
return {
|
|
7
|
+
$$type: "@backstage/PermissionResourceRef",
|
|
8
|
+
pluginId: options.pluginId,
|
|
9
|
+
resourceType: options.resourceType,
|
|
10
|
+
TQuery: null,
|
|
11
|
+
TResource: null
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
exports.createPermissionResourceRef = createPermissionResourceRef;
|
|
18
|
+
//# sourceMappingURL=createPermissionResourceRef.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createPermissionResourceRef.cjs.js","sources":["../../src/integration/createPermissionResourceRef.ts"],"sourcesContent":["/*\n * Copyright 2025 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\n/**\n * @public\n */\nexport type PermissionResourceRef<\n TResource = unknown,\n TQuery = unknown,\n TResourceType extends string = string,\n TPluginId extends string = string,\n> = {\n readonly $$type: '@backstage/PermissionResourceRef';\n readonly pluginId: TPluginId;\n readonly resourceType: TResourceType;\n readonly TQuery: TQuery;\n readonly TResource: TResource;\n};\n\n/**\n * @public\n */\nexport function createPermissionResourceRef<TResource, TQuery>(): {\n with<TPluginId extends string, TResourceType extends string>(options: {\n pluginId: TPluginId;\n resourceType: TResourceType;\n }): PermissionResourceRef<TResource, TQuery, TResourceType, TPluginId>;\n} {\n return {\n with<TPluginId extends string, TResourceType extends string>(options: {\n pluginId: TPluginId;\n resourceType: TResourceType;\n }): PermissionResourceRef<TResource, TQuery, TResourceType, TPluginId> {\n return {\n $$type: '@backstage/PermissionResourceRef',\n pluginId: options.pluginId,\n resourceType: options.resourceType,\n TQuery: null as TQuery,\n TResource: null as TResource,\n };\n },\n };\n}\n"],"names":[],"mappings":";;AAmCO,SAAS,2BAKd,GAAA;AACA,EAAO,OAAA;AAAA,IACL,KAA6D,OAGU,EAAA;AACrE,MAAO,OAAA;AAAA,QACL,MAAQ,EAAA,kCAAA;AAAA,QACR,UAAU,OAAQ,CAAA,QAAA;AAAA,QAClB,cAAc,OAAQ,CAAA,YAAA;AAAA,QACtB,MAAQ,EAAA,IAAA;AAAA,QACR,SAAW,EAAA;AAAA,OACb;AAAA;AACF,GACF;AACF;;;;"}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
function createPermissionRule(rule) {
|
|
4
|
+
if ("resourceRef" in rule) {
|
|
5
|
+
return { ...rule, resourceType: rule.resourceRef.resourceType };
|
|
6
|
+
}
|
|
7
|
+
return rule;
|
|
8
|
+
}
|
|
4
9
|
const makeCreatePermissionRule = () => (rule) => createPermissionRule(rule);
|
|
5
10
|
|
|
6
11
|
exports.createPermissionRule = createPermissionRule;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createPermissionRule.cjs.js","sources":["../../src/integration/createPermissionRule.ts"],"sourcesContent":["/*\n * Copyright 2022 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 {
|
|
1
|
+
{"version":3,"file":"createPermissionRule.cjs.js","sources":["../../src/integration/createPermissionRule.ts"],"sourcesContent":["/*\n * Copyright 2022 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 PermissionCriteria,\n PermissionRuleParams,\n} from '@backstage/plugin-permission-common';\nimport { PermissionRule } from '../types';\nimport { z } from 'zod';\nimport { PermissionResourceRef } from './createPermissionResourceRef';\nimport { NoInfer } from './util';\n\n/**\n * @public\n */\nexport type CreatePermissionRuleOptions<\n TResource,\n TQuery,\n TQueryOutput extends TQuery,\n TResourceType extends string,\n TParams extends PermissionRuleParams,\n> = {\n name: string;\n description: string;\n\n resourceRef: PermissionResourceRef<TResource, TQuery, TResourceType>;\n\n /**\n * A ZodSchema that reflects the structure of the parameters that are passed to\n */\n paramsSchema?: z.ZodSchema<TParams>;\n\n /**\n * Apply this rule to a resource already loaded from a backing data source. The params are\n * arguments supplied for the rule; for example, a rule could be `isOwner` with entityRefs as the\n * params.\n */\n apply(resource: TResource, params: NoInfer<TParams>): boolean;\n\n /**\n * Translate this rule to criteria suitable for use in querying a backing data store. The criteria\n * can be used for loading a collection of resources efficiently with conditional criteria already\n * applied.\n */\n toQuery(params: NoInfer<TParams>): PermissionCriteria<TQueryOutput>;\n};\n\n/**\n * Helper function to create a {@link PermissionRule} for a specific resource type using a {@link PermissionResourceRef}.\n *\n * @public\n */\nexport function createPermissionRule<\n TResource,\n TQuery,\n TQueryOutput extends TQuery,\n TResourceType extends string,\n TParams extends PermissionRuleParams = undefined,\n>(\n rule: CreatePermissionRuleOptions<\n TResource,\n TQuery,\n TQueryOutput,\n TResourceType,\n TParams\n >,\n): PermissionRule<TResource, TQuery, TResourceType, TParams>;\n/**\n * Helper function to ensure that {@link PermissionRule} definitions are typed correctly.\n *\n * @deprecated Use the version of `createPermissionRule` that accepts a `resourceRef` option instead.\n * @public\n */\nexport function createPermissionRule<\n TResource,\n TQuery,\n TResourceType extends string,\n TParams extends PermissionRuleParams = undefined,\n>(\n rule: PermissionRule<TResource, TQuery, TResourceType, TParams>,\n): PermissionRule<TResource, TQuery, TResourceType, TParams>;\nexport function createPermissionRule<\n TResource,\n TQuery,\n TQueryOutput extends TQuery,\n TResourceType extends string,\n TParams extends PermissionRuleParams = undefined,\n>(\n rule:\n | PermissionRule<TResource, TQuery, TResourceType, TParams>\n | CreatePermissionRuleOptions<\n TResource,\n TQuery,\n TQueryOutput,\n TResourceType,\n TParams\n >,\n): PermissionRule<TResource, TQuery, TResourceType, TParams> {\n if ('resourceRef' in rule) {\n return { ...rule, resourceType: rule.resourceRef.resourceType };\n }\n return rule;\n}\n\n/**\n * Helper for making plugin-specific createPermissionRule functions, that have\n * the TResource and TQuery type parameters populated but infer the params from\n * the supplied rule. This helps ensure that rules created for this plugin use\n * consistent types for the resource and query.\n *\n * @public\n * @deprecated Use {@link (createPermissionRule:1)} directly instead with the resourceRef option.\n */\nexport const makeCreatePermissionRule =\n <TResource, TQuery, TResourceType extends string>() =>\n <TParams extends PermissionRuleParams = undefined>(\n rule: PermissionRule<TResource, TQuery, TResourceType, TParams>,\n ) =>\n createPermissionRule(rule);\n"],"names":[],"mappings":";;AA8FO,SAAS,qBAOd,IAS2D,EAAA;AAC3D,EAAA,IAAI,iBAAiB,IAAM,EAAA;AACzB,IAAA,OAAO,EAAE,GAAG,IAAA,EAAM,YAAc,EAAA,IAAA,CAAK,YAAY,YAAa,EAAA;AAAA;AAEhE,EAAO,OAAA,IAAA;AACT;AAWO,MAAM,wBACX,GAAA,MACA,CACE,IAAA,KAEA,qBAAqB,IAAI;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-permission-node",
|
|
3
|
-
"version": "0.8.8-next.
|
|
3
|
+
"version": "0.8.8-next.2",
|
|
4
4
|
"description": "Common permission and authorization utilities for backend plugins",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library",
|
|
@@ -65,10 +65,10 @@
|
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"@backstage/backend-common": "^0.25.0",
|
|
68
|
-
"@backstage/backend-plugin-api": "1.2.0-next.
|
|
68
|
+
"@backstage/backend-plugin-api": "1.2.0-next.2",
|
|
69
69
|
"@backstage/config": "1.3.2",
|
|
70
70
|
"@backstage/errors": "1.2.7",
|
|
71
|
-
"@backstage/plugin-auth-node": "0.
|
|
71
|
+
"@backstage/plugin-auth-node": "0.6.0-next.2",
|
|
72
72
|
"@backstage/plugin-permission-common": "0.8.4",
|
|
73
73
|
"@types/express": "^4.17.6",
|
|
74
74
|
"express": "^4.17.1",
|
|
@@ -77,9 +77,9 @@
|
|
|
77
77
|
"zod-to-json-schema": "^3.20.4"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
|
-
"@backstage/backend-defaults": "0.8.0-next.
|
|
81
|
-
"@backstage/backend-test-utils": "1.3.0-next.
|
|
82
|
-
"@backstage/cli": "0.30.0-next.
|
|
80
|
+
"@backstage/backend-defaults": "0.8.0-next.3",
|
|
81
|
+
"@backstage/backend-test-utils": "1.3.0-next.3",
|
|
82
|
+
"@backstage/cli": "0.30.0-next.3",
|
|
83
83
|
"@types/supertest": "^2.0.8",
|
|
84
84
|
"msw": "^1.0.0",
|
|
85
85
|
"supertest": "^7.0.0"
|