Skip to content

Instantly share code, notes, and snippets.

@desa
Created February 4, 2019 19:27
Show Gist options
  • Select an option

  • Save desa/df6bf6cbfe12c869bfad20d1a6a18e00 to your computer and use it in GitHub Desktop.

Select an option

Save desa/df6bf6cbfe12c869bfad20d1a6a18e00 to your computer and use it in GitHub Desktop.
authz

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
  3. We put the session on context, and pass it down the chain of functions.
  4. 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
  2. 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)
  2. 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).

Note

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment