~willvaughn/grsroot-auth

ref: 57fce2afeaf1d9e5548acece977bb0221c1f1c56 grsroot-auth/src/clj/grsroot_auth/middleware.clj -rw-r--r-- 2.4 KiB
57fce2afWilliam Vaughn add refresh_token table in migrations 5 months ago
                                                                                
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
(ns grsroot-auth.middleware
  (:require
   [grsroot-auth.config :refer [env]]
   [grsroot-auth.env :refer [defaults]]
   [ring.middleware.defaults :refer [api-defaults wrap-defaults]]
   [ring.util.http-response :refer :all]
   [buddy.auth.middleware :refer [wrap-authentication]]
   [buddy.auth.accessrules :refer [wrap-access-rules error]]
   [buddy.auth :refer [authenticated?]]
   [buddy.auth.backends :as backends]
   [buddy.auth.http :as http]
   [buddy.core.keys :as ks]
   [clojure.java.io :as io]
   [clojure.set :as s]))

;; TODO: figure out how to either load this at startup, or hard code a real ID, which I think should change to a uuid
;; maybe just use a memoized function to load this map?
;; This would be a query of roles for grsroot-auth, and then turning their slug into keywords and their values into strings. Not sure if it's best to use string or be coercing to uuids.
;; This should be able to be a uuid object, something getting lost through json serialization and when token is loaded.
(def my-roles {:super-admin "926e9535-2505-4c9e-a6cf-37953324d90d"})

(defn- pkey [auth-cfg]
  (ks/public-key
   (io/resource (:pubkey auth-cfg))))

(defn any-granted? [user roles]
  (seq
   (s/intersection (set (map :app_role_id (:app_roles user)))
                   (set (vals (select-keys my-roles roles))))))

(defn restrict-by-roles [roles]
  (fn [request]
    (if-let [user (:user (:identity request))]
      (if (any-granted? user roles)
        true
        (error "You are not authorized for this feature"))
      (error "You are not authenticated for this feature"))))

(defn on-error [request reason]
  {:status (if (authenticated? request) 403 401)
   :headers {}
   :body {:message reason}})

(defn authenticated-user [request]
  (if (authenticated? request)
    true
    (error "Only authenticated users allowed")))

(def rules [{:uris ["/api/apps" "/api/apps/:app-id/roles"]
             :request-method :post
             :handler {:and [authenticated-user (restrict-by-roles [:super-admin])]}}])

(defn wrap-access [handler]
  (wrap-access-rules handler {:rules rules :on-error on-error}))

(defn wrap-auth [handler]
  (let [backend (backends/jws {:secret (pkey (:auth-cfg env)) :options {:alg :rs512}})]
    (-> handler
        (wrap-authentication backend)
        wrap-access)))

(defn wrap-base [handler]
  (-> handler
      (wrap-defaults api-defaults)
      ((:middleware defaults))))