Skip to content

Commit

Permalink
add support for authz APIs - MINOR RELEASE (#268)
Browse files Browse the repository at this point in the history
* add support for authz APIs

* missing files
  • Loading branch information
slavikm authored Oct 30, 2023
1 parent 87e63f2 commit a22d54d
Show file tree
Hide file tree
Showing 8 changed files with 1,145 additions and 7 deletions.
180 changes: 180 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Then, you can use that to work with the following functions:
9. [Manage JWTs](#manage-jwts)
10. [Embedded Links](#embedded-links)
11. [Search Audit](#search-audit)
12. [Manage Authz](#manage-authz)

If you wish to run any of our code samples and play with them, check out our [Code Examples](#code-examples) section.

Expand Down Expand Up @@ -840,6 +841,185 @@ const audits = await descopeClient.management.audit.search({ actions: ['LoginSuc
console.log(audits);
```

### Manage Authz

Descope support full relation based access control (ReBAC) using a zanzibar like schema and operations.
A schema is comprized of namespaces (entities like documents, folders, orgs, etc.) and each namespace has relation definitions to define relations.
Each relation definition can be simple (either you have it or not) or complex (union of nodes).

A simple example for a file system like schema would be:

```yaml
# Example schema for the authz tests
name: Files
namespaces:
- name: org
relationDefinitions:
- name: parent
- name: member
complexDefinition:
nType: union
children:
- nType: child
expression:
neType: self
- nType: child
expression:
neType: relationLeft
relationDefinition: parent
relationDefinitionNamespace: org
targetRelationDefinition: member
targetRelationDefinitionNamespace: org
- name: folder
relationDefinitions:
- name: parent
- name: owner
complexDefinition:
nType: union
children:
- nType: child
expression:
neType: self
- nType: child
expression:
neType: relationRight
relationDefinition: parent
relationDefinitionNamespace: folder
targetRelationDefinition: owner
targetRelationDefinitionNamespace: folder
- name: editor
complexDefinition:
nType: union
children:
- nType: child
expression:
neType: self
- nType: child
expression:
neType: relationRight
relationDefinition: parent
relationDefinitionNamespace: folder
targetRelationDefinition: editor
targetRelationDefinitionNamespace: folder
- nType: child
expression:
neType: targetSet
targetRelationDefinition: owner
targetRelationDefinitionNamespace: folder
- name: viewer
complexDefinition:
nType: union
children:
- nType: child
expression:
neType: self
- nType: child
expression:
neType: relationRight
relationDefinition: parent
relationDefinitionNamespace: folder
targetRelationDefinition: viewer
targetRelationDefinitionNamespace: folder
- nType: child
expression:
neType: targetSet
targetRelationDefinition: editor
targetRelationDefinitionNamespace: folder
- name: doc
relationDefinitions:
- name: parent
- name: owner
complexDefinition:
nType: union
children:
- nType: child
expression:
neType: self
- nType: child
expression:
neType: relationRight
relationDefinition: parent
relationDefinitionNamespace: doc
targetRelationDefinition: owner
targetRelationDefinitionNamespace: folder
- name: editor
complexDefinition:
nType: union
children:
- nType: child
expression:
neType: self
- nType: child
expression:
neType: relationRight
relationDefinition: parent
relationDefinitionNamespace: doc
targetRelationDefinition: editor
targetRelationDefinitionNamespace: folder
- nType: child
expression:
neType: targetSet
targetRelationDefinition: owner
targetRelationDefinitionNamespace: doc
- name: viewer
complexDefinition:
nType: union
children:
- nType: child
expression:
neType: self
- nType: child
expression:
neType: relationRight
relationDefinition: parent
relationDefinitionNamespace: doc
targetRelationDefinition: viewer
targetRelationDefinitionNamespace: folder
- nType: child
expression:
neType: targetSet
targetRelationDefinition: editor
targetRelationDefinitionNamespace: doc
```
Descope SDK allows you to fully manage the schema and relations as well as perform simple (and not so simple) checks regarding the existence of relations.
```typescript
// Load the existing schema
const s = await descopeClient.management.authz.loadSchema();
console.log(s);

// Save schema and make sure to remove all namespaces not listed
await descopeClient.management.authz.saveSchema(s, true);

// Create a relation between a resource and user
await descopeClient.management.authz.createRelations([
{
resource: 'some-doc',
relationDefinition: 'owner',
namespace: 'doc',
target: 'u1',
},
{
resource: 'some-doc',
relationDefinition: 'editor',
namespace: 'doc',
target: 'u2',
},
]);

// Check if target has the relevant relation
// The answer should be true because an owner is also a viewer
const q = await descopeClient.management.authz.hasRelations([
{
resource: 'some-doc',
relationDefinition: 'viewer',
namespace: 'doc',
target: 'u1',
},
]);
```

### Utils for your end to end (e2e) tests and integration tests

To ease your e2e tests, we exposed dedicated management methods,
Expand Down
14 changes: 7 additions & 7 deletions examples/managementCli/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

128 changes: 128 additions & 0 deletions examples/managementCli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,134 @@ program
handleSdkRes(await sdk.management.audit.search({ text }), option.output);
});

// authz
program
.command('authz-load-schema')
.description('Load and display the current schema')
.option('-o, --output <filename>', 'Output filename')
.action(async (option) => {
handleSdkRes(await sdk.management.authz.loadSchema(), option.output);
});

program
.command('authz-save-schema')
.description('Save the schema defined in the given file')
.option('-i, --input <filename>', 'Schema input filename')
.action(async (option) => {
const file = fs.readFileSync(option.input, 'utf8');
const s = JSON.parse(file);
handleSdkRes(await sdk.management.authz.saveSchema(s, true), undefined);
});

program
.command('authz-has-relation')
.description('Check if given target has relation for given resource')
.option('-r, --resource <resource>', 'The resource we are checking')
.option('-d, --relationDefinition <rd>', 'The relation definition name')
.option('-n, --namespace <ns>', 'The relation definition namespace')
.option('-t, --target <target>', 'The target we are checking')
.option('-o, --output <filename>', 'Output filename')
.action(async (option) => {
handleSdkRes(
await sdk.management.authz.hasRelations([
{
resource: option.resource,
relationDefinition: option.relationDefinition,
namespace: option.namespace,
target: option.target,
},
]),
option.output,
);
});

program
.command('authz-create-relation')
.description('Create a relation')
.option('-r, --resource <resource>', 'The resource for the relation')
.option('-d, --relationDefinition <rd>', 'The relation definition name')
.option('-n, --namespace <ns>', 'The relation definition namespace')
.option('-t, --target <target>', 'The target for the relation')
.action(async (option) => {
handleSdkRes(
await sdk.management.authz.createRelations([
{
resource: option.resource,
relationDefinition: option.relationDefinition,
namespace: option.namespace,
target: option.target,
},
]),
undefined,
);
});

program
.command('authz-delete-relation')
.description('Delete a relation')
.option('-r, --resource <resource>', 'The resource for the relation')
.option('-d, --relationDefinition <rd>', 'The relation definition name')
.option('-n, --namespace <ns>', 'The relation definition namespace')
.option('-t, --target <target>', 'The target for the relation')
.action(async (option) => {
handleSdkRes(
await sdk.management.authz.deleteRelations([
{
resource: option.resource,
relationDefinition: option.relationDefinition,
namespace: option.namespace,
target: option.target,
},
]),
undefined,
);
});

program
.command('authz-who-can-access')
.description('Display all relations for the given resource and rd')
.option('-r, --resource <resource>', 'The resource for the relation')
.option('-d, --relationDefinition <rd>', 'The relation definition name')
.option('-n, --namespace <ns>', 'The relation definition namespace')
.option('-o, --output <filename>', 'Output filename')
.action(async (option) => {
handleSdkRes(
await sdk.management.authz.whoCanAccess(
option.resource,
option.relationDefinition,
option.namespace,
),
option.output,
);
});

program
.command('authz-resource-relations')
.description('Load relations for the given resource')
.option('-r, --resource <resource>', 'The resource for the relations')
.option('-o, --output <filename>', 'Output filename')
.action(async (option) => {
handleSdkRes(await sdk.management.authz.resourceRelations(option.resource), option.output);
});

program
.command('authz-target-relations')
.description('Load relations for the given target')
.option('-t, --target <target>', 'The target for the relations')
.option('-o, --output <filename>', 'Output filename')
.action(async (option) => {
handleSdkRes(await sdk.management.authz.targetsRelations([option.target]), option.output);
});

program
.command('authz-target-access')
.description('Display all relations for the given target')
.argument('<target>', 'display all relations for given target')
.option('-o, --output <filename>', 'Output filename')
.action(async (target, option) => {
handleSdkRes(await sdk.management.authz.whatCanTargetAccess(target), option.output);
});

// *** Helper functions ***

function handleSdkRes(res: SdkResponse<any>, responseFile?: string) {
Expand Down
Loading

0 comments on commit a22d54d

Please sign in to comment.