Add documentation about package api conventions for permissions

Signed-off-by: Joe Porpeglia <josephp@spotify.com>
This commit is contained in:
Joe Porpeglia
2022-04-27 18:58:42 -04:00
committed by Joon Park
parent 1cbab91f6d
commit d039fb44a7
3 changed files with 41 additions and 21 deletions
@@ -26,7 +26,7 @@ Let's navigate to the file `plugins/todo-list-common/src/permissions.ts` and add
});
```
For this tutorial, we've automatically exported all permissions from this file (see `plugins/todo-list-common/src/index.ts`). For the actual plugins that you author, you must export any permission authorized by the plugin so Backstage integrators can import them when writing policies.
> Note: All permissions authorized by your plugin should be exported from a ["common-library" package](https://backstage.io/docs/local-dev/cli-build-system#package-roles). This allows Backstage integrators to reference them in frontend components and permission policies.
## Authorizing using the new permission
@@ -83,7 +83,7 @@ import { makeCreatePermissionRule } from '@backstage/plugin-permission-node';
import { TODO_LIST_RESOURCE_TYPE } from '@internal/plugin-todo-list-common';
import { Todo, TodoFilter } from './todos';
const createTodoListPermissionRule = makeCreatePermissionRule<
export const createTodoListPermissionRule = makeCreatePermissionRule<
Todo,
TodoFilter
>();
@@ -108,6 +108,8 @@ export const rules = { isOwner };
`makeCreatePermissionRule` is a helper used to ensure that rules created for this plugin use consistent types for the resource and query.
> Note: To support custom rules defined by Backstage integrators, you must export `createTodoListPermissionRule` from the backend package and provide some way for custom rules to be passed in before the backend starts, likely via `createRouter`.
We have created a new `isOwner` rule, which is going to be automatically used by the permission framework whenever a conditional response is returned in response to an authorized request with an attached `resourceRef`.
Specifically, the `apply` function is used to understand whether the passed resource should be authorized or not.
@@ -149,9 +151,33 @@ Now, let's create the new endpoint by editing `plugins/todo-list-backend/src/ser
router.post('/todos', async (req, res) => {
```
## Provide utilities for policy authors
Now that we have a new resource type and a corresponding rule, we need to export some utilities for policy authors to reference them.
Create a new `plugins/todo-list-backend/src/conditionExports.ts` file and add the following code:
```typescript
import { TODO_LIST_RESOURCE_TYPE } from '@internal/plugin-todo-list-common';
import { createConditionExports } from '@backstage/plugin-permission-node';
import { permissionRules } from './service/rules';
const { conditions, createConditionalDecision } = createConditionExports({
pluginId: 'catalog',
resourceType: RESOURCE_TYPE_CATALOG_ENTITY,
rules: permissionRules,
});
export const todoListConditions = conditions;
export const createTodoListConditionalDecision = createConditionalDecision;
```
Make sure `todoListConditions` and `createTodoListConditionalDecision` are exported from the `todo-list-backend` package.
## Test the authorized update endpoint
Now let's go back to the permission policy's handle function and try to authorize our new permission.
Let's go back to the permission policy's handle function and try to authorize our new permission with an `isOwner` condition.
```diff
// packages/backend/src/plugins/permission.ts
@@ -171,6 +197,10 @@ Now let's go back to the permission policy's handle function and try to authoriz
+ todoListUpdate,
+ TODO_LIST_RESOURCE_TYPE,
+ } from '@internal/plugin-todo-list-common';
+ import {
+ todoListConditions,
+ createTodoListConditionalDecision,
+ } from '@internal/plugin-todo-list-backend';
...
@@ -181,15 +211,10 @@ Now let's go back to the permission policy's handle function and try to authoriz
}
+ if (isPermission(request.permission, todoListUpdate)) {
+ return {
+ result: AuthorizeResult.CONDITIONAL,
+ pluginId: 'todolist',
+ resourceType: TODO_LIST_RESOURCE_TYPE,
+ conditions: {
+ rule: 'IS_OWNER',
+ params: [user?.identity.userEntityRef],
+ },
+ };
+ return createTodoListConditionalDecision(
+ request.permission,
+ todoListConditions.isOwner(user?.identity.userEntityRef),
+ );
+ }
+
return {
@@ -139,15 +139,10 @@ import {
+ isPermission(request.permission, todoListUpdate) ||
+ isPermission(request.permission, todoListRead)
+ ) {
return {
result: AuthorizeResult.CONDITIONAL,
pluginId: 'todolist',
resourceType: TODO_LIST_RESOURCE_TYPE,
conditions: {
rule: 'IS_OWNER',
params: [user?.identity.userEntityRef],
},
};
return createTodoListConditionalDecision(
request.permission,
todoListConditions.isOwner(user?.identity.userEntityRef),
);
}
```