-
Notifications
You must be signed in to change notification settings - Fork 13
/
interceptor.clj
81 lines (72 loc) · 3.94 KB
/
interceptor.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
(ns geheimtur.interceptor
(:require [io.pedestal.interceptor :refer [interceptor]]
[geheimtur.util.auth :as auth :refer [authorized? authenticated? throw-forbidden]]
[geheimtur.util.response :as response]
[io.pedestal.log :as log]
[geheimtur.impl.interactive :refer [interactive-error-handler]]
[geheimtur.impl.http-basic :refer [http-basic-authenticate http-basic-error-handler]]
[geheimtur.impl.token :refer [token-authenticate token-error-handler]]))
(defn access-forbidden-handler
[silent? & {:keys [type reason reason-fn]
:or {type :unauthenticated reason "You are not allowed to access this resource"}}]
(let [reason-fn (or reason-fn (constantly reason))]
(fn [context]
(throw-forbidden {:silent? silent? ::auth/type type :reason (reason-fn type context)}))))
(defn- guard-with
[roles unauthenticated-fn unauthorized-fn]
(fn [{request :request :as context}]
(if (authenticated? request)
(if-not (or (empty? roles)
(authorized? request roles))
(unauthorized-fn context)
context)
(unauthenticated-fn context))))
(defn guard
"An interceptor that allows only authenticated users that have any of :roles to access unterlying pages.
Accepts optional parameters:
:roles - a set of roles that are allowed to access the page, if not defined users are required to be just authenticated
:silent? - if set to `true` (default), users will be getting 404 Not Found error page, when they don't have enougth access rights
:unauthenticated-fn - a handler of unauthenticated error state
:unauthorized-fn - a handler of unauthorized error state"
[& {:keys [roles unauthenticated-fn unauthorized-fn silent?] :or {silent? true}}]
(let [unauthenticated-fn (or unauthenticated-fn (access-forbidden-handler silent?))
unauthorized-fn (or unauthorized-fn (access-forbidden-handler silent? :type :unauthorized))]
(interceptor {:name ::guard
:enter (guard-with roles unauthenticated-fn unauthorized-fn)})))
(defn- access-forbidden-catcher
[error-handler]
(fn [context error]
(let [error-data (ex-data error)
type (::auth/type error-data)]
(if-not (nil? type)
(if (true? (:silent? error-data))
(dissoc context :response ) ;; that will cause 404 error
(error-handler context error-data))
(throw error)))))
(defn http-basic
"An interceptor that provides HTTP Basic authentication for your application
and handles authentication/authorization errors."
[realm credential-fn]
(interceptor {:name ::http-basic-auth
:enter (fn [{request :request :as context}]
(if-not (authenticated? request)
(http-basic-authenticate context credential-fn)
context))
:error (access-forbidden-catcher (http-basic-error-handler realm))}))
(defn interactive
"An interceptor that provides interactive authentication flow for
handling authentication/authorization errors in your application."
[config]
(let [config (merge {:login-uri "/login"} config)]
(interceptor {:name ::interactive-auth
:error (access-forbidden-catcher (interactive-error-handler config))})))
(defn token
"An interceptor that provides token-based authentication.
credential-fn - a function that given a request context and an authentication token returns the identity associated with it
Accepts optional parameters:
:token-fn - a function that given a request context returns the token associated with it
:error-fn - a function to handle authentication/authorization errors"
[credential-fn & {:as options}]
(interceptor {:name ::token-auth
:enter (token-authenticate (assoc options :credential-fn credential-fn))
:error (access-forbidden-catcher (token-error-handler options))}))