buddy.auth.accessrules

Access Rules system for ring based applications.

compile-access-rule

(compile-access-rule accessrule)

Receives an access rule and returns a compiled version of it.

The plain version of access rule consists of one hash-map with with :uri and :handler keys. :uri is a url match syntax that will be used for matching the url and :handler is a rule handler.

Little overview of aspect of access rules:

[{:uri "/foo"
  :handler user-access}
 {:uris ["/bar" "/baz"]
  :handler admin-access}]

The clout library (https://github.com/weavejester/clout) for matching the :uri.

It also has support for more advanced matching using plain regular expressions, which are matched against the full request uri:

[{:pattern #"^/foo$"
  :handler user-access}

An access rule can also match against certain HTTP methods, by using the :request-method option. :request-method can be a keyword or a set of keywords.

[{:pattern #"^/foo$"
  :handler user-access
  :request-method :get}

The compilation process consists in transforming the plain version into an optimized one in order to avoid unnecessary overhead to the request process time.

The compiled version of access rule has a very similar format with the plain one. The difference is that :handler is a compiled version, and :pattern or :uri is replaced by matcher function.

Little overview of aspect of compiled version of acces rule:

[{:matcher #<accessrules$compile_access_rule$fn__13092$fn__13095...>
  :handler #<accessrules$compile_rule_handler$fn__14040$fn__14043...>

compile-access-rules

(compile-access-rules accessrules)

Compile a list of access rules.

For more information, see the docstring of compile-access-rule function.

compile-rule-handler

(compile-rule-handler rule)

Receives a rule handler and returns a compiled version of it.

The compiled version of a rule handler consists of one function that accepts a request as first parameter and returns the result of the evaluation of it.

The rule can be a simple function or logical expression. Logical expression is expressed using a hashmap:

{:or [f1 f2]}
{:and [f1 f2]}

Logical expressions can be nested as deep as you want:

{:or [f1 {:and [f2 f3]}]}

The rule handler as unit of work, should return a success or error. success is a simple mark that means that handler passes the validation and error is a mark that means that rule does not pass the validation.

An error mark can return a ring response that will be returned to the http client or string message that will be passed to on-error handler if it exists, or returned as bad-request response with message as response body.

Example of success marks:

  • true
  • (success)

Example of error marks:

  • nil
  • false
  • (error "Error msg")
  • (error {:status 400 :body "Unauthorized"})

error

(error)(error v)

Function that returns a failure state from one access rule handler.

IRuleHandlerResponse

protocol

Abstraction for uniform handling of rule handler return values. It comes with default implementation for nil and boolean types.

members

get-value

(get-value _)

Get a handler response value.

success?

(success? _)

Check if a response is a success.

restrict

(restrict handler rule)

Like wrap-access-rules middleware but works as decorator. It is intended to be used with compojure routing library or similar. Example:

(defn login-ctrl [req] ...)
(defn admin-ctrl [req] ...)

(defroutes app
  (ANY "/login" [] login-ctrl)
  (GET "/admin" [] (restrict admin-ctrl {:handler admin-access ;; Mandatory
                                           :on-error my-reject-handler)

This decorator allows using the same access rules but without any url matching algorithm, however it has the disadvantage of accoupling your routers code with access rules.

success

(success)(success v)

Function that returns a success state from one access rule handler.

wrap-access-rules

(wrap-access-rules handler & [{:keys [policy rules], :or {policy :allow}, :as opts}])

A ring middleware that helps to define access rules for ring handler.

This is an example of access rules list that wrap-access-rules middleware expects:

[{:uri "/foo/*"
  :handler user-access}
 {:uri "/bar/*"
  :handler {:or [user-access admin-access]}}
 {:uri "/baz/*"
  :handler {:and [user-access {:or [admin-access operator-access]}]}}]

All access rules are evaluated in order and the process stops when a match is found.

See docstring of compile-rule-handler for documentation about rule handlers.