Skip to content

Commit a22d54d

Browse files
authored
add support for authz APIs - MINOR RELEASE (#268)
* add support for authz APIs * missing files
1 parent 87e63f2 commit a22d54d

File tree

8 files changed

+1145
-7
lines changed

8 files changed

+1145
-7
lines changed

README.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ Then, you can use that to work with the following functions:
7272
9. [Manage JWTs](#manage-jwts)
7373
10. [Embedded Links](#embedded-links)
7474
11. [Search Audit](#search-audit)
75+
12. [Manage Authz](#manage-authz)
7576

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

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

844+
### Manage Authz
845+
846+
Descope support full relation based access control (ReBAC) using a zanzibar like schema and operations.
847+
A schema is comprized of namespaces (entities like documents, folders, orgs, etc.) and each namespace has relation definitions to define relations.
848+
Each relation definition can be simple (either you have it or not) or complex (union of nodes).
849+
850+
A simple example for a file system like schema would be:
851+
852+
```yaml
853+
# Example schema for the authz tests
854+
name: Files
855+
namespaces:
856+
- name: org
857+
relationDefinitions:
858+
- name: parent
859+
- name: member
860+
complexDefinition:
861+
nType: union
862+
children:
863+
- nType: child
864+
expression:
865+
neType: self
866+
- nType: child
867+
expression:
868+
neType: relationLeft
869+
relationDefinition: parent
870+
relationDefinitionNamespace: org
871+
targetRelationDefinition: member
872+
targetRelationDefinitionNamespace: org
873+
- name: folder
874+
relationDefinitions:
875+
- name: parent
876+
- name: owner
877+
complexDefinition:
878+
nType: union
879+
children:
880+
- nType: child
881+
expression:
882+
neType: self
883+
- nType: child
884+
expression:
885+
neType: relationRight
886+
relationDefinition: parent
887+
relationDefinitionNamespace: folder
888+
targetRelationDefinition: owner
889+
targetRelationDefinitionNamespace: folder
890+
- name: editor
891+
complexDefinition:
892+
nType: union
893+
children:
894+
- nType: child
895+
expression:
896+
neType: self
897+
- nType: child
898+
expression:
899+
neType: relationRight
900+
relationDefinition: parent
901+
relationDefinitionNamespace: folder
902+
targetRelationDefinition: editor
903+
targetRelationDefinitionNamespace: folder
904+
- nType: child
905+
expression:
906+
neType: targetSet
907+
targetRelationDefinition: owner
908+
targetRelationDefinitionNamespace: folder
909+
- name: viewer
910+
complexDefinition:
911+
nType: union
912+
children:
913+
- nType: child
914+
expression:
915+
neType: self
916+
- nType: child
917+
expression:
918+
neType: relationRight
919+
relationDefinition: parent
920+
relationDefinitionNamespace: folder
921+
targetRelationDefinition: viewer
922+
targetRelationDefinitionNamespace: folder
923+
- nType: child
924+
expression:
925+
neType: targetSet
926+
targetRelationDefinition: editor
927+
targetRelationDefinitionNamespace: folder
928+
- name: doc
929+
relationDefinitions:
930+
- name: parent
931+
- name: owner
932+
complexDefinition:
933+
nType: union
934+
children:
935+
- nType: child
936+
expression:
937+
neType: self
938+
- nType: child
939+
expression:
940+
neType: relationRight
941+
relationDefinition: parent
942+
relationDefinitionNamespace: doc
943+
targetRelationDefinition: owner
944+
targetRelationDefinitionNamespace: folder
945+
- name: editor
946+
complexDefinition:
947+
nType: union
948+
children:
949+
- nType: child
950+
expression:
951+
neType: self
952+
- nType: child
953+
expression:
954+
neType: relationRight
955+
relationDefinition: parent
956+
relationDefinitionNamespace: doc
957+
targetRelationDefinition: editor
958+
targetRelationDefinitionNamespace: folder
959+
- nType: child
960+
expression:
961+
neType: targetSet
962+
targetRelationDefinition: owner
963+
targetRelationDefinitionNamespace: doc
964+
- name: viewer
965+
complexDefinition:
966+
nType: union
967+
children:
968+
- nType: child
969+
expression:
970+
neType: self
971+
- nType: child
972+
expression:
973+
neType: relationRight
974+
relationDefinition: parent
975+
relationDefinitionNamespace: doc
976+
targetRelationDefinition: viewer
977+
targetRelationDefinitionNamespace: folder
978+
- nType: child
979+
expression:
980+
neType: targetSet
981+
targetRelationDefinition: editor
982+
targetRelationDefinitionNamespace: doc
983+
```
984+
985+
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.
986+
987+
```typescript
988+
// Load the existing schema
989+
const s = await descopeClient.management.authz.loadSchema();
990+
console.log(s);
991+
992+
// Save schema and make sure to remove all namespaces not listed
993+
await descopeClient.management.authz.saveSchema(s, true);
994+
995+
// Create a relation between a resource and user
996+
await descopeClient.management.authz.createRelations([
997+
{
998+
resource: 'some-doc',
999+
relationDefinition: 'owner',
1000+
namespace: 'doc',
1001+
target: 'u1',
1002+
},
1003+
{
1004+
resource: 'some-doc',
1005+
relationDefinition: 'editor',
1006+
namespace: 'doc',
1007+
target: 'u2',
1008+
},
1009+
]);
1010+
1011+
// Check if target has the relevant relation
1012+
// The answer should be true because an owner is also a viewer
1013+
const q = await descopeClient.management.authz.hasRelations([
1014+
{
1015+
resource: 'some-doc',
1016+
relationDefinition: 'viewer',
1017+
namespace: 'doc',
1018+
target: 'u1',
1019+
},
1020+
]);
1021+
```
1022+
8431023
### Utils for your end to end (e2e) tests and integration tests
8441024

8451025
To ease your e2e tests, we exposed dedicated management methods,

examples/managementCli/package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/managementCli/src/index.ts

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,134 @@ program
507507
handleSdkRes(await sdk.management.audit.search({ text }), option.output);
508508
});
509509

510+
// authz
511+
program
512+
.command('authz-load-schema')
513+
.description('Load and display the current schema')
514+
.option('-o, --output <filename>', 'Output filename')
515+
.action(async (option) => {
516+
handleSdkRes(await sdk.management.authz.loadSchema(), option.output);
517+
});
518+
519+
program
520+
.command('authz-save-schema')
521+
.description('Save the schema defined in the given file')
522+
.option('-i, --input <filename>', 'Schema input filename')
523+
.action(async (option) => {
524+
const file = fs.readFileSync(option.input, 'utf8');
525+
const s = JSON.parse(file);
526+
handleSdkRes(await sdk.management.authz.saveSchema(s, true), undefined);
527+
});
528+
529+
program
530+
.command('authz-has-relation')
531+
.description('Check if given target has relation for given resource')
532+
.option('-r, --resource <resource>', 'The resource we are checking')
533+
.option('-d, --relationDefinition <rd>', 'The relation definition name')
534+
.option('-n, --namespace <ns>', 'The relation definition namespace')
535+
.option('-t, --target <target>', 'The target we are checking')
536+
.option('-o, --output <filename>', 'Output filename')
537+
.action(async (option) => {
538+
handleSdkRes(
539+
await sdk.management.authz.hasRelations([
540+
{
541+
resource: option.resource,
542+
relationDefinition: option.relationDefinition,
543+
namespace: option.namespace,
544+
target: option.target,
545+
},
546+
]),
547+
option.output,
548+
);
549+
});
550+
551+
program
552+
.command('authz-create-relation')
553+
.description('Create a relation')
554+
.option('-r, --resource <resource>', 'The resource for the relation')
555+
.option('-d, --relationDefinition <rd>', 'The relation definition name')
556+
.option('-n, --namespace <ns>', 'The relation definition namespace')
557+
.option('-t, --target <target>', 'The target for the relation')
558+
.action(async (option) => {
559+
handleSdkRes(
560+
await sdk.management.authz.createRelations([
561+
{
562+
resource: option.resource,
563+
relationDefinition: option.relationDefinition,
564+
namespace: option.namespace,
565+
target: option.target,
566+
},
567+
]),
568+
undefined,
569+
);
570+
});
571+
572+
program
573+
.command('authz-delete-relation')
574+
.description('Delete a relation')
575+
.option('-r, --resource <resource>', 'The resource for the relation')
576+
.option('-d, --relationDefinition <rd>', 'The relation definition name')
577+
.option('-n, --namespace <ns>', 'The relation definition namespace')
578+
.option('-t, --target <target>', 'The target for the relation')
579+
.action(async (option) => {
580+
handleSdkRes(
581+
await sdk.management.authz.deleteRelations([
582+
{
583+
resource: option.resource,
584+
relationDefinition: option.relationDefinition,
585+
namespace: option.namespace,
586+
target: option.target,
587+
},
588+
]),
589+
undefined,
590+
);
591+
});
592+
593+
program
594+
.command('authz-who-can-access')
595+
.description('Display all relations for the given resource and rd')
596+
.option('-r, --resource <resource>', 'The resource for the relation')
597+
.option('-d, --relationDefinition <rd>', 'The relation definition name')
598+
.option('-n, --namespace <ns>', 'The relation definition namespace')
599+
.option('-o, --output <filename>', 'Output filename')
600+
.action(async (option) => {
601+
handleSdkRes(
602+
await sdk.management.authz.whoCanAccess(
603+
option.resource,
604+
option.relationDefinition,
605+
option.namespace,
606+
),
607+
option.output,
608+
);
609+
});
610+
611+
program
612+
.command('authz-resource-relations')
613+
.description('Load relations for the given resource')
614+
.option('-r, --resource <resource>', 'The resource for the relations')
615+
.option('-o, --output <filename>', 'Output filename')
616+
.action(async (option) => {
617+
handleSdkRes(await sdk.management.authz.resourceRelations(option.resource), option.output);
618+
});
619+
620+
program
621+
.command('authz-target-relations')
622+
.description('Load relations for the given target')
623+
.option('-t, --target <target>', 'The target for the relations')
624+
.option('-o, --output <filename>', 'Output filename')
625+
.action(async (option) => {
626+
handleSdkRes(await sdk.management.authz.targetsRelations([option.target]), option.output);
627+
});
628+
629+
program
630+
.command('authz-target-access')
631+
.description('Display all relations for the given target')
632+
.argument('<target>', 'display all relations for given target')
633+
.option('-o, --output <filename>', 'Output filename')
634+
.action(async (target, option) => {
635+
handleSdkRes(await sdk.management.authz.whatCanTargetAccess(target), option.output);
636+
});
637+
510638
// *** Helper functions ***
511639

512640
function handleSdkRes(res: SdkResponse<any>, responseFile?: string) {

0 commit comments

Comments
 (0)