amelinium.http.middleware.roles

added in 1.0.0

amelinium service, role-based access control middleware.

description

(description config role)

filter-in-context

(filter-in-context req)(filter-in-context context roles config)

Filters roles map by the given context, merging-in global roles when needed. Returns a set of roles matching the context or nil.

force-context

(force-context req context)(force-context req context self-role?)

Forces different context by setting :roles/context and recalculating :roles/in-context in the given request map req.

get-req-context

(get-req-context req)(get-req-context req config)(get-req-context req config req-context-path)

Gets context from a request using a key path.

get-req-self

(get-req-self req)(get-req-self req config)(get-req-self req config self-role self-path self-check-path)

Gets a value from the given request map (req) located under a (possibly nested) key(s) specified by a sequential collection self-path and compares it with a value obtained from the same req map identified by self-check-path. If the values are equal, it returns self-role. Otherwise it returns nil. If the first obtained value is truthy (not nil and not false) but the second path (self-check-path) is not specified (is nil or false), then the value of self-role is also returned.

get-roles-for-user-id

(get-roles-for-user-id config user-id)(get-roles-for-user-id config user-id handler-fn)(get-roles-for-user-id config user-id handler-fn global-context anonymous-role)

Retrieves all roles for the given user ID and returns them as a map where keys are contexts (expressed as keywords) and values are sets of roles assigned to those contexts.

If the user ID is nil or false, it returns a map with a global context and just one, anonymous role assigned to it within a set. If there is no anonymous role passed as an argument, returns nil.

Self-role is not included, even if it is configured, since it’s highly conditioned and may depend on data from the request or an external data source.

get-roles-from-session

(get-roles-from-session config session)(get-roles-from-session config session handler-fn)(get-roles-from-session config session handler-fn global-context anonymous-role known-user-role)

Uses the given session map session to obtain current user’s ID and then calls handler-fn with that user ID to obtain user’s roles.

If the ID cannot be obtained from a session, anonymous role is added (if it is configured).

If the ID can be obtained from a session but the session is marked as invalid, a special known-user role is added (if it is configured) so it is possible to identify users with expired or broken sessions visiting the service.

handler

(handler user-id config)(handler user-id config query-roles-fn known-roles login-role global-context context-column keep-unknown?)

Processes RBAC information by taking user-id and configuration options.

inject-roles

(inject-roles req)(inject-roles req {:keys [config processor req-context-fn req-self-role-fn anonymous-role known-user-role self-role global-context authorize-default? session-key], :or {authorize-default? true}, :as config})(inject-roles req config processor rcfn srfn anonymous-role known-user-role self-role global-context authorize-default? session-key)(inject-roles req config processor rcfn srfn anonymous-role known-user-role self-role global-context authorize-default? session-key roles-forbidden roles-any roles-all)

Main handler for roles. Takes a request map and updates it with role information. Returns updated map which may be a response if redirects for unauthorized access are enabled.

Internally it uses the process function, passing it a processor as the first argument. The processor should be a function which takes a configuration of roles as a map and the current user identifier. The default one is called handler but its memoized variant is used in the middleware wrapper.

This function is wrapped and exposed in a configuration map (:roles/config) under the key :handler. It takes a single argument (a request map) and performs injection using enclosed configuration and a default, memoized processor.

invalidate-cache!

(invalidate-cache! req-or-config user-id)

known?

(known? config role)

parse-roles

(parse-roles roles user-id config)(parse-roles roles user-id config known-roles global-context context-column keep-unknown?)

Parses a sequence of maps expressing roles and generates a single map with roles grouped by context.

prep-config

(prep-config config)

query-roles

(query-roles user-id config db)(query-roles db user-id)

Gets roles for the given user ID from a database. Returns a map of roles as a sequence of maps.

refresh

(refresh req)

Recalculates roles by calling configured handler on a request map.

unauthorized

(unauthorized config)

Generates unauthorized redirect.

unknown?

(unknown? config role)

user-authenticated?

(user-authenticated? session)

Returns true if user is authenticated, false otherwise.

user-authorized?

(user-authorized? req)(user-authorized? req in-context)(user-authorized? req in-context config)(user-authorized? req in-context data auth-default?)(user-authorized? req in-context auth-default? roles-forbidden roles-any roles-all)

Checks if user is authorized in the specified context. Takes a request map and a set of roles which are tested to be true in the detected context. Uses :data entry of the current route to get local configuration in which it looks for keys (in order):

  • :roles/forbidden,
  • :roles/any,
  • :roles/all.

The :roles/forbidden should contain a set of roles which make access unauthorized if at least one of the current roles is matching.

The :roles/any authorizes operation if at least one of the current roles is matching.

The :roles/all, if present, matches if all the specified roles are effectively present.

The default strategy (when there are no rules specified or just the :roles/forbidden) is to allow but it can be changed in the middleware configuration, under the key :authorize-default?.

Returns nil if the access is forbidden, true if granted, false if there were rules but none matched.

user-known?

(user-known? session)

Returns true if user ID can be obtained from the given session session, even if the session expired or has errors; false otherwise.

wrap-roles

(wrap-roles {:keys [db req-context-path req-self-path req-self-check-path req-self-role-fn req-context-fn query-roles-fn global-context context-column self-role logged-in-role anonymous-role known-user-role roles authorize-default? keep-unknown?], :as config})

Role-based access maintaining middleware. Uses the function associated with :handler configuration key (handler by default) to process roles information. This handler is wrapped in memoizer function to cache the results and passed as a first argument to inject-roles responsible for putting role information into request map.

So the workflow is: - For each request inject-roles is called. - inject-roles extracts session object from the request and calls get-roles-from-session. - get-roles-from-session calls handler on user ID (obtained from the session). - get-roles-from-session adds anonymous role if the user ID could not be obtained. - If there is user ID the handler is called from within get-roles-from-session. - Handler gets user ID and calls a function under configuration key :query-roles-fn. - The result of querying the database is a sequence of maps. - The maps are parsed with parse-roles. - The result of parse-roles is a map with (context -> sets of roles). - The result is returned to inject-roles and injected into a request map.

Additionally, configuration option :req-context-fn can specify an alternative function which will be called within inject-roles to get context from the request.

One can also use :req-self-role-fn to provide a function used to get an identifier of a self-role (only when user is authenticated) on a basis of the request map.