-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathclient.clj
147 lines (117 loc) · 4.47 KB
/
client.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
(ns cerber.stores.client
"Functions handling OAuth2 client storage."
(:require [cerber.stores.token :as token]
[cerber
[db :as db]
[error :as error]
[helpers :as helpers]
[mappers :as mappers]
[store :refer :all]]
[failjure.core :as f]))
(def client-store (atom :not-initialized))
(defrecord Client [id secret info redirects grants scopes approved? enabled? created-at modified-at activated-at blocked-at])
(defrecord SqlClientStore []
Store
(fetch-one [this [client-id]]
(some-> (db/find-client {:id client-id})
mappers/row->client))
(revoke-one! [this [client-id]]
(db/delete-client {:id client-id}))
(store! [this k client]
(= 1 (db/insert-client (-> client
(update :scopes helpers/coll->str)
(update :grants helpers/coll->str)
(update :redirects helpers/coll->str)))))
(modify! [this k client]
(if (:enabled? client)
(db/enable-client client)
(db/disable-client client)))
(purge! [this]
(db/clear-clients))
(close! [this]
))
(defmulti create-client-store (fn [type config] type))
(defmethod create-client-store :in-memory [_ _]
(->MemoryStore "clients" (atom {})))
(defmethod create-client-store :redis [_ redis-spec]
(->RedisStore "clients" redis-spec))
(defmethod create-client-store :sql [_ db-conn]
(when db-conn
(db/bind-queries db-conn)
(->SqlClientStore)))
(defn init-store
"Initializes client store according to given type and configuration."
[type config]
(reset! client-store (create-client-store type config)))
(defn validate-uri
"Returns java.net.URL instance of given uri or failure info in case of error."
[uri]
(if (empty? uri)
(error/internal-error "redirect-uri cannot be empty")
(if (or (>= (.indexOf uri "#") 0)
(>= (.indexOf uri "..") 0)
(.matches uri ".*\\s+.*"))
(error/internal-error "Illegal characters in redirect URI")
(try
(java.net.URL. uri)
(catch Exception e (error/internal-error (.getMessage e)))))))
(defn validate-redirects
"Goes through all redirects and returns list of validation failures."
[redirects]
(filter f/failed? (map validate-uri redirects)))
(defn find-client
"Returns a client with given id if any found or nil otherwise."
[client-id]
(when-let [found (and client-id (fetch-one @client-store [client-id]))]
(map->Client found)))
(defn revoke-client
"Revokes previously generated client and all tokens generated to this client so far."
[client]
(let [id (:id client)]
(revoke-one! @client-store [id])
(token/revoke-client-tokens client)))
(defn purge-clients
"Removes clients from store."
[]
(purge! @client-store))
(defn enable-client
"Enables client. Returns true if client has been enabled successfully or false otherwise."
[client]
(= 1 (modify! @client-store [:id] (assoc client :enabled? true :activated-at (helpers/now)))))
(defn disable-client
"Disables client. Returns true if client has been disabled successfully or false otherwise."
[client]
(token/revoke-client-tokens client)
(= 1 (modify! @client-store [:id] (assoc client :enabled? false :blocked-at (helpers/now)))))
(defn create-client
"Creates and returns a new client."
[grants redirects {:keys [info scopes enabled? approved? id secret]}]
(let [result (validate-redirects redirects)
client {:id (or id (helpers/generate-secret))
:secret (or secret (helpers/generate-secret))
:info info
:approved? (boolean approved?)
:enabled? (boolean enabled?)
:scopes scopes
:grants grants
:redirects redirects
:activated-at (helpers/now)
:created-at (helpers/now)}]
(if (seq result)
(error/internal-error (first result))
(if (store! @client-store [:id] client)
(map->Client client)
(error/internal-error "Cannot store client")))))
(defn grant-allowed?
[client grant]
(when-let [grants (:grants client)]
(.contains grants grant)))
(defn redirect-uri-valid?
[client redirect-uri]
(.contains (:redirects client) redirect-uri))
(defn scopes-valid?
"Checks whether given scopes are valid ones assigned to client."
[client scopes]
(let [client-scopes (:scopes client)]
(or (empty? scopes)
(every? #(.contains client-scopes %) scopes))))