Let’s say an app needs different kinds of roles: admin, managers, sales, etc. Each role has different permissions. This is actually a very basic functionality in apps. We can use Wikipedia and all its roles (admin, mods, revs) as example.
So, how to implement this in SAFE?
Current SAFE API has 2 access control mechanisms: multi-signed ownership, and black/white lists. This unfortunately (imo), is not enough to implement the multi-roles and require some complex workarounds (as far as I can see).
Change “whitelist” and “owners” properties to not be a list of users anymore. Instead they will be a list of a list of users, or a list of “roles”. Here, each entry/role is a pointer to an MD that contains a list of users. Ex.: “owner: [admins, managers, sales]”, then we will have 3 MDs (named “admins”, “managers”, “sales”) containing a list of users each.
With this indirect reference I believe we can easily implement multi-role / hierarchical access.
In practical terms:
- Add 2 properties to MutableData: “owner_groups”, “whitelist_groups” (or replace the current “owner”/“whitelist”);
- Both properties are lists of mutable references;
- These mutables have a list of userIDs;
- Anyone in any “owner_groups” can do anything with the MD, except to remove an owner at its left side in the list.
- Ex.: owner_groups: [admins, mods, revs].
A “mod” user can do anything with the MD except to remove the “admins” entry from the “owner_groups” property (because it’s on its left side);
Example - An edit war on Wikipedia:
- User#1 creates a “car” article;
- App creates a MD:
- name: “wiki_car”;
- owners: [admins, mods, revs];
- whitelist: ;
- App creates an Immutable that contains the article’s contents and adds it in the MD;
- “Revs” MD:
- ownership: [admins, mods]
- whitelist: [mods]
- data: Rev#1, Rev#2, Rev#3
- “Mods” MD:
- ownership: [admins]
- whitelist: [admins]
- data: Mod#1, Mod#2
- “Admins” MD:
- ownership: [god]
- whitelist: [god]
- User#2 edits the article:
- New immutable is created and added into the “wiki_car” MD;
- As the “whitelist_group” is empty, network doesn’t need to do any additional checking;
An edit war starts between User#1 and User#2;
Rev#1 protects the article, allowing only other revs to change it:
- Update “wiki_car” MD:
- The network fetches all “owners” MDs of “wiki_car” and verifies that Rev#1 is there, allowing the operation;
User#2 tries to edit (add an immutable ref into the MD):
- The network fetch the “revs” MD that is in the “wiki_car” whitelist and forbids the update;
User#2 complains to another rev. He says it is unfair. Other revs accept the complain and decide to undo Rev#1 changes, but Rev#1 disagree and starts a edit war with others revs, which is against the rules;
Revs complain to a Mod;
Mod#1 “fires” Rev#1:
- Remove Rev#1 from “Revs” MD;
- Change “car” article’s whitelist to empty again, un-protecting it;
With this approach, is fairly easy to manage an hierarchy of roles, even if the app has thousands of users. Add an admin doesn’t require to update millions of articles, for example.
Network overhead: For each MD update, the network will need to fetch extra MDs (the ones in “whitelist_groups”). This means that the more whitelist_groups entries we have, slower the app will be for updates. Same thing applies when changing MD properties like ownership or the whitelist list: in this case, the network needs to fetch MDs listed in the ownership_group property. This can be a problem for the network, but consider the following:
- This only happens on UPDATEs, which cost money - possibly eliminating it as an attack vector;
- If still a problem, a solution could be to the network charge more (according to the amount of entries) or limit the number of entries (e.g. 5);
- By slowing down the app (due to the extra GETs on UPDATEs) will serve as a pressure to developers keep lists lean;
- Most cases will need only 1 entry in the whitelist. Even in a Wikipedia, with thousands of super-users, only needs to have 1 entry in the whitelist (the immediate superior);
- It’s not recursive: this method allows an hierarchy of permissions and power delegation, and only does a few predictable amount of requests (in most cases, only 1, and only when adding new items to the MD);
- Without an embedded “role control” mechanism, workarounds will be necessary, costing much more GETs to the network;
- The “Role” MD can have a special type, that the network can use to optimize this mechanism;
Decentralized apps: I used a current-internet-app example, but I do think this approach can be very useful when managing permissions in decentralized apps. For example, on a SafeTube protocol you can follow a “curator” group of people that works on a hierarchy of roles. Or you can decentralize permissions of your protocol based on a chain of trust.