Base permissions engine data structures

Actions and objects

class tutelary.engine.Action(s)

Actions are represented by period-separated sequences of elements (e.g. parcel.edit, admin.assign-role) with wildcard elements indicated by * (e.g. party.*). A list of registered actions is maintained to support permissions set queries to find the set of actions that are permitted on a specified object pattern.

register(action)

Action registration is used to support generating lists of permitted actions from a permission set and an object pattern. Only registered actions will be returned by such queries.

class tutelary.engine.Object(s)

Objects are represented by slash-separated sequences of elements (e.g. Cadasta/Batangas/parcel/123, H4H/PaP/party/118) with wildcard elements indicated by * (e.g. Cadasta/*/parcel/*). Slashes can be backslash-escaped, as can backslashes (e.g. Cadasta/Village-X\/Y/parcel/943).

Policies

class tutelary.engine.PolicyBody(json, variables=None)

A policy body is just a sequence of clauses, possibly with a name. Conversion to and from JSON representations (with canonicalisation), and hash generation from the canonical representation.

Can be composed into permission sets, so for convenience allow for iteration over individual (action, object) pairs (note that each clause can have multiple actions and objects).

class tutelary.engine.Clause(effect=None, act=None, obj=None, dict=None)

A clause is a simple container for an effect (“allow” or “deny”) and a list of non-overlapping action patterns and non-overlapping object patterns to which the effect applies. (The patterns must be non-overlapping because there is no ordering imposed between the different action/object combinations within a clause. Overlapping patterns are thus potentially ambiguous.)

Permission trees

class tutelary.engine.PermissionTree(policies=None, json=None)

A permission tree records, in a compact way, the permissions associated with a sequence of policy clauses. The construction of permission trees handles the overriding of earlier clauses by later clauses and the treatment of wildcards in the action and object patterns for individual policy clauses.

Can:
  • Create empty permissions trees.
  • Compose statements and policies into a permission tree.
  • Test an (action, object) pair against a permission tree.
  • Determine the list of allowed actions for an object pattern from a permission tree.

Most of the functionality needed here is implemented in the WildTree class.

add(effect=None, act=None, obj=None, policy=None, policies=None)

Insert an individual (effect, action, object) triple or all triples for a policy or list of policies.

allow(act, obj=None)

Determine where a given action on a given object is allowed.

permitted_actions(obj=None)

Determine permitted actions for a given object pattern.

WildTree

class tutelary.wildtree.WildTree(json=None)

Data structure for mapping between segmented paths (e.g. a/b/c/d) and values, allowing for wildcards (e.g. a/*/c/*), where later key path insertions override earlier ones.

Provides JSON serialisation (via to_json()) and deserialisation (via constructor).

__contains__(key)

Exact path membership: wildcards must be matched explicitly.

__delitem__(key)

Key deletion: wildcards must be matched explicitly.

__getitem__(key)

Key lookup with wildcards.

__init__(json=None)

By default, all new WildTree objects are empty. They can also be deserialised from a JSON representation. We store the optional value at the endpoint of the path to this node, plus a list of subtrees. Each subtree is a pair whose first element is a key value (which may be a * wildcard) and whose second element is a WildTree.

__iter__()

Iterate over keys in the tree in “domination order”.

__len__()

Effective number of keys in the tree. Note that inserting keys that override other keys leads to the overridden keys being purged from the tree, so the key count does not necessarily increase monotonically as keys are inserted.

__setitem__(key, value)

Insert a new key path, potentially overriding and hence purging existing key paths.

__weakref__

list of weak references to the object (if defined)

find(key, perfect=False)

Find a key path in the tree, matching wildcards. Return value for key, along with index path through subtree lists to the result. Throw KeyError if the key path doesn’t exist in the tree.

to_json()

Serialisation to JSON.

tutelary.wildtree.dominates(p, q)

Test for path domination. An individual path element a dominates another path element b, written as a >= b if either a == b or a is a wild card. A path p = p1, p2, …, pn dominates another path q = q1, q2, …, qm if n == m and, for all i, pi >= qi.