-
Notifications
You must be signed in to change notification settings - Fork 12
/
session.clj
111 lines (101 loc) · 4.36 KB
/
session.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
(ns ring.adapter.undertow.middleware.session
(:require [ring.middleware.session :as ring-session])
(:import [io.undertow.util Sessions]
[io.undertow.server HttpServerExchange]
[io.undertow.server.session Session
SessionConfig
SessionCookieConfig]))
;; Mostly copied from https://github.com/immutant/immutant/blob/master/web/src/immutant/web/internal/undertow.clj
(defprotocol RingSession
(attribute [session key])
(set-attribute! [session key value])
(get-expiry [session])
(set-expiry [session timeout]))
(extend-type Session
RingSession
(attribute [session key]
(.getAttribute session key))
(set-attribute! [session key value]
(.setAttribute session key value))
(get-expiry [session]
(.getMaxInactiveInterval session))
(set-expiry [session timeout]
(.setMaxInactiveInterval session timeout)))
(def ring-session-key "ring-session-data")
(defn ring-session [session]
(if session (attribute session ring-session-key)))
(defn set-ring-session! [session data]
(set-attribute! session ring-session-key data))
(defn set-session-expiry
[session timeout]
(when (not= timeout (get-expiry session))
(set-expiry session timeout))
session)
(def ^{:tag SessionCookieConfig :private true} set-cookie-config!
(memoize
(fn [^SessionCookieConfig config
{:keys [cookie-name]
{:keys [path domain max-age secure http-only]} :cookie-attrs}]
(cond-> config
cookie-name (.setCookieName cookie-name)
path (.setPath path)
domain (.setDomain domain)
max-age (.setMaxAge max-age)
secure (.setSecure secure)
http-only (.setHttpOnly http-only)))))
(defn- get-or-create-session
([exchange]
(get-or-create-session exchange nil))
([^HttpServerExchange exchange {:keys [timeout] :as options}]
(when options
(set-cookie-config!
(.getAttachment exchange SessionConfig/ATTACHMENT_KEY)
options))
(-> exchange
Sessions/getOrCreateSession
(as-> session
(if options
(set-session-expiry session timeout)
session)))))
(defn wrap-undertow-session
"Ring middleware to insert a :session entry into the request, its
value stored in the `io.undertow.server.session.Session` from the
associated handler"
[handler options]
(let [fallback (delay (ring-session/wrap-session handler options))]
(fn [request]
(if-let [^HttpServerExchange exchange (:server-exchange request)]
(let [response (handler
(assoc request
;; we assume the request map automatically derefs delays
:session (delay (ring-session (get-or-create-session exchange options)))))]
(when (contains? response :session)
(if-let [data (:session response)]
(when-let [session (get-or-create-session exchange)]
(set-ring-session! session data))
(when-let [session (Sessions/getSession exchange)]
(.invalidate session exchange))))
response)
(@fallback request)))))
;; From https://github.com/immutant/immutant/blob/master/web/src/immutant/web/middleware.clj
(defn wrap-session
"Uses the session from either Undertow. By default, sessions will timeout
after 30 minutes of inactivity.
Supported options:
* :timeout The number of seconds of inactivity before session expires [1800]
* :cookie-name The name of the cookie that holds the session key [\"JSESSIONID\"]
A :timeout value less than or equal to zero indicates the session
should never expire.
* :cookie-attrs A map of attributes to associate with the session cookie [nil]
And the following :cookie-attrs keys are supported:
* :path - the subpath the cookie is valid for
* :domain - the domain the cookie is valid for
* :max-age - the maximum age in seconds of the cookie
* :secure - set to true if the cookie requires HTTPS, prevent HTTP access
* :http-only - set to true if the cookie is valid for HTTP and HTTPS only
(ie. prevent JavaScript access)"
([handler]
(wrap-session handler {}))
([handler options]
(let [options (merge {:timeout (* 30 60)} options)]
(wrap-undertow-session handler options))))