/
authorization.clj
80 lines (69 loc) · 2.23 KB
/
authorization.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
(ns dgknght.app-lib.authorization
(:require [stowaway.core :as storage]))
(derive ::create ::manage)
(derive ::index ::manage)
(derive ::show ::manage)
(derive ::update ::manage)
(derive ::destroy ::manage)
(defmulti allowed?
"Returns a truthy or falsey value indicating whether or not the
authenticated user is allowed to perform the specified
action on the specified model"
(fn [model action _user]
[(storage/tag model) action]))
(defn- type-of
[model-or-keyword]
(if (keyword? model-or-keyword)
model-or-keyword
(storage/tag model-or-keyword)))
(defmethod allowed? :default
[model action _user]
(throw (ex-info (format "No authorization rules defined for action %s on type %s"
action
(type-of model))
{:action action
:type (type-of model)})))
(defn opaque?
[error]
(::opaque? (ex-data error)))
(defn- auth-error
[model action opaque?]
(let [[msg err-type] (if opaque?
["not found" ::not-found]
["forbidden" ::forbidden])]
(ex-info msg {:type err-type
:action action
:model (storage/tag model)
::opaque? opaque?})))
(def denied? (complement allowed?))
(defn authorize
"Raises an error if the current user does not have
permission to perform the specified function.
This function returns the model so that it can be threaded together
with other left-threadable operations"
[model action user]
{:pre [model action user]}
(if (allowed? model action user)
model
(throw (auth-error model action (not (allowed? model ::show user))))))
(defmulti scope
"Returns a criteria structure limiting the scope
of a query to that to which the specified user
has access."
(fn
[model-type _user]
model-type))
(defmethod scope :default
[model-type _user]
(throw (ex-info (format "No scope defined for type %s"
model-type)
{:type model-type})))
(defn +scope
([criteria user]
(+scope criteria (storage/tag criteria) user))
([criteria model-type user]
(if-let [s (scope model-type user)]
(if (empty? criteria)
s
[:and criteria s])
criteria)))