Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Access control
- There are a number of concepts that are currently loosely related to access control.
- 1. Authorizations
- 2. Sessions
- 3. User Resource Mapping
- The way that a request is currently authorized takes place in one of two ways
- ### Case 1. a token (part of an authorization) is provided
- 1. We look up the authorization by the token provided, this authorization contains the set of all permissions that an authorization has.
- 2. We put the authorization on context, and pass it down the chain of functions.
- 3. Somewhere along that chain, we construct a permission and ask if the if the authorization allows the action.
- ### Case 2. a session key is provided
- 1. We look up the session by the key provided
- 2. We grab the user off of the session and use the user resource mapping and resolve that to a set of permissions
- 2. We put the session on context, and pass it down the chain of functions.
- 3. 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.
- 1. when we are the `member` of an organization and we are only provided the `id` of the resource, we have to retrieve the resource to see if it belongs to the organization to authorize the action
- 1. 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
- 1. find all resources a user, or token, is authorized to see
- 2. given an user, or token, and the ID of a resource determine if I'm authorized to access the resource.
- ## Proposition
- 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`.
- 1. For tokens, you simple check the existence of the key `rt/rid/tt/tid` (where `tt = token type` and `tid = token id`)
- 1. For users, you simple check the existence of the key `rt/rid/ut/uid` (where `ut = user type` and `uid = user id`). If that key does not exist
- then you scan across `rt/rid/ot/*` and for each `oid` you check to see if `ot/oid/ut/uid` exists. 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
- 1. For tokens, you scan across `tt/tid/rt/*`. This should produce the entire list of available resources.
- 2. For users, you scan across `ut/uid/ot/*` for each `oid` and union together the list of `ot/oid/rt/*`, and join that with all of the values
- for `ut/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).
- ## The benefit
- The benefits would be the following
- 1. A simple authorization model that is easy to explain to other
- 2. No need to access a resource in order to know if the user is authorized to see it
- 3. Worst case log linear, in the number of org owners a resource has, authorization time (which should be fairly small since things currently only have a single org owner)
- 3. Returning list of authorized resources should be log lookup + linear in the number of resources
- 3. If performance becomes an issue, there is an obvious partitioning scheme we can do (by resource type)
Add Comment
Please, Sign In to add comment