Permission Management
This document provides a guide on managing graph-based access permissions on the cloud using a structure of architypes. Each user has their own root graph, and access between users' architypes is restricted by default.
Anchors vs Architypes
- Architypes are Jaclang class representation
- Anchors are database class representation
type | Anchors | Architypes |
---|---|---|
Node | NodeAnchor | NodeArchitype |
Edge | EdgeAnchor | EdgeArchitype |
Walker | WalkerAnchor | WalkerArchitype |
Object | ObjectAnchor | ObjectArchitype |
Root | NodeAnchor | Root(NodeArchitype) |
GenericEdge | EdgeAnchor | GenericEdge(EdgeArchitype) |
node Human {
has gender: str;
}
# DB NodeAnchor Representation
{
_id: ObjectId('6735b60656e82d6799dc9772'),
name: 'Human',
root: ObjectId('6735b5e456e82d6799dc976e'),
access: { all: 'NO_ACCESS', roots: { anchors: {} } },
edges: [ 'e::6735b60656e82d6799dc9775', 'e:Friend:6735b60656e82d6799dc9776' ],
# the actual NodeArchitype and it's context or `has attributes`
architype: {
gender: "boy"
},
}
edge Friend {
has best: bool;
}
# DB EdgeAnchor Representation
{
_id: ObjectId('6735b60656e82d6799dc9776'),
name: 'Friend',
root: ObjectId('6735b5e456e82d6799dc976e'),
access: { all: 'NO_ACCESS', roots: { anchors: {} } },
source: 'n:B:6735b60656e82d6799dc9771',
target: 'n:C:6735b60656e82d6799dc9772',
is_undirected: false
# the actual EdgeArchitype and it's context or `has attributes`
architype: {
best: true
},
}
Access Levels
NO_ACCESS
: No other user can access current architype.READ
: Other user have Read-Only access to current architype.CONNECT
: Other user's node can connect to current node.WRITE
: Other user can do anything to current architype.
Default User Graph Structure
In this setup, each user's architype (node, edge, walker) is isolated with default permissions as follows:
all
: Non specific access (Given to all users)roots
: Root specific access (specific to user)
Example Structure in DB perspective
Consider the following structure:
By default, User2
cannot access Node1
owns by Root1
. To allow User2
access to node1
, we need to explicitly add a permission mapping in Root2
.
Example of Granting Access
To grant READ
access to User2
for Node1
owns by Root1
, we modify Node1’s access permissions:
# Node1 is the architype
# Node1.__jac__ is the anchor
Node1.__jac__.access = {
"all": "READ",
"roots": {
"anchors": {}
}
}
User1
wants to give only READ
access to User2
, we set permissions as follows:
# Node1 is the architype
# Node1.__jac__ is the anchor
Node1.__jac__.access = {
"all": "NO_ACCESS",
"roots": {
"anchors": {
"n::123445673 User2's Root JID": "READ"
}
}
}
Permission Management Walkers
Consider this scenario:
Granting Access
To grant boy1
in User1
’s graph access to User2
, we can use a walker.
Granting Access in jac-lang
# Run the walker in user1
walker set_access {
has access: str; # "READ", "WRITE", "CONNECT"
has root_uuid: str;
can give_access with boy entry {
# here = boy1
Jac.allow_root(here, UUID(self.root_ref_jid), self.access);
}
}
Granting Access in jac-cloud
# Run the walker in user1
walker set_access {
has access: str; # "READ", "WRITE", "CONNECT"
has root_ref_jid: str;
can give_access with boy entry {
# here = boy1
Jac.allow_root(here, NodeAnchor.ref(self.root_ref_jid), self.access);
}
}
boy1.access = {
"all": "NO_ACCESS",
"roots": {
"anchors": {
"n::123445673 User2's Root JID": "READ"
}
}
}
Removing Access
To remove access, use the walker below.
Removing Access in jac-lang
# Run the walker in user1
walker remove_access {
has root_uuid: str;
can remove_access with boy entry {
# here = boy1
Jac.disallow_root(here, UUID(self.root_uuid));
}
}
Removing Access in jac-cloud
# Run the walker in user1
walker remove_access {
has root_ref_jid: str;
can remove_access with boy entry {
# here = boy1
Jac.disallow_root(here, NodeAnchor.ref(self.root_ref_jid));
}
}
Global Access Control
To grant read access to all, use the following syntax:
Equivalent structure:To remove access to all, use the following syntax:
Equivalent structure:Manual Access Management
In some cases, you may need to manually verify, filter, or update access permissions on nodes. The following Python examples demonstrate how to handle these tasks.
Checking Access Manually
To manually check access levels on a collection of nodes, you can use the following code. This script filters nodes by type and checks for READ
, WRITE
, and CONNECT
access permissions.
for nodeanchor in NodeArchitype.Collection.find(
{
"type": "<type of the node>",
"context.public": true
}
):
# Check read access
if not Jac.check_read_access(nodeanchor):
continue
# Check write access
if not Jac.check_write_access(nodeanchor):
continue
# Check connect access
if not Jac.check_connect_access(nodeanchor):
continue
Filtering Nodes by Type
To retrieve a specific node based on its type, use the following code snippet. This will find a node of the specified type that is also public in context.
node = NodeArchitype.Collection.find_one(
{
"type": "<type of the node>",
"context.public": true
}
)
Updating Access Permissions Manually
To manually update access permissions for multiple nodes, use the following code. This example sets the access.all
permission to CONNECT
for all nodes of a specific type that are publicly accessible.