This is a library to define an authorization policy. It is modeled after the authorize package, but I made my own for a simple reason:
- I wanted to exercise my Elixir skills and see what happened if I wrote my own
Compared to authorize, this library has a couple of additional features:
Authorizations return a justification.
The result of an
authorizecall is always a triple{result, rule, parameters}whereresultis:okor:error,rulespecifies the rule that made the decision, andparametersgives the input parameters for the decision and any additional values that the authorization rule chooses to include. The reason for this decision is to provide a self-contained context of the decision to enable historic auditing.Support authorization context.
Authorization rules can make use of a context parameter, for any ambient information that is not part of the (Subject, Object, Action) triple to be authorized.
Additionally, you can define fetcher functions to declare context values that can be fetched to implement your policy, for example group memberships of a user, if that information is not part of your user record.
Fetcher functions will only be invoked if the context value they fetch is not yet part of the context.
auval_office is available on Hex, so install it like this:
defdepsdo[# ...{:auval_office,"~> 0.1.0"}]Authorization happens in a policy module, which contains all the rules for a specific policy, and the associated fetchers:
defmoduleExample.PolicyuseAuvalOffice.Policy# To define a policy, list rules one after another.# Basic rule syntax is like this:rule:a_symbol_or_string_naming_the_rule,action,subject,objectdo# Allow the access, and stop evaluating further rules:ok# As above, but provide additional decision context (e.g. for building an audit trail){:ok,pigs: :learned_to_fly}# Disallow the access, and stop evaluating further rules:error# As above, but provide additional decision context (e.g. for building an audit trail){:error,moon: :was_not_in_the_seventh_house}# Make no decision, and evaluate further rules:nextend# Subject and object can be patterns, and bound names are available in the body of the rulerule:author_can_edit_blog_post,:edit,%User{id: id},%Post{author_id: author_id}doifauthor_id==iddo:okelse:nextendend# Rules can be guarded by a condition.# The rule will be skipped unless the condition is truerule:author_can_edit_blog_post_shorter_definition,:edit%User{id: id},%Post{author_id: author_id},when: id==author_id,do: :ok# Rules can refer to context by pattern matching, for example when additional information# has to be fetched in the course of evaluationrule:author_can_delete_blog_post_while_it_has_no_comments,:delete,%User{id: id},%Post{author_id},context: %{post_comments: 0}doifauthor_id==id,do: :ok,else: :nextend# To fetch the number of blog posts, use a fetcher.# You can match on subject, object, action and context.# As with rules, a guard clause can be given; the fetcher is skipped when the guard clause evaluates to false# Basic syntax:fetch:fetcher_id,:field_name,[parameter: pattern]do{:ok,value}# or {:error, error} to fail evaluationend# For example to fetch the number of blog post comments:fetch:blog_post_comment_count,:post_comments,object: %Post{id: id}do{:ok,BlogPost.count_comments()}endend