There are a number of concepts that are currently loosely related to access control.
- Authorizations
- Sessions
- User Resource Mapping
The way that a request is currently authorized takes place in one of two ways
- We look up the authorization by the token provided, this authorization contains the set of all permissions that an authorization has.
- We put the authorization on context, and pass it down the chain of functions.
- Somewhere along that chain, we construct a permission and ask if the if the authorization allows the action.
- We look up the session by the key provided
- We grab the user off of the session and use the user resource mapping and resolve that to a set of permissions
- We put the session on context, and pass it down the chain of functions.
- Somewhere along that chain, we construct a permission and ask if the if the session allows the action.
While this sounds relatively straight forward, it has been relatively hard to express the model to others and in practice has lead to a bit of awkwardness in the implementation.
This awkwardness is the result of needing to look at the resource in order to authorize access. There are two main ways this manifests itself.
- when we are the
memberof an organization and we are only provided theidof the resource, we have to retrieve the resource to see if it belongs to the organization to authorize the action - when attempting to authorize
find many, we have to fetch all and construct a permission for each resource (filtering out results that aren't authorized)
Ideally, we should have an efficient way doing the following
- find all resources a user, or token, is authorized to see
- given an user, or token, and the ID of a resource determine if I'm authorized to access the resource.
I propose that we move to a system that is based on Access Control Lists (ACL). That is, instead of having a set of permissions that we move around and use for each request,
each resource in the system has an associated list that contains the IDs of each of entity that has access to the resource (where an entity is a user, org, or token).
This way, given a user, or token, and the resource id, we could check to see if the user was authorized to perform the action without ever needing to explicitly access
the resource.
In addition to the ACL, I propose we store an Inverse ACL (IACL), so that given a user, or token, we can look up all resources that it is authorized to see.
I belive this would roughly look like two indexes, similar to what User resource mappings look like today. Those two indexes would be
ACL index
(resource type)/id -> [(user || org || token)/id]
This would be used to detemine authorization of a resource given a resource type, resource id and user, or token, id.
Let rt = resource type and rid = resource id.
- For tokens, you simple check the existence of the key
rt/rid/tt/tid(wherett = token typeandtid = token id) - For users, you simple check the existence of the key
rt/rid/ut/uid(whereut = user typeanduid = user id). If that key does not exist then you scan acrossrt/rid/ot/*and for eachoidyou check to see ifot/oid/ut/uidexists. If no such key exists, the action will fail. This has worst case peformance of log linear (there are the initial log lookup + the log lookups for each org scan value) in the number of org entries.
Note: it's possible that there is only one case here, the specific implementation would depend a bit on requirements.
IACL index
(user || org || token)/id -> [(resource type)/id]
This would be used to find all resources of a particular type. Given rt = resource type the process would be as follows
- For tokens, you scan across
tt/tid/rt/*. This should produce the entire list of available resources. - For users, you scan across
ut/uid/ot/*for eachoidand union together the list ofot/oid/rt/*, and join that with all of the values forut/uid/rt/*. This will likely require a bit of deduping during the scan, but the operation should be efficient.
One thing that this would change is that tokens would now have an associated operation that takes place, where the token id is added to the list of each resource that the token grants permission to.
Additionally, we'd need a system that could resolve names to IDs (since this design works exclusively with IDs).
It should be noted that this model is functionally equivalent to a minimal role based access control model See the role based acces control document section on ACLg. This is possible since we can store the types of actions that a user, group, or token is allowed to perform as a value in the ACL.