diff --git a/packages/permission-common/api-report.md b/packages/permission-common/api-report.md index a88d50b083..159d61d4c8 100644 --- a/packages/permission-common/api-report.md +++ b/packages/permission-common/api-report.md @@ -37,33 +37,23 @@ export type DiscoveryApi = { }; // @public -export class Permission { - constructor( - name: string, - attributes: PermissionAttributes, - resourceType?: string | undefined, - ); - // (undocumented) - readonly attributes: PermissionAttributes; - // (undocumented) - static create({ name, attributes, resourceType }: PermissionJSON): Permission; - // (undocumented) - is(permission: Permission): boolean; - // (undocumented) - get isCreate(): boolean; - // (undocumented) - get isDelete(): boolean; - // (undocumented) - get isRead(): boolean; - // (undocumented) - get isUpdate(): boolean; - // (undocumented) - readonly name: string; - // (undocumented) - readonly resourceType?: string | undefined; - // (undocumented) - toJSON(): PermissionJSON; -} +export function isCreatePermission(permission: Permission): boolean; + +// @public +export function isDeletePermission(permission: Permission): boolean; + +// @public +export function isReadPermission(permission: Permission): boolean; + +// @public +export function isUpdatePermission(permission: Permission): boolean; + +// @public +export type Permission = { + name: string; + attributes: PermissionAttributes; + resourceType?: string; +}; // @public export enum PermissionAction { @@ -105,12 +95,8 @@ export type PermissionCriteria = | { anyOf: PermissionCriteria[]; } + | { + not: PermissionCriteria; + } | PermissionCondition; - -// @public -export type PermissionJSON = { - name: string; - attributes: PermissionAttributes; - resourceType?: string; -}; ``` diff --git a/packages/permission-common/src/Permission.ts b/packages/permission-common/src/Permission.ts deleted file mode 100644 index 83473c8beb..0000000000 --- a/packages/permission-common/src/Permission.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - PermissionAction, - PermissionAttributes, - PermissionJSON, -} from './types/permission'; - -/** - * A permission that can be checked through authorization. - * - * Permissions are the "what" part of authorization, the action to be performed. This may be reading - * an entity from the catalog, executing a software template, or any other action a plugin author - * may wish to protect. - * - * To evaluate authorization, a permission is paired with a Backstage identity (the "who") and - * evaluated using an authorization policy. - * @public - */ -export class Permission { - constructor( - readonly name: string, - readonly attributes: PermissionAttributes, - readonly resourceType?: string, - ) {} - - is(permission: Permission) { - return this.name === permission.name; - } - - get isCreate() { - return this.attributes.action === PermissionAction.Create; - } - - get isRead() { - return this.attributes.action === PermissionAction.Read; - } - - get isUpdate() { - return this.attributes.action === PermissionAction.Update; - } - - get isDelete() { - return this.attributes.action === PermissionAction.Delete; - } - - toJSON(): PermissionJSON { - return { - name: this.name, - attributes: this.attributes, - resourceType: this.resourceType, - }; - } - - static create({ - name, - attributes, - resourceType, - }: PermissionJSON): Permission { - return new Permission(name, attributes, resourceType); - } -} diff --git a/packages/permission-common/src/PermissionClient.test.ts b/packages/permission-common/src/PermissionClient.test.ts index d709cca28d..91ad16d24e 100644 --- a/packages/permission-common/src/PermissionClient.test.ts +++ b/packages/permission-common/src/PermissionClient.test.ts @@ -17,9 +17,9 @@ import { RestContext, rest } from 'msw'; import { setupServer } from 'msw/node'; import { PermissionClient } from './PermissionClient'; -import { AuthorizeResult, Identified, AuthorizeRequestJSON } from './types/api'; +import { AuthorizeRequest, AuthorizeResult, Identified } from './types/api'; import { DiscoveryApi } from './types/discovery'; -import { Permission } from './Permission'; +import { Permission } from './types/permission'; const server = setupServer(); const token = 'fake-token'; @@ -32,11 +32,11 @@ const discoveryApi: DiscoveryApi = { }; const client: PermissionClient = new PermissionClient({ discoveryApi }); -const mockPermission = Permission.create({ +const mockPermission: Permission = { name: 'test.permission', attributes: {}, resourceType: 'test-resource', -}); +}; const mockAuthorizeRequest = { permission: mockPermission, @@ -50,7 +50,7 @@ describe('PermissionClient', () => { describe('authorize', () => { const mockAuthorizeHandler = jest.fn((req, res, { json }: RestContext) => { - const responses = req.body.map((a: Identified) => ({ + const responses = req.body.map((a: Identified) => ({ id: a.id, result: AuthorizeResult.ALLOW, })); diff --git a/packages/permission-common/src/PermissionClient.ts b/packages/permission-common/src/PermissionClient.ts index acb23f3345..52fb0478ae 100644 --- a/packages/permission-common/src/PermissionClient.ts +++ b/packages/permission-common/src/PermissionClient.ts @@ -21,7 +21,6 @@ import { AuthorizeResult, AuthorizeRequest, AuthorizeResponse, - AuthorizeRequestJSON, Identified, } from './types/api'; import { DiscoveryApi } from './types/discovery'; @@ -65,11 +64,10 @@ export class PermissionClient { requests: AuthorizeRequest[], options?: AuthorizeRequestOptions, ): Promise { - const identifiedRequests: Identified[] = requests.map( + const identifiedRequests: Identified[] = requests.map( request => ({ id: uuid.v4(), - permission: request.permission.toJSON(), - resourceRef: request.resourceRef, + ...request, }), ); @@ -102,7 +100,7 @@ export class PermissionClient { } private assertValidResponses( - requests: Identified[], + requests: Identified[], json: any, ): asserts json is Identified[] { const responses = Array.isArray(json) ? json : []; diff --git a/packages/permission-common/src/index.ts b/packages/permission-common/src/index.ts index ca48218a9e..7c3f6dd613 100644 --- a/packages/permission-common/src/index.ts +++ b/packages/permission-common/src/index.ts @@ -20,5 +20,5 @@ * @packageDocumentation */ export * from './types'; -export * from './Permission'; +export * from './permissions'; export * from './PermissionClient'; diff --git a/packages/permission-common/src/permissions/index.ts b/packages/permission-common/src/permissions/index.ts new file mode 100644 index 0000000000..736d898539 --- /dev/null +++ b/packages/permission-common/src/permissions/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './util'; diff --git a/packages/permission-common/src/permissions/util.ts b/packages/permission-common/src/permissions/util.ts new file mode 100644 index 0000000000..06253755d5 --- /dev/null +++ b/packages/permission-common/src/permissions/util.ts @@ -0,0 +1,49 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Permission, PermissionAction } from '../types'; + +/** + * Check if a given permission is related to a create action. + * @public + */ +export function isCreatePermission(permission: Permission) { + return permission.attributes.action === PermissionAction.Create; +} + +/** + * Check if a given permission is related to a read action. + * @public + */ +export function isReadPermission(permission: Permission) { + return permission.attributes.action === PermissionAction.Read; +} + +/** + * Check if a given permission is related to an update action. + * @public + */ +export function isUpdatePermission(permission: Permission) { + return permission.attributes.action === PermissionAction.Update; +} + +/** + * Check if a given permission is related to a delete action. + * @public + */ +export function isDeletePermission(permission: Permission) { + return permission.attributes.action === PermissionAction.Delete; +} diff --git a/packages/permission-common/src/types/api.ts b/packages/permission-common/src/types/api.ts index 95d505bc16..9927f798d2 100644 --- a/packages/permission-common/src/types/api.ts +++ b/packages/permission-common/src/types/api.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import { Permission } from '../Permission'; -import { PermissionJSON } from './permission'; +import { Permission } from './permission'; export type Identified = T & { id: string }; @@ -47,11 +46,6 @@ export type AuthorizeRequest = { resourceRef?: string; }; -export type AuthorizeRequestJSON = { - permission: PermissionJSON; - resourceRef?: string; -}; - /** * A condition returned with a CONDITIONAL authorization response. * @@ -72,6 +66,7 @@ export type PermissionCondition = { export type PermissionCriteria = | { allOf: PermissionCriteria[] } | { anyOf: PermissionCriteria[] } + | { not: PermissionCriteria } | PermissionCondition; /** diff --git a/packages/permission-common/src/types/index.ts b/packages/permission-common/src/types/index.ts index bea3de4672..ef43666fa7 100644 --- a/packages/permission-common/src/types/index.ts +++ b/packages/permission-common/src/types/index.ts @@ -23,4 +23,4 @@ export type { } from './api'; export type { DiscoveryApi } from './discovery'; export { PermissionAction } from './permission'; -export type { PermissionAttributes, PermissionJSON } from './permission'; +export type { PermissionAttributes, Permission } from './permission'; diff --git a/packages/permission-common/src/types/permission.ts b/packages/permission-common/src/types/permission.ts index 97a6842fb7..6929bcd547 100644 --- a/packages/permission-common/src/types/permission.ts +++ b/packages/permission-common/src/types/permission.ts @@ -35,10 +35,17 @@ export type PermissionAttributes = { }; /** - * JSON serializable representation of a {@link Permission}. + * A permission that can be checked through authorization. + * + * Permissions are the "what" part of authorization, the action to be performed. This may be reading + * an entity from the catalog, executing a software template, or any other action a plugin author + * may wish to protect. + * + * To evaluate authorization, a permission is paired with a Backstage identity (the "who") and + * evaluated using an authorization policy. * @public */ -export type PermissionJSON = { +export type Permission = { name: string; attributes: PermissionAttributes; resourceType?: string;