@backstage/plugin-permission-common 0.7.13 → 0.7.14

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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # @backstage/plugin-permission-common
2
2
 
3
+ ## 0.7.14
4
+
5
+ ### Patch Changes
6
+
7
+ - d44a20a: Added additional plugin metadata to `package.json`.
8
+ - Updated dependencies
9
+ - @backstage/config@1.2.0
10
+ - @backstage/errors@1.2.4
11
+ - @backstage/types@1.1.1
12
+
13
+ ## 0.7.14-next.0
14
+
15
+ ### Patch Changes
16
+
17
+ - d44a20a: Added additional plugin metadata to `package.json`.
18
+ - Updated dependencies
19
+ - @backstage/config@1.2.0
20
+ - @backstage/errors@1.2.4
21
+ - @backstage/types@1.1.1
22
+
3
23
  ## 0.7.13
4
24
 
5
25
  ### Patch Changes
@@ -0,0 +1,105 @@
1
+ import { ResponseError } from '@backstage/errors';
2
+ import fetch from 'cross-fetch';
3
+ import * as uuid from 'uuid';
4
+ import { z } from 'zod';
5
+ import { AuthorizeResult } from './types/api.esm.js';
6
+
7
+ const permissionCriteriaSchema = z.lazy(
8
+ () => z.object({
9
+ rule: z.string(),
10
+ resourceType: z.string(),
11
+ params: z.record(z.any()).optional()
12
+ }).or(z.object({ anyOf: z.array(permissionCriteriaSchema).nonempty() })).or(z.object({ allOf: z.array(permissionCriteriaSchema).nonempty() })).or(z.object({ not: permissionCriteriaSchema }))
13
+ );
14
+ const authorizePermissionResponseSchema = z.object({
15
+ result: z.literal(AuthorizeResult.ALLOW).or(z.literal(AuthorizeResult.DENY))
16
+ });
17
+ const queryPermissionResponseSchema = z.union([
18
+ z.object({
19
+ result: z.literal(AuthorizeResult.ALLOW).or(z.literal(AuthorizeResult.DENY))
20
+ }),
21
+ z.object({
22
+ result: z.literal(AuthorizeResult.CONDITIONAL),
23
+ pluginId: z.string(),
24
+ resourceType: z.string(),
25
+ conditions: permissionCriteriaSchema
26
+ })
27
+ ]);
28
+ const responseSchema = (itemSchema, ids) => z.object({
29
+ items: z.array(
30
+ z.intersection(
31
+ z.object({
32
+ id: z.string()
33
+ }),
34
+ itemSchema
35
+ )
36
+ ).refine(
37
+ (items) => items.length === ids.size && items.every(({ id }) => ids.has(id)),
38
+ {
39
+ message: "Items in response do not match request"
40
+ }
41
+ )
42
+ });
43
+ class PermissionClient {
44
+ enabled;
45
+ discovery;
46
+ constructor(options) {
47
+ this.discovery = options.discovery;
48
+ this.enabled = options.config.getOptionalBoolean("permission.enabled") ?? false;
49
+ }
50
+ /**
51
+ * {@inheritdoc PermissionEvaluator.authorize}
52
+ */
53
+ async authorize(requests, options) {
54
+ return this.makeRequest(
55
+ requests,
56
+ authorizePermissionResponseSchema,
57
+ options
58
+ );
59
+ }
60
+ /**
61
+ * {@inheritdoc PermissionEvaluator.authorizeConditional}
62
+ */
63
+ async authorizeConditional(queries, options) {
64
+ return this.makeRequest(queries, queryPermissionResponseSchema, options);
65
+ }
66
+ async makeRequest(queries, itemSchema, options) {
67
+ if (!this.enabled) {
68
+ return queries.map((_) => ({ result: AuthorizeResult.ALLOW }));
69
+ }
70
+ const request = {
71
+ items: queries.map((query) => ({
72
+ id: uuid.v4(),
73
+ ...query
74
+ }))
75
+ };
76
+ const permissionApi = await this.discovery.getBaseUrl("permission");
77
+ const response = await fetch(`${permissionApi}/authorize`, {
78
+ method: "POST",
79
+ body: JSON.stringify(request),
80
+ headers: {
81
+ ...this.getAuthorizationHeader(options?.token),
82
+ "content-type": "application/json"
83
+ }
84
+ });
85
+ if (!response.ok) {
86
+ throw await ResponseError.fromResponse(response);
87
+ }
88
+ const responseBody = await response.json();
89
+ const parsedResponse = responseSchema(
90
+ itemSchema,
91
+ new Set(request.items.map(({ id }) => id))
92
+ ).parse(responseBody);
93
+ const responsesById = parsedResponse.items.reduce((acc, r) => {
94
+ acc[r.id] = r;
95
+ return acc;
96
+ }, {});
97
+ return request.items.map((query) => responsesById[query.id]);
98
+ }
99
+ getAuthorizationHeader(token) {
100
+ return token ? { Authorization: `Bearer ${token}` } : {};
101
+ }
102
+ }
103
+
104
+ export { PermissionClient };
105
+ //# sourceMappingURL=PermissionClient.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PermissionClient.esm.js","sources":["../src/PermissionClient.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 { Config } from '@backstage/config';\nimport { ResponseError } from '@backstage/errors';\nimport fetch from 'cross-fetch';\nimport * as uuid from 'uuid';\nimport { z } from 'zod';\nimport {\n AuthorizeResult,\n PermissionMessageBatch,\n PermissionCriteria,\n PermissionCondition,\n PermissionEvaluator,\n QueryPermissionRequest,\n AuthorizePermissionRequest,\n EvaluatorRequestOptions,\n AuthorizePermissionResponse,\n QueryPermissionResponse,\n} from './types/api';\nimport { DiscoveryApi } from './types/discovery';\nimport { AuthorizeRequestOptions } from './types/permission';\n\nconst permissionCriteriaSchema: z.ZodSchema<\n PermissionCriteria<PermissionCondition>\n> = z.lazy(() =>\n z\n .object({\n rule: z.string(),\n resourceType: z.string(),\n params: z.record(z.any()).optional(),\n })\n .or(z.object({ anyOf: z.array(permissionCriteriaSchema).nonempty() }))\n .or(z.object({ allOf: z.array(permissionCriteriaSchema).nonempty() }))\n .or(z.object({ not: permissionCriteriaSchema })),\n);\n\nconst authorizePermissionResponseSchema: z.ZodSchema<AuthorizePermissionResponse> =\n z.object({\n result: z\n .literal(AuthorizeResult.ALLOW)\n .or(z.literal(AuthorizeResult.DENY)),\n });\n\nconst queryPermissionResponseSchema: z.ZodSchema<QueryPermissionResponse> =\n z.union([\n z.object({\n result: z\n .literal(AuthorizeResult.ALLOW)\n .or(z.literal(AuthorizeResult.DENY)),\n }),\n z.object({\n result: z.literal(AuthorizeResult.CONDITIONAL),\n pluginId: z.string(),\n resourceType: z.string(),\n conditions: permissionCriteriaSchema,\n }),\n ]);\n\nconst responseSchema = <T>(\n itemSchema: z.ZodSchema<T>,\n ids: Set<string>,\n): z.ZodSchema<PermissionMessageBatch<T>> =>\n z.object({\n items: z\n .array(\n z.intersection(\n z.object({\n id: z.string(),\n }),\n itemSchema,\n ),\n )\n .refine(\n items =>\n items.length === ids.size && items.every(({ id }) => ids.has(id)),\n {\n message: 'Items in response do not match request',\n },\n ),\n });\n\n/**\n * An isomorphic client for requesting authorization for Backstage permissions.\n * @public\n */\nexport class PermissionClient implements PermissionEvaluator {\n private readonly enabled: boolean;\n private readonly discovery: DiscoveryApi;\n\n constructor(options: { discovery: DiscoveryApi; config: Config }) {\n this.discovery = options.discovery;\n this.enabled =\n options.config.getOptionalBoolean('permission.enabled') ?? false;\n }\n\n /**\n * {@inheritdoc PermissionEvaluator.authorize}\n */\n async authorize(\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]> {\n return this.makeRequest(\n requests,\n authorizePermissionResponseSchema,\n options,\n );\n }\n\n /**\n * {@inheritdoc PermissionEvaluator.authorizeConditional}\n */\n async authorizeConditional(\n queries: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<QueryPermissionResponse[]> {\n return this.makeRequest(queries, queryPermissionResponseSchema, options);\n }\n\n private async makeRequest<TQuery, TResult>(\n queries: TQuery[],\n itemSchema: z.ZodSchema<TResult>,\n options?: AuthorizeRequestOptions,\n ) {\n if (!this.enabled) {\n return queries.map(_ => ({ result: AuthorizeResult.ALLOW as const }));\n }\n\n const request: PermissionMessageBatch<TQuery> = {\n items: queries.map(query => ({\n id: uuid.v4(),\n ...query,\n })),\n };\n\n const permissionApi = await this.discovery.getBaseUrl('permission');\n const response = await fetch(`${permissionApi}/authorize`, {\n method: 'POST',\n body: JSON.stringify(request),\n headers: {\n ...this.getAuthorizationHeader(options?.token),\n 'content-type': 'application/json',\n },\n });\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n const responseBody = await response.json();\n\n const parsedResponse = responseSchema(\n itemSchema,\n new Set(request.items.map(({ id }) => id)),\n ).parse(responseBody);\n\n const responsesById = parsedResponse.items.reduce((acc, r) => {\n acc[r.id] = r;\n return acc;\n }, {} as Record<string, z.infer<typeof itemSchema>>);\n\n return request.items.map(query => responsesById[query.id]);\n }\n\n private getAuthorizationHeader(token?: string): Record<string, string> {\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n}\n"],"names":[],"mappings":";;;;;;AAoCA,MAAM,2BAEF,CAAE,CAAA,IAAA;AAAA,EAAK,MACT,EACG,MAAO,CAAA;AAAA,IACN,IAAA,EAAM,EAAE,MAAO,EAAA;AAAA,IACf,YAAA,EAAc,EAAE,MAAO,EAAA;AAAA,IACvB,QAAQ,CAAE,CAAA,MAAA,CAAO,EAAE,GAAI,EAAC,EAAE,QAAS,EAAA;AAAA,GACpC,CACA,CAAA,EAAA,CAAG,CAAE,CAAA,MAAA,CAAO,EAAE,KAAO,EAAA,CAAA,CAAE,KAAM,CAAA,wBAAwB,EAAE,QAAS,EAAA,EAAG,CAAC,EACpE,EAAG,CAAA,CAAA,CAAE,MAAO,CAAA,EAAE,OAAO,CAAE,CAAA,KAAA,CAAM,wBAAwB,CAAA,CAAE,UAAW,EAAC,CAAC,CAAA,CACpE,GAAG,CAAE,CAAA,MAAA,CAAO,EAAE,GAAK,EAAA,wBAAA,EAA0B,CAAC,CAAA;AACnD,CAAA,CAAA;AAEA,MAAM,iCAAA,GACJ,EAAE,MAAO,CAAA;AAAA,EACP,MAAA,EAAQ,CACL,CAAA,OAAA,CAAQ,eAAgB,CAAA,KAAK,CAC7B,CAAA,EAAA,CAAG,CAAE,CAAA,OAAA,CAAQ,eAAgB,CAAA,IAAI,CAAC,CAAA;AACvC,CAAC,CAAA,CAAA;AAEH,MAAM,6BAAA,GACJ,EAAE,KAAM,CAAA;AAAA,EACN,EAAE,MAAO,CAAA;AAAA,IACP,MAAA,EAAQ,CACL,CAAA,OAAA,CAAQ,eAAgB,CAAA,KAAK,CAC7B,CAAA,EAAA,CAAG,CAAE,CAAA,OAAA,CAAQ,eAAgB,CAAA,IAAI,CAAC,CAAA;AAAA,GACtC,CAAA;AAAA,EACD,EAAE,MAAO,CAAA;AAAA,IACP,MAAQ,EAAA,CAAA,CAAE,OAAQ,CAAA,eAAA,CAAgB,WAAW,CAAA;AAAA,IAC7C,QAAA,EAAU,EAAE,MAAO,EAAA;AAAA,IACnB,YAAA,EAAc,EAAE,MAAO,EAAA;AAAA,IACvB,UAAY,EAAA,wBAAA;AAAA,GACb,CAAA;AACH,CAAC,CAAA,CAAA;AAEH,MAAM,cAAiB,GAAA,CACrB,UACA,EAAA,GAAA,KAEA,EAAE,MAAO,CAAA;AAAA,EACP,OAAO,CACJ,CAAA,KAAA;AAAA,IACC,CAAE,CAAA,YAAA;AAAA,MACA,EAAE,MAAO,CAAA;AAAA,QACP,EAAA,EAAI,EAAE,MAAO,EAAA;AAAA,OACd,CAAA;AAAA,MACD,UAAA;AAAA,KACF;AAAA,GAED,CAAA,MAAA;AAAA,IACC,CACE,KAAA,KAAA,KAAA,CAAM,MAAW,KAAA,GAAA,CAAI,QAAQ,KAAM,CAAA,KAAA,CAAM,CAAC,EAAE,EAAG,EAAA,KAAM,GAAI,CAAA,GAAA,CAAI,EAAE,CAAC,CAAA;AAAA,IAClE;AAAA,MACE,OAAS,EAAA,wCAAA;AAAA,KACX;AAAA,GACF;AACJ,CAAC,CAAA,CAAA;AAMI,MAAM,gBAAgD,CAAA;AAAA,EAC1C,OAAA,CAAA;AAAA,EACA,SAAA,CAAA;AAAA,EAEjB,YAAY,OAAsD,EAAA;AAChE,IAAA,IAAA,CAAK,YAAY,OAAQ,CAAA,SAAA,CAAA;AACzB,IAAA,IAAA,CAAK,OACH,GAAA,OAAA,CAAQ,MAAO,CAAA,kBAAA,CAAmB,oBAAoB,CAAK,IAAA,KAAA,CAAA;AAAA,GAC/D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SACJ,CAAA,QAAA,EACA,OACwC,EAAA;AACxC,IAAA,OAAO,IAAK,CAAA,WAAA;AAAA,MACV,QAAA;AAAA,MACA,iCAAA;AAAA,MACA,OAAA;AAAA,KACF,CAAA;AAAA,GACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBACJ,CAAA,OAAA,EACA,OACoC,EAAA;AACpC,IAAA,OAAO,IAAK,CAAA,WAAA,CAAY,OAAS,EAAA,6BAAA,EAA+B,OAAO,CAAA,CAAA;AAAA,GACzE;AAAA,EAEA,MAAc,WAAA,CACZ,OACA,EAAA,UAAA,EACA,OACA,EAAA;AACA,IAAI,IAAA,CAAC,KAAK,OAAS,EAAA;AACjB,MAAA,OAAO,QAAQ,GAAI,CAAA,CAAA,CAAA,MAAM,EAAE,MAAQ,EAAA,eAAA,CAAgB,OAAiB,CAAA,CAAA,CAAA;AAAA,KACtE;AAEA,IAAA,MAAM,OAA0C,GAAA;AAAA,MAC9C,KAAA,EAAO,OAAQ,CAAA,GAAA,CAAI,CAAU,KAAA,MAAA;AAAA,QAC3B,EAAA,EAAI,KAAK,EAAG,EAAA;AAAA,QACZ,GAAG,KAAA;AAAA,OACH,CAAA,CAAA;AAAA,KACJ,CAAA;AAEA,IAAA,MAAM,aAAgB,GAAA,MAAM,IAAK,CAAA,SAAA,CAAU,WAAW,YAAY,CAAA,CAAA;AAClE,IAAA,MAAM,QAAW,GAAA,MAAM,KAAM,CAAA,CAAA,EAAG,aAAa,CAAc,UAAA,CAAA,EAAA;AAAA,MACzD,MAAQ,EAAA,MAAA;AAAA,MACR,IAAA,EAAM,IAAK,CAAA,SAAA,CAAU,OAAO,CAAA;AAAA,MAC5B,OAAS,EAAA;AAAA,QACP,GAAG,IAAA,CAAK,sBAAuB,CAAA,OAAA,EAAS,KAAK,CAAA;AAAA,QAC7C,cAAgB,EAAA,kBAAA;AAAA,OAClB;AAAA,KACD,CAAA,CAAA;AACD,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,MAAM,aAAc,CAAA,YAAA,CAAa,QAAQ,CAAA,CAAA;AAAA,KACjD;AAEA,IAAM,MAAA,YAAA,GAAe,MAAM,QAAA,CAAS,IAAK,EAAA,CAAA;AAEzC,IAAA,MAAM,cAAiB,GAAA,cAAA;AAAA,MACrB,UAAA;AAAA,MACA,IAAI,GAAI,CAAA,OAAA,CAAQ,KAAM,CAAA,GAAA,CAAI,CAAC,EAAE,EAAA,EAAS,KAAA,EAAE,CAAC,CAAA;AAAA,KAC3C,CAAE,MAAM,YAAY,CAAA,CAAA;AAEpB,IAAA,MAAM,gBAAgB,cAAe,CAAA,KAAA,CAAM,MAAO,CAAA,CAAC,KAAK,CAAM,KAAA;AAC5D,MAAI,GAAA,CAAA,CAAA,CAAE,EAAE,CAAI,GAAA,CAAA,CAAA;AACZ,MAAO,OAAA,GAAA,CAAA;AAAA,KACT,EAAG,EAAgD,CAAA,CAAA;AAEnD,IAAA,OAAO,QAAQ,KAAM,CAAA,GAAA,CAAI,WAAS,aAAc,CAAA,KAAA,CAAM,EAAE,CAAC,CAAA,CAAA;AAAA,GAC3D;AAAA,EAEQ,uBAAuB,KAAwC,EAAA;AACrE,IAAA,OAAO,QAAQ,EAAE,aAAA,EAAe,UAAU,KAAK,CAAA,CAAA,KAAO,EAAC,CAAA;AAAA,GACzD;AACF;;;;"}
package/dist/index.cjs.js CHANGED
@@ -1,16 +1,14 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var errors = require('@backstage/errors');
6
4
  var fetch = require('cross-fetch');
7
5
  var uuid = require('uuid');
8
6
  var zod = require('zod');
9
7
 
10
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
11
9
 
12
- function _interopNamespace(e) {
13
- if (e && e.__esModule) return e;
10
+ function _interopNamespaceCompat(e) {
11
+ if (e && typeof e === 'object' && 'default' in e) return e;
14
12
  var n = Object.create(null);
15
13
  if (e) {
16
14
  Object.keys(e).forEach(function (k) {
@@ -23,12 +21,12 @@ function _interopNamespace(e) {
23
21
  }
24
22
  });
25
23
  }
26
- n["default"] = e;
24
+ n.default = e;
27
25
  return Object.freeze(n);
28
26
  }
29
27
 
30
- var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
31
- var uuid__namespace = /*#__PURE__*/_interopNamespace(uuid);
28
+ var fetch__default = /*#__PURE__*/_interopDefaultCompat(fetch);
29
+ var uuid__namespace = /*#__PURE__*/_interopNamespaceCompat(uuid);
32
30
 
33
31
  var AuthorizeResult = /* @__PURE__ */ ((AuthorizeResult2) => {
34
32
  AuthorizeResult2["DENY"] = "DENY";
@@ -91,12 +89,6 @@ function createPermission({
91
89
  };
92
90
  }
93
91
 
94
- var __defProp = Object.defineProperty;
95
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
96
- var __publicField = (obj, key, value) => {
97
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
98
- return value;
99
- };
100
92
  const permissionCriteriaSchema = zod.z.lazy(
101
93
  () => zod.z.object({
102
94
  rule: zod.z.string(),
@@ -134,12 +126,11 @@ const responseSchema = (itemSchema, ids) => zod.z.object({
134
126
  )
135
127
  });
136
128
  class PermissionClient {
129
+ enabled;
130
+ discovery;
137
131
  constructor(options) {
138
- __publicField(this, "enabled");
139
- __publicField(this, "discovery");
140
- var _a;
141
132
  this.discovery = options.discovery;
142
- this.enabled = (_a = options.config.getOptionalBoolean("permission.enabled")) != null ? _a : false;
133
+ this.enabled = options.config.getOptionalBoolean("permission.enabled") ?? false;
143
134
  }
144
135
  /**
145
136
  * {@inheritdoc PermissionEvaluator.authorize}
@@ -168,11 +159,11 @@ class PermissionClient {
168
159
  }))
169
160
  };
170
161
  const permissionApi = await this.discovery.getBaseUrl("permission");
171
- const response = await fetch__default["default"](`${permissionApi}/authorize`, {
162
+ const response = await fetch__default.default(`${permissionApi}/authorize`, {
172
163
  method: "POST",
173
164
  body: JSON.stringify(request),
174
165
  headers: {
175
- ...this.getAuthorizationHeader(options == null ? void 0 : options.token),
166
+ ...this.getAuthorizationHeader(options?.token),
176
167
  "content-type": "application/json"
177
168
  }
178
169
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/types/api.ts","../src/permissions/util.ts","../src/permissions/createPermission.ts","../src/PermissionClient.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 { JsonPrimitive } from '@backstage/types';\nimport { Permission, ResourcePermission } from './permission';\n\n/**\n * A request with a UUID identifier, so that batched responses can be matched up with the original\n * requests.\n * @public\n */\nexport type IdentifiedPermissionMessage<T> = T & { id: string };\n\n/**\n * A batch of request or response items.\n * @public\n */\nexport type PermissionMessageBatch<T> = {\n items: IdentifiedPermissionMessage<T>[];\n};\n\n/**\n * The result of an authorization request.\n * @public\n */\nexport enum AuthorizeResult {\n /**\n * The authorization request is denied.\n */\n DENY = 'DENY',\n /**\n * The authorization request is allowed.\n */\n ALLOW = 'ALLOW',\n /**\n * The authorization request is allowed if the provided conditions are met.\n */\n CONDITIONAL = 'CONDITIONAL',\n}\n\n/**\n * A definitive decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.\n *\n * @remarks\n *\n * This indicates that the policy unconditionally allows (or denies) the request.\n *\n * @public\n */\nexport type DefinitivePolicyDecision = {\n result: AuthorizeResult.ALLOW | AuthorizeResult.DENY;\n};\n\n/**\n * A conditional decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.\n *\n * @remarks\n *\n * This indicates that the policy allows authorization for the request, given that the returned\n * conditions hold when evaluated. The conditions will be evaluated by the corresponding plugin\n * which knows about the referenced permission rules.\n *\n * @public\n */\nexport type ConditionalPolicyDecision = {\n result: AuthorizeResult.CONDITIONAL;\n pluginId: string;\n resourceType: string;\n conditions: PermissionCriteria<PermissionCondition>;\n};\n\n/**\n * A decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.\n *\n * @public\n */\nexport type PolicyDecision =\n | DefinitivePolicyDecision\n | ConditionalPolicyDecision;\n\n/**\n * A condition returned with a CONDITIONAL authorization response.\n *\n * Conditions are a reference to a rule defined by a plugin, and parameters to apply the rule. For\n * example, a rule might be `isOwner` from the catalog-backend, and params may be a list of entity\n * claims from a identity token.\n * @public\n */\nexport type PermissionCondition<\n TResourceType extends string = string,\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = {\n resourceType: TResourceType;\n rule: string;\n params?: TParams;\n};\n\n/**\n * Utility type to represent an array with 1 or more elements.\n * @ignore\n */\ntype NonEmptyArray<T> = [T, ...T[]];\n\n/**\n * Represents a logical AND for the provided criteria.\n * @public\n */\nexport type AllOfCriteria<TQuery> = {\n allOf: NonEmptyArray<PermissionCriteria<TQuery>>;\n};\n\n/**\n * Represents a logical OR for the provided criteria.\n * @public\n */\nexport type AnyOfCriteria<TQuery> = {\n anyOf: NonEmptyArray<PermissionCriteria<TQuery>>;\n};\n\n/**\n * Represents a negation of the provided criteria.\n * @public\n */\nexport type NotCriteria<TQuery> = {\n not: PermissionCriteria<TQuery>;\n};\n\n/**\n * Composes several {@link PermissionCondition}s as criteria with a nested AND/OR structure.\n * @public\n */\nexport type PermissionCriteria<TQuery> =\n | AllOfCriteria<TQuery>\n | AnyOfCriteria<TQuery>\n | NotCriteria<TQuery>\n | TQuery;\n\n/**\n * A parameter to a permission rule.\n *\n * @public\n */\nexport type PermissionRuleParam = undefined | JsonPrimitive | JsonPrimitive[];\n\n/**\n * Types that can be used as parameters to permission rules.\n *\n * @public\n */\nexport type PermissionRuleParams =\n | undefined\n | Record<string, PermissionRuleParam>;\n\n/**\n * An individual request sent to the permission backend.\n * @public\n */\nexport type EvaluatePermissionRequest = {\n permission: Permission;\n resourceRef?: string;\n};\n\n/**\n * A batch of requests sent to the permission backend.\n * @public\n */\nexport type EvaluatePermissionRequestBatch =\n PermissionMessageBatch<EvaluatePermissionRequest>;\n\n/**\n * An individual response from the permission backend.\n *\n * @remarks\n *\n * This response type is an alias of {@link PolicyDecision} to maintain separation between the\n * {@link @backstage/plugin-permission-node#PermissionPolicy} interface and the permission backend\n * api. They may diverge at some point in the future. The response\n *\n * @public\n */\nexport type EvaluatePermissionResponse = PolicyDecision;\n\n/**\n * A batch of responses from the permission backend.\n * @public\n */\nexport type EvaluatePermissionResponseBatch =\n PermissionMessageBatch<EvaluatePermissionResponse>;\n\n/**\n * Request object for {@link PermissionEvaluator.authorize}. If a {@link ResourcePermission}\n * is provided, it must include a corresponding `resourceRef`.\n * @public\n */\nexport type AuthorizePermissionRequest =\n | {\n permission: Exclude<Permission, ResourcePermission>;\n resourceRef?: never;\n }\n | { permission: ResourcePermission; resourceRef: string };\n\n/**\n * Response object for {@link PermissionEvaluator.authorize}.\n * @public\n */\nexport type AuthorizePermissionResponse = DefinitivePolicyDecision;\n\n/**\n * Request object for {@link PermissionEvaluator.authorizeConditional}.\n * @public\n */\nexport type QueryPermissionRequest = {\n permission: ResourcePermission;\n resourceRef?: never;\n};\n\n/**\n * Response object for {@link PermissionEvaluator.authorizeConditional}.\n * @public\n */\nexport type QueryPermissionResponse = PolicyDecision;\n\n/**\n * A client interacting with the permission backend can implement this evaluator interface.\n *\n * @public\n */\nexport interface PermissionEvaluator {\n /**\n * Evaluates {@link Permission | Permissions} and returns a definitive decision.\n */\n authorize(\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]>;\n\n /**\n * Evaluates {@link ResourcePermission | ResourcePermissions} and returns both definitive and\n * conditional decisions, depending on the configured\n * {@link @backstage/plugin-permission-node#PermissionPolicy}. This method is useful when the\n * caller needs more control over the processing of conditional decisions. For example, a plugin\n * backend may want to use {@link PermissionCriteria | conditions} in a database query instead of\n * evaluating each resource in memory.\n */\n authorizeConditional(\n requests: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<QueryPermissionResponse[]>;\n}\n\n/**\n * Options for {@link PermissionEvaluator} requests.\n *\n * @public\n */\nexport type EvaluatorRequestOptions = {\n /**\n * @deprecated Backend plugins should no longer depend on the\n * `PermissionEvaluator`, but instead use the `PermissionService` from\n * `@backstage/backend-plugin-api`. Frontend plugins should not need to inject\n * this token at all, but instead implicitly rely on underlying fetchApi to do\n * it for them.\n */\n token?: string;\n};\n","/*\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 AuthorizePermissionRequest,\n AuthorizePermissionResponse,\n DefinitivePolicyDecision,\n EvaluatorRequestOptions,\n Permission,\n PermissionAuthorizer,\n PermissionEvaluator,\n QueryPermissionRequest,\n QueryPermissionResponse,\n ResourcePermission,\n} from '../types';\n\n/**\n * Check if the two parameters are equivalent permissions.\n * @public\n */\nexport function isPermission<T extends Permission>(\n permission: Permission,\n comparedPermission: T,\n): permission is T {\n return permission.name === comparedPermission.name;\n}\n\n/**\n * Check if a given permission is a {@link ResourcePermission}. When\n * `resourceType` is supplied as the second parameter, also checks if\n * the permission has the specified resource type.\n * @public\n */\nexport function isResourcePermission<T extends string = string>(\n permission: Permission,\n resourceType?: T,\n): permission is ResourcePermission<T> {\n if (!('resourceType' in permission)) {\n return false;\n }\n\n return !resourceType || permission.resourceType === resourceType;\n}\n\n/**\n * Check if a given permission is related to a create action.\n * @public\n */\nexport function isCreatePermission(permission: Permission) {\n return permission.attributes.action === 'create';\n}\n\n/**\n * Check if a given permission is related to a read action.\n * @public\n */\nexport function isReadPermission(permission: Permission) {\n return permission.attributes.action === 'read';\n}\n\n/**\n * Check if a given permission is related to an update action.\n * @public\n */\nexport function isUpdatePermission(permission: Permission) {\n return permission.attributes.action === 'update';\n}\n\n/**\n * Check if a given permission is related to a delete action.\n * @public\n */\nexport function isDeletePermission(permission: Permission) {\n return permission.attributes.action === 'delete';\n}\n\n/**\n * Convert {@link PermissionAuthorizer} to {@link PermissionEvaluator}.\n *\n * @public\n */\nexport function toPermissionEvaluator(\n permissionAuthorizer: PermissionAuthorizer,\n): PermissionEvaluator {\n return {\n authorize: async (\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]> => {\n const response = await permissionAuthorizer.authorize(requests, options);\n\n return response as DefinitivePolicyDecision[];\n },\n authorizeConditional(\n requests: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<QueryPermissionResponse[]> {\n const parsedRequests =\n requests as unknown as AuthorizePermissionRequest[];\n return permissionAuthorizer.authorize(parsedRequests, options);\n },\n };\n}\n","/*\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 BasicPermission,\n Permission,\n PermissionAttributes,\n ResourcePermission,\n} from '../types';\n\n/**\n * Utility function for creating a valid {@link ResourcePermission}, inferring\n * the appropriate type and resource type parameter.\n *\n * @public\n */\nexport function createPermission<TResourceType extends string>(input: {\n name: string;\n attributes: PermissionAttributes;\n resourceType: TResourceType;\n}): ResourcePermission<TResourceType>;\n/**\n * Utility function for creating a valid {@link BasicPermission}.\n *\n * @public\n */\nexport function createPermission(input: {\n name: string;\n attributes: PermissionAttributes;\n}): BasicPermission;\nexport function createPermission({\n name,\n attributes,\n resourceType,\n}: {\n name: string;\n attributes: PermissionAttributes;\n resourceType?: string;\n}): Permission {\n if (resourceType) {\n return {\n type: 'resource',\n name,\n attributes,\n resourceType,\n };\n }\n\n return {\n type: 'basic',\n name,\n attributes,\n };\n}\n","/*\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 { Config } from '@backstage/config';\nimport { ResponseError } from '@backstage/errors';\nimport fetch from 'cross-fetch';\nimport * as uuid from 'uuid';\nimport { z } from 'zod';\nimport {\n AuthorizeResult,\n PermissionMessageBatch,\n PermissionCriteria,\n PermissionCondition,\n PermissionEvaluator,\n QueryPermissionRequest,\n AuthorizePermissionRequest,\n EvaluatorRequestOptions,\n AuthorizePermissionResponse,\n QueryPermissionResponse,\n} from './types/api';\nimport { DiscoveryApi } from './types/discovery';\nimport { AuthorizeRequestOptions } from './types/permission';\n\nconst permissionCriteriaSchema: z.ZodSchema<\n PermissionCriteria<PermissionCondition>\n> = z.lazy(() =>\n z\n .object({\n rule: z.string(),\n resourceType: z.string(),\n params: z.record(z.any()).optional(),\n })\n .or(z.object({ anyOf: z.array(permissionCriteriaSchema).nonempty() }))\n .or(z.object({ allOf: z.array(permissionCriteriaSchema).nonempty() }))\n .or(z.object({ not: permissionCriteriaSchema })),\n);\n\nconst authorizePermissionResponseSchema: z.ZodSchema<AuthorizePermissionResponse> =\n z.object({\n result: z\n .literal(AuthorizeResult.ALLOW)\n .or(z.literal(AuthorizeResult.DENY)),\n });\n\nconst queryPermissionResponseSchema: z.ZodSchema<QueryPermissionResponse> =\n z.union([\n z.object({\n result: z\n .literal(AuthorizeResult.ALLOW)\n .or(z.literal(AuthorizeResult.DENY)),\n }),\n z.object({\n result: z.literal(AuthorizeResult.CONDITIONAL),\n pluginId: z.string(),\n resourceType: z.string(),\n conditions: permissionCriteriaSchema,\n }),\n ]);\n\nconst responseSchema = <T>(\n itemSchema: z.ZodSchema<T>,\n ids: Set<string>,\n): z.ZodSchema<PermissionMessageBatch<T>> =>\n z.object({\n items: z\n .array(\n z.intersection(\n z.object({\n id: z.string(),\n }),\n itemSchema,\n ),\n )\n .refine(\n items =>\n items.length === ids.size && items.every(({ id }) => ids.has(id)),\n {\n message: 'Items in response do not match request',\n },\n ),\n });\n\n/**\n * An isomorphic client for requesting authorization for Backstage permissions.\n * @public\n */\nexport class PermissionClient implements PermissionEvaluator {\n private readonly enabled: boolean;\n private readonly discovery: DiscoveryApi;\n\n constructor(options: { discovery: DiscoveryApi; config: Config }) {\n this.discovery = options.discovery;\n this.enabled =\n options.config.getOptionalBoolean('permission.enabled') ?? false;\n }\n\n /**\n * {@inheritdoc PermissionEvaluator.authorize}\n */\n async authorize(\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]> {\n return this.makeRequest(\n requests,\n authorizePermissionResponseSchema,\n options,\n );\n }\n\n /**\n * {@inheritdoc PermissionEvaluator.authorizeConditional}\n */\n async authorizeConditional(\n queries: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<QueryPermissionResponse[]> {\n return this.makeRequest(queries, queryPermissionResponseSchema, options);\n }\n\n private async makeRequest<TQuery, TResult>(\n queries: TQuery[],\n itemSchema: z.ZodSchema<TResult>,\n options?: AuthorizeRequestOptions,\n ) {\n if (!this.enabled) {\n return queries.map(_ => ({ result: AuthorizeResult.ALLOW as const }));\n }\n\n const request: PermissionMessageBatch<TQuery> = {\n items: queries.map(query => ({\n id: uuid.v4(),\n ...query,\n })),\n };\n\n const permissionApi = await this.discovery.getBaseUrl('permission');\n const response = await fetch(`${permissionApi}/authorize`, {\n method: 'POST',\n body: JSON.stringify(request),\n headers: {\n ...this.getAuthorizationHeader(options?.token),\n 'content-type': 'application/json',\n },\n });\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n const responseBody = await response.json();\n\n const parsedResponse = responseSchema(\n itemSchema,\n new Set(request.items.map(({ id }) => id)),\n ).parse(responseBody);\n\n const responsesById = parsedResponse.items.reduce((acc, r) => {\n acc[r.id] = r;\n return acc;\n }, {} as Record<string, z.infer<typeof itemSchema>>);\n\n return request.items.map(query => responsesById[query.id]);\n }\n\n private getAuthorizationHeader(token?: string): Record<string, string> {\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n}\n"],"names":["AuthorizeResult","z","uuid","fetch","ResponseError"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/types/api.ts","../src/permissions/util.ts","../src/permissions/createPermission.ts","../src/PermissionClient.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 { JsonPrimitive } from '@backstage/types';\nimport { Permission, ResourcePermission } from './permission';\n\n/**\n * A request with a UUID identifier, so that batched responses can be matched up with the original\n * requests.\n * @public\n */\nexport type IdentifiedPermissionMessage<T> = T & { id: string };\n\n/**\n * A batch of request or response items.\n * @public\n */\nexport type PermissionMessageBatch<T> = {\n items: IdentifiedPermissionMessage<T>[];\n};\n\n/**\n * The result of an authorization request.\n * @public\n */\nexport enum AuthorizeResult {\n /**\n * The authorization request is denied.\n */\n DENY = 'DENY',\n /**\n * The authorization request is allowed.\n */\n ALLOW = 'ALLOW',\n /**\n * The authorization request is allowed if the provided conditions are met.\n */\n CONDITIONAL = 'CONDITIONAL',\n}\n\n/**\n * A definitive decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.\n *\n * @remarks\n *\n * This indicates that the policy unconditionally allows (or denies) the request.\n *\n * @public\n */\nexport type DefinitivePolicyDecision = {\n result: AuthorizeResult.ALLOW | AuthorizeResult.DENY;\n};\n\n/**\n * A conditional decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.\n *\n * @remarks\n *\n * This indicates that the policy allows authorization for the request, given that the returned\n * conditions hold when evaluated. The conditions will be evaluated by the corresponding plugin\n * which knows about the referenced permission rules.\n *\n * @public\n */\nexport type ConditionalPolicyDecision = {\n result: AuthorizeResult.CONDITIONAL;\n pluginId: string;\n resourceType: string;\n conditions: PermissionCriteria<PermissionCondition>;\n};\n\n/**\n * A decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.\n *\n * @public\n */\nexport type PolicyDecision =\n | DefinitivePolicyDecision\n | ConditionalPolicyDecision;\n\n/**\n * A condition returned with a CONDITIONAL authorization response.\n *\n * Conditions are a reference to a rule defined by a plugin, and parameters to apply the rule. For\n * example, a rule might be `isOwner` from the catalog-backend, and params may be a list of entity\n * claims from a identity token.\n * @public\n */\nexport type PermissionCondition<\n TResourceType extends string = string,\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = {\n resourceType: TResourceType;\n rule: string;\n params?: TParams;\n};\n\n/**\n * Utility type to represent an array with 1 or more elements.\n * @ignore\n */\ntype NonEmptyArray<T> = [T, ...T[]];\n\n/**\n * Represents a logical AND for the provided criteria.\n * @public\n */\nexport type AllOfCriteria<TQuery> = {\n allOf: NonEmptyArray<PermissionCriteria<TQuery>>;\n};\n\n/**\n * Represents a logical OR for the provided criteria.\n * @public\n */\nexport type AnyOfCriteria<TQuery> = {\n anyOf: NonEmptyArray<PermissionCriteria<TQuery>>;\n};\n\n/**\n * Represents a negation of the provided criteria.\n * @public\n */\nexport type NotCriteria<TQuery> = {\n not: PermissionCriteria<TQuery>;\n};\n\n/**\n * Composes several {@link PermissionCondition}s as criteria with a nested AND/OR structure.\n * @public\n */\nexport type PermissionCriteria<TQuery> =\n | AllOfCriteria<TQuery>\n | AnyOfCriteria<TQuery>\n | NotCriteria<TQuery>\n | TQuery;\n\n/**\n * A parameter to a permission rule.\n *\n * @public\n */\nexport type PermissionRuleParam = undefined | JsonPrimitive | JsonPrimitive[];\n\n/**\n * Types that can be used as parameters to permission rules.\n *\n * @public\n */\nexport type PermissionRuleParams =\n | undefined\n | Record<string, PermissionRuleParam>;\n\n/**\n * An individual request sent to the permission backend.\n * @public\n */\nexport type EvaluatePermissionRequest = {\n permission: Permission;\n resourceRef?: string;\n};\n\n/**\n * A batch of requests sent to the permission backend.\n * @public\n */\nexport type EvaluatePermissionRequestBatch =\n PermissionMessageBatch<EvaluatePermissionRequest>;\n\n/**\n * An individual response from the permission backend.\n *\n * @remarks\n *\n * This response type is an alias of {@link PolicyDecision} to maintain separation between the\n * {@link @backstage/plugin-permission-node#PermissionPolicy} interface and the permission backend\n * api. They may diverge at some point in the future. The response\n *\n * @public\n */\nexport type EvaluatePermissionResponse = PolicyDecision;\n\n/**\n * A batch of responses from the permission backend.\n * @public\n */\nexport type EvaluatePermissionResponseBatch =\n PermissionMessageBatch<EvaluatePermissionResponse>;\n\n/**\n * Request object for {@link PermissionEvaluator.authorize}. If a {@link ResourcePermission}\n * is provided, it must include a corresponding `resourceRef`.\n * @public\n */\nexport type AuthorizePermissionRequest =\n | {\n permission: Exclude<Permission, ResourcePermission>;\n resourceRef?: never;\n }\n | { permission: ResourcePermission; resourceRef: string };\n\n/**\n * Response object for {@link PermissionEvaluator.authorize}.\n * @public\n */\nexport type AuthorizePermissionResponse = DefinitivePolicyDecision;\n\n/**\n * Request object for {@link PermissionEvaluator.authorizeConditional}.\n * @public\n */\nexport type QueryPermissionRequest = {\n permission: ResourcePermission;\n resourceRef?: never;\n};\n\n/**\n * Response object for {@link PermissionEvaluator.authorizeConditional}.\n * @public\n */\nexport type QueryPermissionResponse = PolicyDecision;\n\n/**\n * A client interacting with the permission backend can implement this evaluator interface.\n *\n * @public\n */\nexport interface PermissionEvaluator {\n /**\n * Evaluates {@link Permission | Permissions} and returns a definitive decision.\n */\n authorize(\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]>;\n\n /**\n * Evaluates {@link ResourcePermission | ResourcePermissions} and returns both definitive and\n * conditional decisions, depending on the configured\n * {@link @backstage/plugin-permission-node#PermissionPolicy}. This method is useful when the\n * caller needs more control over the processing of conditional decisions. For example, a plugin\n * backend may want to use {@link PermissionCriteria | conditions} in a database query instead of\n * evaluating each resource in memory.\n */\n authorizeConditional(\n requests: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<QueryPermissionResponse[]>;\n}\n\n/**\n * Options for {@link PermissionEvaluator} requests.\n *\n * @public\n */\nexport type EvaluatorRequestOptions = {\n /**\n * @deprecated Backend plugins should no longer depend on the\n * `PermissionEvaluator`, but instead use the `PermissionService` from\n * `@backstage/backend-plugin-api`. Frontend plugins should not need to inject\n * this token at all, but instead implicitly rely on underlying fetchApi to do\n * it for them.\n */\n token?: string;\n};\n","/*\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 AuthorizePermissionRequest,\n AuthorizePermissionResponse,\n DefinitivePolicyDecision,\n EvaluatorRequestOptions,\n Permission,\n PermissionAuthorizer,\n PermissionEvaluator,\n QueryPermissionRequest,\n QueryPermissionResponse,\n ResourcePermission,\n} from '../types';\n\n/**\n * Check if the two parameters are equivalent permissions.\n * @public\n */\nexport function isPermission<T extends Permission>(\n permission: Permission,\n comparedPermission: T,\n): permission is T {\n return permission.name === comparedPermission.name;\n}\n\n/**\n * Check if a given permission is a {@link ResourcePermission}. When\n * `resourceType` is supplied as the second parameter, also checks if\n * the permission has the specified resource type.\n * @public\n */\nexport function isResourcePermission<T extends string = string>(\n permission: Permission,\n resourceType?: T,\n): permission is ResourcePermission<T> {\n if (!('resourceType' in permission)) {\n return false;\n }\n\n return !resourceType || permission.resourceType === resourceType;\n}\n\n/**\n * Check if a given permission is related to a create action.\n * @public\n */\nexport function isCreatePermission(permission: Permission) {\n return permission.attributes.action === 'create';\n}\n\n/**\n * Check if a given permission is related to a read action.\n * @public\n */\nexport function isReadPermission(permission: Permission) {\n return permission.attributes.action === 'read';\n}\n\n/**\n * Check if a given permission is related to an update action.\n * @public\n */\nexport function isUpdatePermission(permission: Permission) {\n return permission.attributes.action === 'update';\n}\n\n/**\n * Check if a given permission is related to a delete action.\n * @public\n */\nexport function isDeletePermission(permission: Permission) {\n return permission.attributes.action === 'delete';\n}\n\n/**\n * Convert {@link PermissionAuthorizer} to {@link PermissionEvaluator}.\n *\n * @public\n */\nexport function toPermissionEvaluator(\n permissionAuthorizer: PermissionAuthorizer,\n): PermissionEvaluator {\n return {\n authorize: async (\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]> => {\n const response = await permissionAuthorizer.authorize(requests, options);\n\n return response as DefinitivePolicyDecision[];\n },\n authorizeConditional(\n requests: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<QueryPermissionResponse[]> {\n const parsedRequests =\n requests as unknown as AuthorizePermissionRequest[];\n return permissionAuthorizer.authorize(parsedRequests, options);\n },\n };\n}\n","/*\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 BasicPermission,\n Permission,\n PermissionAttributes,\n ResourcePermission,\n} from '../types';\n\n/**\n * Utility function for creating a valid {@link ResourcePermission}, inferring\n * the appropriate type and resource type parameter.\n *\n * @public\n */\nexport function createPermission<TResourceType extends string>(input: {\n name: string;\n attributes: PermissionAttributes;\n resourceType: TResourceType;\n}): ResourcePermission<TResourceType>;\n/**\n * Utility function for creating a valid {@link BasicPermission}.\n *\n * @public\n */\nexport function createPermission(input: {\n name: string;\n attributes: PermissionAttributes;\n}): BasicPermission;\nexport function createPermission({\n name,\n attributes,\n resourceType,\n}: {\n name: string;\n attributes: PermissionAttributes;\n resourceType?: string;\n}): Permission {\n if (resourceType) {\n return {\n type: 'resource',\n name,\n attributes,\n resourceType,\n };\n }\n\n return {\n type: 'basic',\n name,\n attributes,\n };\n}\n","/*\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 { Config } from '@backstage/config';\nimport { ResponseError } from '@backstage/errors';\nimport fetch from 'cross-fetch';\nimport * as uuid from 'uuid';\nimport { z } from 'zod';\nimport {\n AuthorizeResult,\n PermissionMessageBatch,\n PermissionCriteria,\n PermissionCondition,\n PermissionEvaluator,\n QueryPermissionRequest,\n AuthorizePermissionRequest,\n EvaluatorRequestOptions,\n AuthorizePermissionResponse,\n QueryPermissionResponse,\n} from './types/api';\nimport { DiscoveryApi } from './types/discovery';\nimport { AuthorizeRequestOptions } from './types/permission';\n\nconst permissionCriteriaSchema: z.ZodSchema<\n PermissionCriteria<PermissionCondition>\n> = z.lazy(() =>\n z\n .object({\n rule: z.string(),\n resourceType: z.string(),\n params: z.record(z.any()).optional(),\n })\n .or(z.object({ anyOf: z.array(permissionCriteriaSchema).nonempty() }))\n .or(z.object({ allOf: z.array(permissionCriteriaSchema).nonempty() }))\n .or(z.object({ not: permissionCriteriaSchema })),\n);\n\nconst authorizePermissionResponseSchema: z.ZodSchema<AuthorizePermissionResponse> =\n z.object({\n result: z\n .literal(AuthorizeResult.ALLOW)\n .or(z.literal(AuthorizeResult.DENY)),\n });\n\nconst queryPermissionResponseSchema: z.ZodSchema<QueryPermissionResponse> =\n z.union([\n z.object({\n result: z\n .literal(AuthorizeResult.ALLOW)\n .or(z.literal(AuthorizeResult.DENY)),\n }),\n z.object({\n result: z.literal(AuthorizeResult.CONDITIONAL),\n pluginId: z.string(),\n resourceType: z.string(),\n conditions: permissionCriteriaSchema,\n }),\n ]);\n\nconst responseSchema = <T>(\n itemSchema: z.ZodSchema<T>,\n ids: Set<string>,\n): z.ZodSchema<PermissionMessageBatch<T>> =>\n z.object({\n items: z\n .array(\n z.intersection(\n z.object({\n id: z.string(),\n }),\n itemSchema,\n ),\n )\n .refine(\n items =>\n items.length === ids.size && items.every(({ id }) => ids.has(id)),\n {\n message: 'Items in response do not match request',\n },\n ),\n });\n\n/**\n * An isomorphic client for requesting authorization for Backstage permissions.\n * @public\n */\nexport class PermissionClient implements PermissionEvaluator {\n private readonly enabled: boolean;\n private readonly discovery: DiscoveryApi;\n\n constructor(options: { discovery: DiscoveryApi; config: Config }) {\n this.discovery = options.discovery;\n this.enabled =\n options.config.getOptionalBoolean('permission.enabled') ?? false;\n }\n\n /**\n * {@inheritdoc PermissionEvaluator.authorize}\n */\n async authorize(\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]> {\n return this.makeRequest(\n requests,\n authorizePermissionResponseSchema,\n options,\n );\n }\n\n /**\n * {@inheritdoc PermissionEvaluator.authorizeConditional}\n */\n async authorizeConditional(\n queries: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<QueryPermissionResponse[]> {\n return this.makeRequest(queries, queryPermissionResponseSchema, options);\n }\n\n private async makeRequest<TQuery, TResult>(\n queries: TQuery[],\n itemSchema: z.ZodSchema<TResult>,\n options?: AuthorizeRequestOptions,\n ) {\n if (!this.enabled) {\n return queries.map(_ => ({ result: AuthorizeResult.ALLOW as const }));\n }\n\n const request: PermissionMessageBatch<TQuery> = {\n items: queries.map(query => ({\n id: uuid.v4(),\n ...query,\n })),\n };\n\n const permissionApi = await this.discovery.getBaseUrl('permission');\n const response = await fetch(`${permissionApi}/authorize`, {\n method: 'POST',\n body: JSON.stringify(request),\n headers: {\n ...this.getAuthorizationHeader(options?.token),\n 'content-type': 'application/json',\n },\n });\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n const responseBody = await response.json();\n\n const parsedResponse = responseSchema(\n itemSchema,\n new Set(request.items.map(({ id }) => id)),\n ).parse(responseBody);\n\n const responsesById = parsedResponse.items.reduce((acc, r) => {\n acc[r.id] = r;\n return acc;\n }, {} as Record<string, z.infer<typeof itemSchema>>);\n\n return request.items.map(query => responsesById[query.id]);\n }\n\n private getAuthorizationHeader(token?: string): Record<string, string> {\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n}\n"],"names":["AuthorizeResult","z","uuid","fetch","ResponseError"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -392,4 +392,4 @@ declare class PermissionClient implements PermissionEvaluator {
392
392
  private getAuthorizationHeader;
393
393
  }
394
394
 
395
- export { AllOfCriteria, AnyOfCriteria, AuthorizePermissionRequest, AuthorizePermissionResponse, AuthorizeRequestOptions, AuthorizeResult, BasicPermission, ConditionalPolicyDecision, DefinitivePolicyDecision, DiscoveryApi, EvaluatePermissionRequest, EvaluatePermissionRequestBatch, EvaluatePermissionResponse, EvaluatePermissionResponseBatch, EvaluatorRequestOptions, IdentifiedPermissionMessage, NotCriteria, Permission, PermissionAttributes, PermissionAuthorizer, PermissionBase, PermissionClient, PermissionCondition, PermissionCriteria, PermissionEvaluator, PermissionMessageBatch, PermissionRuleParam, PermissionRuleParams, PolicyDecision, QueryPermissionRequest, QueryPermissionResponse, ResourcePermission, createPermission, isCreatePermission, isDeletePermission, isPermission, isReadPermission, isResourcePermission, isUpdatePermission, toPermissionEvaluator };
395
+ export { type AllOfCriteria, type AnyOfCriteria, type AuthorizePermissionRequest, type AuthorizePermissionResponse, type AuthorizeRequestOptions, AuthorizeResult, type BasicPermission, type ConditionalPolicyDecision, type DefinitivePolicyDecision, type DiscoveryApi, type EvaluatePermissionRequest, type EvaluatePermissionRequestBatch, type EvaluatePermissionResponse, type EvaluatePermissionResponseBatch, type EvaluatorRequestOptions, type IdentifiedPermissionMessage, type NotCriteria, type Permission, type PermissionAttributes, type PermissionAuthorizer, type PermissionBase, PermissionClient, type PermissionCondition, type PermissionCriteria, type PermissionEvaluator, type PermissionMessageBatch, type PermissionRuleParam, type PermissionRuleParams, type PolicyDecision, type QueryPermissionRequest, type QueryPermissionResponse, type ResourcePermission, createPermission, isCreatePermission, isDeletePermission, isPermission, isReadPermission, isResourcePermission, isUpdatePermission, toPermissionEvaluator };
package/dist/index.esm.js CHANGED
@@ -1,172 +1,5 @@
1
- import { ResponseError } from '@backstage/errors';
2
- import fetch from 'cross-fetch';
3
- import * as uuid from 'uuid';
4
- import { z } from 'zod';
5
-
6
- var AuthorizeResult = /* @__PURE__ */ ((AuthorizeResult2) => {
7
- AuthorizeResult2["DENY"] = "DENY";
8
- AuthorizeResult2["ALLOW"] = "ALLOW";
9
- AuthorizeResult2["CONDITIONAL"] = "CONDITIONAL";
10
- return AuthorizeResult2;
11
- })(AuthorizeResult || {});
12
-
13
- function isPermission(permission, comparedPermission) {
14
- return permission.name === comparedPermission.name;
15
- }
16
- function isResourcePermission(permission, resourceType) {
17
- if (!("resourceType" in permission)) {
18
- return false;
19
- }
20
- return !resourceType || permission.resourceType === resourceType;
21
- }
22
- function isCreatePermission(permission) {
23
- return permission.attributes.action === "create";
24
- }
25
- function isReadPermission(permission) {
26
- return permission.attributes.action === "read";
27
- }
28
- function isUpdatePermission(permission) {
29
- return permission.attributes.action === "update";
30
- }
31
- function isDeletePermission(permission) {
32
- return permission.attributes.action === "delete";
33
- }
34
- function toPermissionEvaluator(permissionAuthorizer) {
35
- return {
36
- authorize: async (requests, options) => {
37
- const response = await permissionAuthorizer.authorize(requests, options);
38
- return response;
39
- },
40
- authorizeConditional(requests, options) {
41
- const parsedRequests = requests;
42
- return permissionAuthorizer.authorize(parsedRequests, options);
43
- }
44
- };
45
- }
46
-
47
- function createPermission({
48
- name,
49
- attributes,
50
- resourceType
51
- }) {
52
- if (resourceType) {
53
- return {
54
- type: "resource",
55
- name,
56
- attributes,
57
- resourceType
58
- };
59
- }
60
- return {
61
- type: "basic",
62
- name,
63
- attributes
64
- };
65
- }
66
-
67
- var __defProp = Object.defineProperty;
68
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
69
- var __publicField = (obj, key, value) => {
70
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
71
- return value;
72
- };
73
- const permissionCriteriaSchema = z.lazy(
74
- () => z.object({
75
- rule: z.string(),
76
- resourceType: z.string(),
77
- params: z.record(z.any()).optional()
78
- }).or(z.object({ anyOf: z.array(permissionCriteriaSchema).nonempty() })).or(z.object({ allOf: z.array(permissionCriteriaSchema).nonempty() })).or(z.object({ not: permissionCriteriaSchema }))
79
- );
80
- const authorizePermissionResponseSchema = z.object({
81
- result: z.literal(AuthorizeResult.ALLOW).or(z.literal(AuthorizeResult.DENY))
82
- });
83
- const queryPermissionResponseSchema = z.union([
84
- z.object({
85
- result: z.literal(AuthorizeResult.ALLOW).or(z.literal(AuthorizeResult.DENY))
86
- }),
87
- z.object({
88
- result: z.literal(AuthorizeResult.CONDITIONAL),
89
- pluginId: z.string(),
90
- resourceType: z.string(),
91
- conditions: permissionCriteriaSchema
92
- })
93
- ]);
94
- const responseSchema = (itemSchema, ids) => z.object({
95
- items: z.array(
96
- z.intersection(
97
- z.object({
98
- id: z.string()
99
- }),
100
- itemSchema
101
- )
102
- ).refine(
103
- (items) => items.length === ids.size && items.every(({ id }) => ids.has(id)),
104
- {
105
- message: "Items in response do not match request"
106
- }
107
- )
108
- });
109
- class PermissionClient {
110
- constructor(options) {
111
- __publicField(this, "enabled");
112
- __publicField(this, "discovery");
113
- var _a;
114
- this.discovery = options.discovery;
115
- this.enabled = (_a = options.config.getOptionalBoolean("permission.enabled")) != null ? _a : false;
116
- }
117
- /**
118
- * {@inheritdoc PermissionEvaluator.authorize}
119
- */
120
- async authorize(requests, options) {
121
- return this.makeRequest(
122
- requests,
123
- authorizePermissionResponseSchema,
124
- options
125
- );
126
- }
127
- /**
128
- * {@inheritdoc PermissionEvaluator.authorizeConditional}
129
- */
130
- async authorizeConditional(queries, options) {
131
- return this.makeRequest(queries, queryPermissionResponseSchema, options);
132
- }
133
- async makeRequest(queries, itemSchema, options) {
134
- if (!this.enabled) {
135
- return queries.map((_) => ({ result: AuthorizeResult.ALLOW }));
136
- }
137
- const request = {
138
- items: queries.map((query) => ({
139
- id: uuid.v4(),
140
- ...query
141
- }))
142
- };
143
- const permissionApi = await this.discovery.getBaseUrl("permission");
144
- const response = await fetch(`${permissionApi}/authorize`, {
145
- method: "POST",
146
- body: JSON.stringify(request),
147
- headers: {
148
- ...this.getAuthorizationHeader(options == null ? void 0 : options.token),
149
- "content-type": "application/json"
150
- }
151
- });
152
- if (!response.ok) {
153
- throw await ResponseError.fromResponse(response);
154
- }
155
- const responseBody = await response.json();
156
- const parsedResponse = responseSchema(
157
- itemSchema,
158
- new Set(request.items.map(({ id }) => id))
159
- ).parse(responseBody);
160
- const responsesById = parsedResponse.items.reduce((acc, r) => {
161
- acc[r.id] = r;
162
- return acc;
163
- }, {});
164
- return request.items.map((query) => responsesById[query.id]);
165
- }
166
- getAuthorizationHeader(token) {
167
- return token ? { Authorization: `Bearer ${token}` } : {};
168
- }
169
- }
170
-
171
- export { AuthorizeResult, PermissionClient, createPermission, isCreatePermission, isDeletePermission, isPermission, isReadPermission, isResourcePermission, isUpdatePermission, toPermissionEvaluator };
1
+ export { AuthorizeResult } from './types/api.esm.js';
2
+ export { isCreatePermission, isDeletePermission, isPermission, isReadPermission, isResourcePermission, isUpdatePermission, toPermissionEvaluator } from './permissions/util.esm.js';
3
+ export { createPermission } from './permissions/createPermission.esm.js';
4
+ export { PermissionClient } from './PermissionClient.esm.js';
172
5
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/types/api.ts","../src/permissions/util.ts","../src/permissions/createPermission.ts","../src/PermissionClient.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 { JsonPrimitive } from '@backstage/types';\nimport { Permission, ResourcePermission } from './permission';\n\n/**\n * A request with a UUID identifier, so that batched responses can be matched up with the original\n * requests.\n * @public\n */\nexport type IdentifiedPermissionMessage<T> = T & { id: string };\n\n/**\n * A batch of request or response items.\n * @public\n */\nexport type PermissionMessageBatch<T> = {\n items: IdentifiedPermissionMessage<T>[];\n};\n\n/**\n * The result of an authorization request.\n * @public\n */\nexport enum AuthorizeResult {\n /**\n * The authorization request is denied.\n */\n DENY = 'DENY',\n /**\n * The authorization request is allowed.\n */\n ALLOW = 'ALLOW',\n /**\n * The authorization request is allowed if the provided conditions are met.\n */\n CONDITIONAL = 'CONDITIONAL',\n}\n\n/**\n * A definitive decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.\n *\n * @remarks\n *\n * This indicates that the policy unconditionally allows (or denies) the request.\n *\n * @public\n */\nexport type DefinitivePolicyDecision = {\n result: AuthorizeResult.ALLOW | AuthorizeResult.DENY;\n};\n\n/**\n * A conditional decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.\n *\n * @remarks\n *\n * This indicates that the policy allows authorization for the request, given that the returned\n * conditions hold when evaluated. The conditions will be evaluated by the corresponding plugin\n * which knows about the referenced permission rules.\n *\n * @public\n */\nexport type ConditionalPolicyDecision = {\n result: AuthorizeResult.CONDITIONAL;\n pluginId: string;\n resourceType: string;\n conditions: PermissionCriteria<PermissionCondition>;\n};\n\n/**\n * A decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.\n *\n * @public\n */\nexport type PolicyDecision =\n | DefinitivePolicyDecision\n | ConditionalPolicyDecision;\n\n/**\n * A condition returned with a CONDITIONAL authorization response.\n *\n * Conditions are a reference to a rule defined by a plugin, and parameters to apply the rule. For\n * example, a rule might be `isOwner` from the catalog-backend, and params may be a list of entity\n * claims from a identity token.\n * @public\n */\nexport type PermissionCondition<\n TResourceType extends string = string,\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = {\n resourceType: TResourceType;\n rule: string;\n params?: TParams;\n};\n\n/**\n * Utility type to represent an array with 1 or more elements.\n * @ignore\n */\ntype NonEmptyArray<T> = [T, ...T[]];\n\n/**\n * Represents a logical AND for the provided criteria.\n * @public\n */\nexport type AllOfCriteria<TQuery> = {\n allOf: NonEmptyArray<PermissionCriteria<TQuery>>;\n};\n\n/**\n * Represents a logical OR for the provided criteria.\n * @public\n */\nexport type AnyOfCriteria<TQuery> = {\n anyOf: NonEmptyArray<PermissionCriteria<TQuery>>;\n};\n\n/**\n * Represents a negation of the provided criteria.\n * @public\n */\nexport type NotCriteria<TQuery> = {\n not: PermissionCriteria<TQuery>;\n};\n\n/**\n * Composes several {@link PermissionCondition}s as criteria with a nested AND/OR structure.\n * @public\n */\nexport type PermissionCriteria<TQuery> =\n | AllOfCriteria<TQuery>\n | AnyOfCriteria<TQuery>\n | NotCriteria<TQuery>\n | TQuery;\n\n/**\n * A parameter to a permission rule.\n *\n * @public\n */\nexport type PermissionRuleParam = undefined | JsonPrimitive | JsonPrimitive[];\n\n/**\n * Types that can be used as parameters to permission rules.\n *\n * @public\n */\nexport type PermissionRuleParams =\n | undefined\n | Record<string, PermissionRuleParam>;\n\n/**\n * An individual request sent to the permission backend.\n * @public\n */\nexport type EvaluatePermissionRequest = {\n permission: Permission;\n resourceRef?: string;\n};\n\n/**\n * A batch of requests sent to the permission backend.\n * @public\n */\nexport type EvaluatePermissionRequestBatch =\n PermissionMessageBatch<EvaluatePermissionRequest>;\n\n/**\n * An individual response from the permission backend.\n *\n * @remarks\n *\n * This response type is an alias of {@link PolicyDecision} to maintain separation between the\n * {@link @backstage/plugin-permission-node#PermissionPolicy} interface and the permission backend\n * api. They may diverge at some point in the future. The response\n *\n * @public\n */\nexport type EvaluatePermissionResponse = PolicyDecision;\n\n/**\n * A batch of responses from the permission backend.\n * @public\n */\nexport type EvaluatePermissionResponseBatch =\n PermissionMessageBatch<EvaluatePermissionResponse>;\n\n/**\n * Request object for {@link PermissionEvaluator.authorize}. If a {@link ResourcePermission}\n * is provided, it must include a corresponding `resourceRef`.\n * @public\n */\nexport type AuthorizePermissionRequest =\n | {\n permission: Exclude<Permission, ResourcePermission>;\n resourceRef?: never;\n }\n | { permission: ResourcePermission; resourceRef: string };\n\n/**\n * Response object for {@link PermissionEvaluator.authorize}.\n * @public\n */\nexport type AuthorizePermissionResponse = DefinitivePolicyDecision;\n\n/**\n * Request object for {@link PermissionEvaluator.authorizeConditional}.\n * @public\n */\nexport type QueryPermissionRequest = {\n permission: ResourcePermission;\n resourceRef?: never;\n};\n\n/**\n * Response object for {@link PermissionEvaluator.authorizeConditional}.\n * @public\n */\nexport type QueryPermissionResponse = PolicyDecision;\n\n/**\n * A client interacting with the permission backend can implement this evaluator interface.\n *\n * @public\n */\nexport interface PermissionEvaluator {\n /**\n * Evaluates {@link Permission | Permissions} and returns a definitive decision.\n */\n authorize(\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]>;\n\n /**\n * Evaluates {@link ResourcePermission | ResourcePermissions} and returns both definitive and\n * conditional decisions, depending on the configured\n * {@link @backstage/plugin-permission-node#PermissionPolicy}. This method is useful when the\n * caller needs more control over the processing of conditional decisions. For example, a plugin\n * backend may want to use {@link PermissionCriteria | conditions} in a database query instead of\n * evaluating each resource in memory.\n */\n authorizeConditional(\n requests: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<QueryPermissionResponse[]>;\n}\n\n/**\n * Options for {@link PermissionEvaluator} requests.\n *\n * @public\n */\nexport type EvaluatorRequestOptions = {\n /**\n * @deprecated Backend plugins should no longer depend on the\n * `PermissionEvaluator`, but instead use the `PermissionService` from\n * `@backstage/backend-plugin-api`. Frontend plugins should not need to inject\n * this token at all, but instead implicitly rely on underlying fetchApi to do\n * it for them.\n */\n token?: string;\n};\n","/*\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 AuthorizePermissionRequest,\n AuthorizePermissionResponse,\n DefinitivePolicyDecision,\n EvaluatorRequestOptions,\n Permission,\n PermissionAuthorizer,\n PermissionEvaluator,\n QueryPermissionRequest,\n QueryPermissionResponse,\n ResourcePermission,\n} from '../types';\n\n/**\n * Check if the two parameters are equivalent permissions.\n * @public\n */\nexport function isPermission<T extends Permission>(\n permission: Permission,\n comparedPermission: T,\n): permission is T {\n return permission.name === comparedPermission.name;\n}\n\n/**\n * Check if a given permission is a {@link ResourcePermission}. When\n * `resourceType` is supplied as the second parameter, also checks if\n * the permission has the specified resource type.\n * @public\n */\nexport function isResourcePermission<T extends string = string>(\n permission: Permission,\n resourceType?: T,\n): permission is ResourcePermission<T> {\n if (!('resourceType' in permission)) {\n return false;\n }\n\n return !resourceType || permission.resourceType === resourceType;\n}\n\n/**\n * Check if a given permission is related to a create action.\n * @public\n */\nexport function isCreatePermission(permission: Permission) {\n return permission.attributes.action === 'create';\n}\n\n/**\n * Check if a given permission is related to a read action.\n * @public\n */\nexport function isReadPermission(permission: Permission) {\n return permission.attributes.action === 'read';\n}\n\n/**\n * Check if a given permission is related to an update action.\n * @public\n */\nexport function isUpdatePermission(permission: Permission) {\n return permission.attributes.action === 'update';\n}\n\n/**\n * Check if a given permission is related to a delete action.\n * @public\n */\nexport function isDeletePermission(permission: Permission) {\n return permission.attributes.action === 'delete';\n}\n\n/**\n * Convert {@link PermissionAuthorizer} to {@link PermissionEvaluator}.\n *\n * @public\n */\nexport function toPermissionEvaluator(\n permissionAuthorizer: PermissionAuthorizer,\n): PermissionEvaluator {\n return {\n authorize: async (\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]> => {\n const response = await permissionAuthorizer.authorize(requests, options);\n\n return response as DefinitivePolicyDecision[];\n },\n authorizeConditional(\n requests: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<QueryPermissionResponse[]> {\n const parsedRequests =\n requests as unknown as AuthorizePermissionRequest[];\n return permissionAuthorizer.authorize(parsedRequests, options);\n },\n };\n}\n","/*\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 BasicPermission,\n Permission,\n PermissionAttributes,\n ResourcePermission,\n} from '../types';\n\n/**\n * Utility function for creating a valid {@link ResourcePermission}, inferring\n * the appropriate type and resource type parameter.\n *\n * @public\n */\nexport function createPermission<TResourceType extends string>(input: {\n name: string;\n attributes: PermissionAttributes;\n resourceType: TResourceType;\n}): ResourcePermission<TResourceType>;\n/**\n * Utility function for creating a valid {@link BasicPermission}.\n *\n * @public\n */\nexport function createPermission(input: {\n name: string;\n attributes: PermissionAttributes;\n}): BasicPermission;\nexport function createPermission({\n name,\n attributes,\n resourceType,\n}: {\n name: string;\n attributes: PermissionAttributes;\n resourceType?: string;\n}): Permission {\n if (resourceType) {\n return {\n type: 'resource',\n name,\n attributes,\n resourceType,\n };\n }\n\n return {\n type: 'basic',\n name,\n attributes,\n };\n}\n","/*\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 { Config } from '@backstage/config';\nimport { ResponseError } from '@backstage/errors';\nimport fetch from 'cross-fetch';\nimport * as uuid from 'uuid';\nimport { z } from 'zod';\nimport {\n AuthorizeResult,\n PermissionMessageBatch,\n PermissionCriteria,\n PermissionCondition,\n PermissionEvaluator,\n QueryPermissionRequest,\n AuthorizePermissionRequest,\n EvaluatorRequestOptions,\n AuthorizePermissionResponse,\n QueryPermissionResponse,\n} from './types/api';\nimport { DiscoveryApi } from './types/discovery';\nimport { AuthorizeRequestOptions } from './types/permission';\n\nconst permissionCriteriaSchema: z.ZodSchema<\n PermissionCriteria<PermissionCondition>\n> = z.lazy(() =>\n z\n .object({\n rule: z.string(),\n resourceType: z.string(),\n params: z.record(z.any()).optional(),\n })\n .or(z.object({ anyOf: z.array(permissionCriteriaSchema).nonempty() }))\n .or(z.object({ allOf: z.array(permissionCriteriaSchema).nonempty() }))\n .or(z.object({ not: permissionCriteriaSchema })),\n);\n\nconst authorizePermissionResponseSchema: z.ZodSchema<AuthorizePermissionResponse> =\n z.object({\n result: z\n .literal(AuthorizeResult.ALLOW)\n .or(z.literal(AuthorizeResult.DENY)),\n });\n\nconst queryPermissionResponseSchema: z.ZodSchema<QueryPermissionResponse> =\n z.union([\n z.object({\n result: z\n .literal(AuthorizeResult.ALLOW)\n .or(z.literal(AuthorizeResult.DENY)),\n }),\n z.object({\n result: z.literal(AuthorizeResult.CONDITIONAL),\n pluginId: z.string(),\n resourceType: z.string(),\n conditions: permissionCriteriaSchema,\n }),\n ]);\n\nconst responseSchema = <T>(\n itemSchema: z.ZodSchema<T>,\n ids: Set<string>,\n): z.ZodSchema<PermissionMessageBatch<T>> =>\n z.object({\n items: z\n .array(\n z.intersection(\n z.object({\n id: z.string(),\n }),\n itemSchema,\n ),\n )\n .refine(\n items =>\n items.length === ids.size && items.every(({ id }) => ids.has(id)),\n {\n message: 'Items in response do not match request',\n },\n ),\n });\n\n/**\n * An isomorphic client for requesting authorization for Backstage permissions.\n * @public\n */\nexport class PermissionClient implements PermissionEvaluator {\n private readonly enabled: boolean;\n private readonly discovery: DiscoveryApi;\n\n constructor(options: { discovery: DiscoveryApi; config: Config }) {\n this.discovery = options.discovery;\n this.enabled =\n options.config.getOptionalBoolean('permission.enabled') ?? false;\n }\n\n /**\n * {@inheritdoc PermissionEvaluator.authorize}\n */\n async authorize(\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]> {\n return this.makeRequest(\n requests,\n authorizePermissionResponseSchema,\n options,\n );\n }\n\n /**\n * {@inheritdoc PermissionEvaluator.authorizeConditional}\n */\n async authorizeConditional(\n queries: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<QueryPermissionResponse[]> {\n return this.makeRequest(queries, queryPermissionResponseSchema, options);\n }\n\n private async makeRequest<TQuery, TResult>(\n queries: TQuery[],\n itemSchema: z.ZodSchema<TResult>,\n options?: AuthorizeRequestOptions,\n ) {\n if (!this.enabled) {\n return queries.map(_ => ({ result: AuthorizeResult.ALLOW as const }));\n }\n\n const request: PermissionMessageBatch<TQuery> = {\n items: queries.map(query => ({\n id: uuid.v4(),\n ...query,\n })),\n };\n\n const permissionApi = await this.discovery.getBaseUrl('permission');\n const response = await fetch(`${permissionApi}/authorize`, {\n method: 'POST',\n body: JSON.stringify(request),\n headers: {\n ...this.getAuthorizationHeader(options?.token),\n 'content-type': 'application/json',\n },\n });\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n const responseBody = await response.json();\n\n const parsedResponse = responseSchema(\n itemSchema,\n new Set(request.items.map(({ id }) => id)),\n ).parse(responseBody);\n\n const responsesById = parsedResponse.items.reduce((acc, r) => {\n acc[r.id] = r;\n return acc;\n }, {} as Record<string, z.infer<typeof itemSchema>>);\n\n return request.items.map(query => responsesById[query.id]);\n }\n\n private getAuthorizationHeader(token?: string): Record<string, string> {\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n}\n"],"names":["AuthorizeResult"],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
@@ -0,0 +1,22 @@
1
+ function createPermission({
2
+ name,
3
+ attributes,
4
+ resourceType
5
+ }) {
6
+ if (resourceType) {
7
+ return {
8
+ type: "resource",
9
+ name,
10
+ attributes,
11
+ resourceType
12
+ };
13
+ }
14
+ return {
15
+ type: "basic",
16
+ name,
17
+ attributes
18
+ };
19
+ }
20
+
21
+ export { createPermission };
22
+ //# sourceMappingURL=createPermission.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createPermission.esm.js","sources":["../../src/permissions/createPermission.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 BasicPermission,\n Permission,\n PermissionAttributes,\n ResourcePermission,\n} from '../types';\n\n/**\n * Utility function for creating a valid {@link ResourcePermission}, inferring\n * the appropriate type and resource type parameter.\n *\n * @public\n */\nexport function createPermission<TResourceType extends string>(input: {\n name: string;\n attributes: PermissionAttributes;\n resourceType: TResourceType;\n}): ResourcePermission<TResourceType>;\n/**\n * Utility function for creating a valid {@link BasicPermission}.\n *\n * @public\n */\nexport function createPermission(input: {\n name: string;\n attributes: PermissionAttributes;\n}): BasicPermission;\nexport function createPermission({\n name,\n attributes,\n resourceType,\n}: {\n name: string;\n attributes: PermissionAttributes;\n resourceType?: string;\n}): Permission {\n if (resourceType) {\n return {\n type: 'resource',\n name,\n attributes,\n resourceType,\n };\n }\n\n return {\n type: 'basic',\n name,\n attributes,\n };\n}\n"],"names":[],"mappings":"AA2CO,SAAS,gBAAiB,CAAA;AAAA,EAC/B,IAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AACF,CAIe,EAAA;AACb,EAAA,IAAI,YAAc,EAAA;AAChB,IAAO,OAAA;AAAA,MACL,IAAM,EAAA,UAAA;AAAA,MACN,IAAA;AAAA,MACA,UAAA;AAAA,MACA,YAAA;AAAA,KACF,CAAA;AAAA,GACF;AAEA,EAAO,OAAA;AAAA,IACL,IAAM,EAAA,OAAA;AAAA,IACN,IAAA;AAAA,IACA,UAAA;AAAA,GACF,CAAA;AACF;;;;"}
@@ -0,0 +1,36 @@
1
+ function isPermission(permission, comparedPermission) {
2
+ return permission.name === comparedPermission.name;
3
+ }
4
+ function isResourcePermission(permission, resourceType) {
5
+ if (!("resourceType" in permission)) {
6
+ return false;
7
+ }
8
+ return !resourceType || permission.resourceType === resourceType;
9
+ }
10
+ function isCreatePermission(permission) {
11
+ return permission.attributes.action === "create";
12
+ }
13
+ function isReadPermission(permission) {
14
+ return permission.attributes.action === "read";
15
+ }
16
+ function isUpdatePermission(permission) {
17
+ return permission.attributes.action === "update";
18
+ }
19
+ function isDeletePermission(permission) {
20
+ return permission.attributes.action === "delete";
21
+ }
22
+ function toPermissionEvaluator(permissionAuthorizer) {
23
+ return {
24
+ authorize: async (requests, options) => {
25
+ const response = await permissionAuthorizer.authorize(requests, options);
26
+ return response;
27
+ },
28
+ authorizeConditional(requests, options) {
29
+ const parsedRequests = requests;
30
+ return permissionAuthorizer.authorize(parsedRequests, options);
31
+ }
32
+ };
33
+ }
34
+
35
+ export { isCreatePermission, isDeletePermission, isPermission, isReadPermission, isResourcePermission, isUpdatePermission, toPermissionEvaluator };
36
+ //# sourceMappingURL=util.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.esm.js","sources":["../../src/permissions/util.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 AuthorizePermissionRequest,\n AuthorizePermissionResponse,\n DefinitivePolicyDecision,\n EvaluatorRequestOptions,\n Permission,\n PermissionAuthorizer,\n PermissionEvaluator,\n QueryPermissionRequest,\n QueryPermissionResponse,\n ResourcePermission,\n} from '../types';\n\n/**\n * Check if the two parameters are equivalent permissions.\n * @public\n */\nexport function isPermission<T extends Permission>(\n permission: Permission,\n comparedPermission: T,\n): permission is T {\n return permission.name === comparedPermission.name;\n}\n\n/**\n * Check if a given permission is a {@link ResourcePermission}. When\n * `resourceType` is supplied as the second parameter, also checks if\n * the permission has the specified resource type.\n * @public\n */\nexport function isResourcePermission<T extends string = string>(\n permission: Permission,\n resourceType?: T,\n): permission is ResourcePermission<T> {\n if (!('resourceType' in permission)) {\n return false;\n }\n\n return !resourceType || permission.resourceType === resourceType;\n}\n\n/**\n * Check if a given permission is related to a create action.\n * @public\n */\nexport function isCreatePermission(permission: Permission) {\n return permission.attributes.action === 'create';\n}\n\n/**\n * Check if a given permission is related to a read action.\n * @public\n */\nexport function isReadPermission(permission: Permission) {\n return permission.attributes.action === 'read';\n}\n\n/**\n * Check if a given permission is related to an update action.\n * @public\n */\nexport function isUpdatePermission(permission: Permission) {\n return permission.attributes.action === 'update';\n}\n\n/**\n * Check if a given permission is related to a delete action.\n * @public\n */\nexport function isDeletePermission(permission: Permission) {\n return permission.attributes.action === 'delete';\n}\n\n/**\n * Convert {@link PermissionAuthorizer} to {@link PermissionEvaluator}.\n *\n * @public\n */\nexport function toPermissionEvaluator(\n permissionAuthorizer: PermissionAuthorizer,\n): PermissionEvaluator {\n return {\n authorize: async (\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]> => {\n const response = await permissionAuthorizer.authorize(requests, options);\n\n return response as DefinitivePolicyDecision[];\n },\n authorizeConditional(\n requests: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<QueryPermissionResponse[]> {\n const parsedRequests =\n requests as unknown as AuthorizePermissionRequest[];\n return permissionAuthorizer.authorize(parsedRequests, options);\n },\n };\n}\n"],"names":[],"mappings":"AAiCgB,SAAA,YAAA,CACd,YACA,kBACiB,EAAA;AACjB,EAAO,OAAA,UAAA,CAAW,SAAS,kBAAmB,CAAA,IAAA,CAAA;AAChD,CAAA;AAQgB,SAAA,oBAAA,CACd,YACA,YACqC,EAAA;AACrC,EAAI,IAAA,EAAE,kBAAkB,UAAa,CAAA,EAAA;AACnC,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AAEA,EAAO,OAAA,CAAC,YAAgB,IAAA,UAAA,CAAW,YAAiB,KAAA,YAAA,CAAA;AACtD,CAAA;AAMO,SAAS,mBAAmB,UAAwB,EAAA;AACzD,EAAO,OAAA,UAAA,CAAW,WAAW,MAAW,KAAA,QAAA,CAAA;AAC1C,CAAA;AAMO,SAAS,iBAAiB,UAAwB,EAAA;AACvD,EAAO,OAAA,UAAA,CAAW,WAAW,MAAW,KAAA,MAAA,CAAA;AAC1C,CAAA;AAMO,SAAS,mBAAmB,UAAwB,EAAA;AACzD,EAAO,OAAA,UAAA,CAAW,WAAW,MAAW,KAAA,QAAA,CAAA;AAC1C,CAAA;AAMO,SAAS,mBAAmB,UAAwB,EAAA;AACzD,EAAO,OAAA,UAAA,CAAW,WAAW,MAAW,KAAA,QAAA,CAAA;AAC1C,CAAA;AAOO,SAAS,sBACd,oBACqB,EAAA;AACrB,EAAO,OAAA;AAAA,IACL,SAAA,EAAW,OACT,QAAA,EACA,OAC2C,KAAA;AAC3C,MAAA,MAAM,QAAW,GAAA,MAAM,oBAAqB,CAAA,SAAA,CAAU,UAAU,OAAO,CAAA,CAAA;AAEvE,MAAO,OAAA,QAAA,CAAA;AAAA,KACT;AAAA,IACA,oBAAA,CACE,UACA,OACoC,EAAA;AACpC,MAAA,MAAM,cACJ,GAAA,QAAA,CAAA;AACF,MAAO,OAAA,oBAAA,CAAqB,SAAU,CAAA,cAAA,EAAgB,OAAO,CAAA,CAAA;AAAA,KAC/D;AAAA,GACF,CAAA;AACF;;;;"}
@@ -0,0 +1,9 @@
1
+ var AuthorizeResult = /* @__PURE__ */ ((AuthorizeResult2) => {
2
+ AuthorizeResult2["DENY"] = "DENY";
3
+ AuthorizeResult2["ALLOW"] = "ALLOW";
4
+ AuthorizeResult2["CONDITIONAL"] = "CONDITIONAL";
5
+ return AuthorizeResult2;
6
+ })(AuthorizeResult || {});
7
+
8
+ export { AuthorizeResult };
9
+ //# sourceMappingURL=api.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.esm.js","sources":["../../src/types/api.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 { JsonPrimitive } from '@backstage/types';\nimport { Permission, ResourcePermission } from './permission';\n\n/**\n * A request with a UUID identifier, so that batched responses can be matched up with the original\n * requests.\n * @public\n */\nexport type IdentifiedPermissionMessage<T> = T & { id: string };\n\n/**\n * A batch of request or response items.\n * @public\n */\nexport type PermissionMessageBatch<T> = {\n items: IdentifiedPermissionMessage<T>[];\n};\n\n/**\n * The result of an authorization request.\n * @public\n */\nexport enum AuthorizeResult {\n /**\n * The authorization request is denied.\n */\n DENY = 'DENY',\n /**\n * The authorization request is allowed.\n */\n ALLOW = 'ALLOW',\n /**\n * The authorization request is allowed if the provided conditions are met.\n */\n CONDITIONAL = 'CONDITIONAL',\n}\n\n/**\n * A definitive decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.\n *\n * @remarks\n *\n * This indicates that the policy unconditionally allows (or denies) the request.\n *\n * @public\n */\nexport type DefinitivePolicyDecision = {\n result: AuthorizeResult.ALLOW | AuthorizeResult.DENY;\n};\n\n/**\n * A conditional decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.\n *\n * @remarks\n *\n * This indicates that the policy allows authorization for the request, given that the returned\n * conditions hold when evaluated. The conditions will be evaluated by the corresponding plugin\n * which knows about the referenced permission rules.\n *\n * @public\n */\nexport type ConditionalPolicyDecision = {\n result: AuthorizeResult.CONDITIONAL;\n pluginId: string;\n resourceType: string;\n conditions: PermissionCriteria<PermissionCondition>;\n};\n\n/**\n * A decision returned by the {@link @backstage/plugin-permission-node#PermissionPolicy}.\n *\n * @public\n */\nexport type PolicyDecision =\n | DefinitivePolicyDecision\n | ConditionalPolicyDecision;\n\n/**\n * A condition returned with a CONDITIONAL authorization response.\n *\n * Conditions are a reference to a rule defined by a plugin, and parameters to apply the rule. For\n * example, a rule might be `isOwner` from the catalog-backend, and params may be a list of entity\n * claims from a identity token.\n * @public\n */\nexport type PermissionCondition<\n TResourceType extends string = string,\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = {\n resourceType: TResourceType;\n rule: string;\n params?: TParams;\n};\n\n/**\n * Utility type to represent an array with 1 or more elements.\n * @ignore\n */\ntype NonEmptyArray<T> = [T, ...T[]];\n\n/**\n * Represents a logical AND for the provided criteria.\n * @public\n */\nexport type AllOfCriteria<TQuery> = {\n allOf: NonEmptyArray<PermissionCriteria<TQuery>>;\n};\n\n/**\n * Represents a logical OR for the provided criteria.\n * @public\n */\nexport type AnyOfCriteria<TQuery> = {\n anyOf: NonEmptyArray<PermissionCriteria<TQuery>>;\n};\n\n/**\n * Represents a negation of the provided criteria.\n * @public\n */\nexport type NotCriteria<TQuery> = {\n not: PermissionCriteria<TQuery>;\n};\n\n/**\n * Composes several {@link PermissionCondition}s as criteria with a nested AND/OR structure.\n * @public\n */\nexport type PermissionCriteria<TQuery> =\n | AllOfCriteria<TQuery>\n | AnyOfCriteria<TQuery>\n | NotCriteria<TQuery>\n | TQuery;\n\n/**\n * A parameter to a permission rule.\n *\n * @public\n */\nexport type PermissionRuleParam = undefined | JsonPrimitive | JsonPrimitive[];\n\n/**\n * Types that can be used as parameters to permission rules.\n *\n * @public\n */\nexport type PermissionRuleParams =\n | undefined\n | Record<string, PermissionRuleParam>;\n\n/**\n * An individual request sent to the permission backend.\n * @public\n */\nexport type EvaluatePermissionRequest = {\n permission: Permission;\n resourceRef?: string;\n};\n\n/**\n * A batch of requests sent to the permission backend.\n * @public\n */\nexport type EvaluatePermissionRequestBatch =\n PermissionMessageBatch<EvaluatePermissionRequest>;\n\n/**\n * An individual response from the permission backend.\n *\n * @remarks\n *\n * This response type is an alias of {@link PolicyDecision} to maintain separation between the\n * {@link @backstage/plugin-permission-node#PermissionPolicy} interface and the permission backend\n * api. They may diverge at some point in the future. The response\n *\n * @public\n */\nexport type EvaluatePermissionResponse = PolicyDecision;\n\n/**\n * A batch of responses from the permission backend.\n * @public\n */\nexport type EvaluatePermissionResponseBatch =\n PermissionMessageBatch<EvaluatePermissionResponse>;\n\n/**\n * Request object for {@link PermissionEvaluator.authorize}. If a {@link ResourcePermission}\n * is provided, it must include a corresponding `resourceRef`.\n * @public\n */\nexport type AuthorizePermissionRequest =\n | {\n permission: Exclude<Permission, ResourcePermission>;\n resourceRef?: never;\n }\n | { permission: ResourcePermission; resourceRef: string };\n\n/**\n * Response object for {@link PermissionEvaluator.authorize}.\n * @public\n */\nexport type AuthorizePermissionResponse = DefinitivePolicyDecision;\n\n/**\n * Request object for {@link PermissionEvaluator.authorizeConditional}.\n * @public\n */\nexport type QueryPermissionRequest = {\n permission: ResourcePermission;\n resourceRef?: never;\n};\n\n/**\n * Response object for {@link PermissionEvaluator.authorizeConditional}.\n * @public\n */\nexport type QueryPermissionResponse = PolicyDecision;\n\n/**\n * A client interacting with the permission backend can implement this evaluator interface.\n *\n * @public\n */\nexport interface PermissionEvaluator {\n /**\n * Evaluates {@link Permission | Permissions} and returns a definitive decision.\n */\n authorize(\n requests: AuthorizePermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<AuthorizePermissionResponse[]>;\n\n /**\n * Evaluates {@link ResourcePermission | ResourcePermissions} and returns both definitive and\n * conditional decisions, depending on the configured\n * {@link @backstage/plugin-permission-node#PermissionPolicy}. This method is useful when the\n * caller needs more control over the processing of conditional decisions. For example, a plugin\n * backend may want to use {@link PermissionCriteria | conditions} in a database query instead of\n * evaluating each resource in memory.\n */\n authorizeConditional(\n requests: QueryPermissionRequest[],\n options?: EvaluatorRequestOptions,\n ): Promise<QueryPermissionResponse[]>;\n}\n\n/**\n * Options for {@link PermissionEvaluator} requests.\n *\n * @public\n */\nexport type EvaluatorRequestOptions = {\n /**\n * @deprecated Backend plugins should no longer depend on the\n * `PermissionEvaluator`, but instead use the `PermissionService` from\n * `@backstage/backend-plugin-api`. Frontend plugins should not need to inject\n * this token at all, but instead implicitly rely on underlying fetchApi to do\n * it for them.\n */\n token?: string;\n};\n"],"names":["AuthorizeResult"],"mappings":"AAsCY,IAAA,eAAA,qBAAAA,gBAAL,KAAA;AAIL,EAAAA,iBAAA,MAAO,CAAA,GAAA,MAAA,CAAA;AAIP,EAAAA,iBAAA,OAAQ,CAAA,GAAA,OAAA,CAAA;AAIR,EAAAA,iBAAA,aAAc,CAAA,GAAA,aAAA,CAAA;AAZJ,EAAAA,OAAAA,gBAAAA,CAAAA;AAAA,CAAA,EAAA,eAAA,IAAA,EAAA;;;;"}
package/package.json CHANGED
@@ -1,9 +1,16 @@
1
1
  {
2
2
  "name": "@backstage/plugin-permission-common",
3
- "version": "0.7.13",
3
+ "version": "0.7.14",
4
4
  "description": "Isomorphic types and client for Backstage permissions and authorization",
5
5
  "backstage": {
6
- "role": "common-library"
6
+ "role": "common-library",
7
+ "pluginId": "permission",
8
+ "pluginPackages": [
9
+ "@backstage/plugin-permission-backend",
10
+ "@backstage/plugin-permission-common",
11
+ "@backstage/plugin-permission-node",
12
+ "@backstage/plugin-permission-react"
13
+ ]
7
14
  },
8
15
  "publishConfig": {
9
16
  "access": "public",
@@ -49,7 +56,7 @@
49
56
  "zod": "^3.22.4"
50
57
  },
51
58
  "devDependencies": {
52
- "@backstage/cli": "^0.26.0",
59
+ "@backstage/cli": "^0.26.7",
53
60
  "msw": "^1.0.0"
54
61
  },
55
62
  "configSchema": "config.d.ts",