amelinium.http.middleware.roles
added in 1.0.0
amelinium service, role-based access control middleware.
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.
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.
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.
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.