@backstage/plugin-permission-common
Advanced tools
Comparing version 0.0.0-nightly-202201323044 to 0.0.0-nightly-202201921950
# @backstage/plugin-permission-common | ||
## 0.0.0-nightly-202201323044 | ||
## 0.0.0-nightly-202201921950 | ||
### Minor Changes | ||
- b768259244: **BREAKING**: Authorize API request and response types have been updated. The existing `AuthorizeRequest` and `AuthorizeResponse` types now match the entire request and response objects for the /authorize endpoint, and new types `AuthorizeQuery` and `AuthorizeDecision` have been introduced for individual items in the request and response batches respectively. | ||
**BREAKING**: PermissionClient has been updated to use the new request and response format in the latest version of @backstage/permission-backend. | ||
### Patch Changes | ||
- Updated dependencies | ||
- @backstage/config@0.0.0-nightly-202201323044 | ||
- @backstage/errors@0.0.0-nightly-202201323044 | ||
- @backstage/config@0.0.0-nightly-202201921950 | ||
## 0.4.0-next.0 | ||
### Minor Changes | ||
- b768259244: **BREAKING**: Authorize API request and response types have been updated. The existing `AuthorizeRequest` and `AuthorizeResponse` types now match the entire request and response objects for the /authorize endpoint, and new types `AuthorizeQuery` and `AuthorizeDecision` have been introduced for individual items in the request and response batches respectively. | ||
**BREAKING**: PermissionClient has been updated to use the new request and response format in the latest version of @backstage/permission-backend. | ||
### Patch Changes | ||
- Updated dependencies | ||
- @backstage/config@0.1.13-next.0 | ||
## 0.3.1 | ||
### Patch Changes | ||
- Updated dependencies | ||
- @backstage/config@0.1.12 | ||
- @backstage/errors@0.2.0 | ||
## 0.3.0 | ||
@@ -12,0 +38,0 @@ |
@@ -57,10 +57,12 @@ 'use strict'; | ||
}).or(zod.z.object({ anyOf: zod.z.array(permissionCriteriaSchema) })).or(zod.z.object({ allOf: zod.z.array(permissionCriteriaSchema) })).or(zod.z.object({ not: permissionCriteriaSchema }))); | ||
const responseSchema = zod.z.array(zod.z.object({ | ||
id: zod.z.string(), | ||
result: zod.z.literal(AuthorizeResult.ALLOW).or(zod.z.literal(AuthorizeResult.DENY)) | ||
}).or(zod.z.object({ | ||
id: zod.z.string(), | ||
result: zod.z.literal(AuthorizeResult.CONDITIONAL), | ||
conditions: permissionCriteriaSchema | ||
}))); | ||
const responseSchema = zod.z.object({ | ||
items: zod.z.array(zod.z.object({ | ||
id: zod.z.string(), | ||
result: zod.z.literal(AuthorizeResult.ALLOW).or(zod.z.literal(AuthorizeResult.DENY)) | ||
}).or(zod.z.object({ | ||
id: zod.z.string(), | ||
result: zod.z.literal(AuthorizeResult.CONDITIONAL), | ||
conditions: permissionCriteriaSchema | ||
}))) | ||
}); | ||
class PermissionClient { | ||
@@ -72,14 +74,16 @@ constructor(options) { | ||
} | ||
async authorize(requests, options) { | ||
async authorize(queries, options) { | ||
if (!this.enabled) { | ||
return requests.map((_) => ({ result: AuthorizeResult.ALLOW })); | ||
return queries.map((_) => ({ result: AuthorizeResult.ALLOW })); | ||
} | ||
const identifiedRequests = requests.map((request) => ({ | ||
id: uuid__namespace.v4(), | ||
...request | ||
})); | ||
const request = { | ||
items: queries.map((query) => ({ | ||
id: uuid__namespace.v4(), | ||
...query | ||
})) | ||
}; | ||
const permissionApi = await this.discovery.getBaseUrl("permission"); | ||
const response = await fetch__default["default"](`${permissionApi}/authorize`, { | ||
method: "POST", | ||
body: JSON.stringify(identifiedRequests), | ||
body: JSON.stringify(request), | ||
headers: { | ||
@@ -93,9 +97,9 @@ ...this.getAuthorizationHeader(options == null ? void 0 : options.token), | ||
} | ||
const identifiedResponses = await response.json(); | ||
this.assertValidResponses(identifiedRequests, identifiedResponses); | ||
const responsesById = identifiedResponses.reduce((acc, r) => { | ||
const responseBody = await response.json(); | ||
this.assertValidResponse(request, responseBody); | ||
const responsesById = responseBody.items.reduce((acc, r) => { | ||
acc[r.id] = r; | ||
return acc; | ||
}, {}); | ||
return identifiedRequests.map((request) => responsesById[request.id]); | ||
return request.items.map((query) => responsesById[query.id]); | ||
} | ||
@@ -105,6 +109,6 @@ getAuthorizationHeader(token) { | ||
} | ||
assertValidResponses(requests, json) { | ||
assertValidResponse(request, json) { | ||
const authorizedResponses = responseSchema.parse(json); | ||
const responseIds = authorizedResponses.map((r) => r.id); | ||
const hasAllRequestIds = requests.every((r) => responseIds.includes(r.id)); | ||
const responseIds = authorizedResponses.items.map((r) => r.id); | ||
const hasAllRequestIds = request.items.every((r) => responseIds.includes(r.id)); | ||
if (!hasAllRequestIds) { | ||
@@ -111,0 +115,0 @@ throw new Error("Unexpected authorization response from permission-backend"); |
@@ -32,3 +32,3 @@ import { Config } from '@backstage/config'; | ||
interface PermissionAuthorizer { | ||
authorize(requests: AuthorizeRequest[], options?: AuthorizeRequestOptions): Promise<AuthorizeResponse[]>; | ||
authorize(queries: AuthorizeQuery[], options?: AuthorizeRequestOptions): Promise<AuthorizeDecision[]>; | ||
} | ||
@@ -70,6 +70,6 @@ /** | ||
/** | ||
* An authorization request for {@link PermissionClient#authorize}. | ||
* An individual authorization request for {@link PermissionClient#authorize}. | ||
* @public | ||
*/ | ||
declare type AuthorizeRequest = { | ||
declare type AuthorizeQuery = { | ||
permission: Permission; | ||
@@ -79,2 +79,9 @@ resourceRef?: string; | ||
/** | ||
* A batch of authorization requests from {@link PermissionClient#authorize}. | ||
* @public | ||
*/ | ||
declare type AuthorizeRequest = { | ||
items: Identified<AuthorizeQuery>[]; | ||
}; | ||
/** | ||
* A condition returned with a CONDITIONAL authorization response. | ||
@@ -103,6 +110,6 @@ * | ||
/** | ||
* An authorization response from {@link PermissionClient#authorize}. | ||
* An individual authorization response from {@link PermissionClient#authorize}. | ||
* @public | ||
*/ | ||
declare type AuthorizeResponse = { | ||
declare type AuthorizeDecision = { | ||
result: AuthorizeResult.ALLOW | AuthorizeResult.DENY; | ||
@@ -113,2 +120,9 @@ } | { | ||
}; | ||
/** | ||
* A batch of authorization responses from {@link PermissionClient#authorize}. | ||
* @public | ||
*/ | ||
declare type AuthorizeResponse = { | ||
items: Identified<AuthorizeDecision>[]; | ||
}; | ||
@@ -172,7 +186,7 @@ /** | ||
*/ | ||
authorize(requests: AuthorizeRequest[], options?: AuthorizeRequestOptions): Promise<AuthorizeResponse[]>; | ||
authorize(queries: AuthorizeQuery[], options?: AuthorizeRequestOptions): Promise<AuthorizeDecision[]>; | ||
private getAuthorizationHeader; | ||
private assertValidResponses; | ||
private assertValidResponse; | ||
} | ||
export { AuthorizeRequest, AuthorizeRequestOptions, AuthorizeResponse, AuthorizeResult, DiscoveryApi, Identified, Permission, PermissionAttributes, PermissionAuthorizer, PermissionClient, PermissionCondition, PermissionCriteria, isCreatePermission, isDeletePermission, isReadPermission, isUpdatePermission }; | ||
export { AuthorizeDecision, AuthorizeQuery, AuthorizeRequest, AuthorizeRequestOptions, AuthorizeResponse, AuthorizeResult, DiscoveryApi, Identified, Permission, PermissionAttributes, PermissionAuthorizer, PermissionClient, PermissionCondition, PermissionCriteria, isCreatePermission, isDeletePermission, isReadPermission, isUpdatePermission }; |
@@ -30,10 +30,12 @@ import { ResponseError } from '@backstage/errors'; | ||
}).or(z.object({ anyOf: z.array(permissionCriteriaSchema) })).or(z.object({ allOf: z.array(permissionCriteriaSchema) })).or(z.object({ not: permissionCriteriaSchema }))); | ||
const responseSchema = z.array(z.object({ | ||
id: z.string(), | ||
result: z.literal(AuthorizeResult.ALLOW).or(z.literal(AuthorizeResult.DENY)) | ||
}).or(z.object({ | ||
id: z.string(), | ||
result: z.literal(AuthorizeResult.CONDITIONAL), | ||
conditions: permissionCriteriaSchema | ||
}))); | ||
const responseSchema = z.object({ | ||
items: z.array(z.object({ | ||
id: z.string(), | ||
result: z.literal(AuthorizeResult.ALLOW).or(z.literal(AuthorizeResult.DENY)) | ||
}).or(z.object({ | ||
id: z.string(), | ||
result: z.literal(AuthorizeResult.CONDITIONAL), | ||
conditions: permissionCriteriaSchema | ||
}))) | ||
}); | ||
class PermissionClient { | ||
@@ -45,14 +47,16 @@ constructor(options) { | ||
} | ||
async authorize(requests, options) { | ||
async authorize(queries, options) { | ||
if (!this.enabled) { | ||
return requests.map((_) => ({ result: AuthorizeResult.ALLOW })); | ||
return queries.map((_) => ({ result: AuthorizeResult.ALLOW })); | ||
} | ||
const identifiedRequests = requests.map((request) => ({ | ||
id: uuid.v4(), | ||
...request | ||
})); | ||
const request = { | ||
items: queries.map((query) => ({ | ||
id: uuid.v4(), | ||
...query | ||
})) | ||
}; | ||
const permissionApi = await this.discovery.getBaseUrl("permission"); | ||
const response = await fetch(`${permissionApi}/authorize`, { | ||
method: "POST", | ||
body: JSON.stringify(identifiedRequests), | ||
body: JSON.stringify(request), | ||
headers: { | ||
@@ -66,9 +70,9 @@ ...this.getAuthorizationHeader(options == null ? void 0 : options.token), | ||
} | ||
const identifiedResponses = await response.json(); | ||
this.assertValidResponses(identifiedRequests, identifiedResponses); | ||
const responsesById = identifiedResponses.reduce((acc, r) => { | ||
const responseBody = await response.json(); | ||
this.assertValidResponse(request, responseBody); | ||
const responsesById = responseBody.items.reduce((acc, r) => { | ||
acc[r.id] = r; | ||
return acc; | ||
}, {}); | ||
return identifiedRequests.map((request) => responsesById[request.id]); | ||
return request.items.map((query) => responsesById[query.id]); | ||
} | ||
@@ -78,6 +82,6 @@ getAuthorizationHeader(token) { | ||
} | ||
assertValidResponses(requests, json) { | ||
assertValidResponse(request, json) { | ||
const authorizedResponses = responseSchema.parse(json); | ||
const responseIds = authorizedResponses.map((r) => r.id); | ||
const hasAllRequestIds = requests.every((r) => responseIds.includes(r.id)); | ||
const responseIds = authorizedResponses.items.map((r) => r.id); | ||
const hasAllRequestIds = request.items.every((r) => responseIds.includes(r.id)); | ||
if (!hasAllRequestIds) { | ||
@@ -84,0 +88,0 @@ throw new Error("Unexpected authorization response from permission-backend"); |
{ | ||
"name": "@backstage/plugin-permission-common", | ||
"description": "Isomorphic types and client for Backstage permissions and authorization", | ||
"version": "0.0.0-nightly-202201323044", | ||
"version": "0.0.0-nightly-202201921950", | ||
"main": "dist/index.cjs.js", | ||
@@ -41,4 +41,4 @@ "types": "dist/index.d.ts", | ||
"dependencies": { | ||
"@backstage/config": "^0.0.0-nightly-202201323044", | ||
"@backstage/errors": "^0.0.0-nightly-202201323044", | ||
"@backstage/config": "^0.0.0-nightly-202201921950", | ||
"@backstage/errors": "^0.2.0", | ||
"cross-fetch": "^3.0.6", | ||
@@ -49,3 +49,3 @@ "uuid": "^8.0.0", | ||
"devDependencies": { | ||
"@backstage/cli": "^0.0.0-nightly-202201323044", | ||
"@backstage/cli": "^0.0.0-nightly-202201921950", | ||
"@types/jest": "^26.0.7", | ||
@@ -52,0 +52,0 @@ "msw": "^0.35.0" |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
41918
406
17
19
89
+ Added@backstage/errors@0.2.2(transitive)
+ Added@backstage/types@0.1.3(transitive)
Updated@backstage/errors@^0.2.0