Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store sessions in db and extend token sessions #99

Merged
merged 1 commit into from
May 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 46 additions & 36 deletions src/juxt/pass/alpha/authentication.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

(ns juxt.pass.alpha.authentication
(:require
[jsonista.core :as json]
[clojure.tools.logging :as log]
[crypto.password.bcrypt :as password]
[clojure.walk :as walk]
[crux.api :as x]
[crypto.password.bcrypt :as password]
[jsonista.core :as json]
[juxt.reap.alpha.decoders :as reap]
[juxt.reap.alpha.rfc7235 :as rfc7235]
[ring.util.codec :refer [form-decode url-decode]]
[ring.middleware.cookies :refer [cookies-request cookies-response]]))
[ring.middleware.cookies :refer [cookies-request cookies-response]]
[ring.util.codec :refer [form-decode]])
(:import
(java.time Instant)))

(alias 'http (create-ns 'juxt.http.alpha))
(alias 'pass (create-ns 'juxt.pass.alpha))
Expand All @@ -23,32 +26,40 @@
(.nextBytes SECURE-RANDOM bytes)
(.encodeToString BASE64-ENCODER bytes)))

(defonce sessions-by-access-token (atom {}))

(defn put-session! [k session ^java.time.Instant expiry-instant]
(swap! sessions-by-access-token
assoc k (assoc session
::expiry-instant expiry-instant)))

(defn remove-session! [k]
(swap! sessions-by-access-token
dissoc k))

(defn expire-sessions! [date-now]
(swap! sessions-by-access-token
(fn [sessions]
(into {} (remove #(.isAfter (.toInstant date-now)
(-> % second (get ::expiry-instant)))
sessions)))))

(defn lookup-session [k date-now]
(expire-sessions! date-now)
(get @sessions-by-access-token k))

;;(identity @sessions-by-access-token)
(defn put-session! [{::site/keys [crux-node base-uri start-date]} k session]
(let [session (walk/keywordize-keys session)]
(->> [[:crux.tx/put
(merge
(select-keys session [::pass/user ::pass/state ::pass/nonce ::pass/return-to])
{:crux.db/id (str base-uri "/site-session/" k)
:juxt.site.alpha/type "SiteSession"
::expiry-instant
(-> (if start-date (.toInstant start-date) (Instant/now))
(.plusSeconds (or (:expires_in session) 3600)))})]]
(x/submit-tx crux-node)
(x/await-tx crux-node))))

(defn remove-session! [{::site/keys [crux-node base-uri]} k]
(->> [[:crux.tx/evict (str base-uri "/site-session/" k)]]
(x/submit-tx crux-node)
(x/await-tx crux-node)))

(defn expire-sessions! [{::site/keys [crux-node db start-date]}]
(->> (x/q db '{:find [ss expiry-instant]
:where [[ss :juxt.site.alpha/type "SiteSession"]
[ss ::expiry-instant expiry-instant]]})
(filter (fn [[_ expiry-instant]]
(.isAfter (.toInstant start-date) expiry-instant)))
(mapv (fn [[ss _]] [:crux.tx/evict ss]))
(x/submit-tx crux-node)
(x/await-tx crux-node)))

(defn lookup-session [{::site/keys [db base-uri] :as req} k]
(expire-sessions! req)
(x/entity db (str base-uri "/site-session/" k)))

(defn token-response
[{::site/keys [received-representation resource start-date]
[{::site/keys [received-representation resource]
::pass/keys [subject] :as req}]

;; Check grant_type of posted-representation
Expand Down Expand Up @@ -84,9 +95,9 @@
"user" (::pass/user subject)}

_ (put-session!
req
access-token
(merge session subject)
(.plusSeconds (.toInstant start-date) expires-in))
(merge session subject))

body (.getBytes
(str
Expand Down Expand Up @@ -145,10 +156,10 @@
"token_type" "login"
"expires_in" expires-in}]
(put-session!
req
access-token
(merge session {::pass/user user
::pass/username username})
(.plusSeconds (.toInstant start-date) expires-in))
::pass/username username}))
(-> req
(assoc :ring.response/status 302
:ring.response/body
Expand Down Expand Up @@ -236,13 +247,12 @@
(some-> req
((fn [req] (assoc req :headers (get req :ring.request/headers))))
cookies-request
:cookies (get "site_session") :value json/read-value)
now (::site/start-date req)]
:cookies (get "site_session") :value json/read-value)]

(or
;; Cookie
(when access-token
(when-let [session (lookup-session access-token now)]
(when-let [session (lookup-session req access-token)]
(->
(select-keys session [::pass/user ::pass/username])
(assoc ::pass/auth-scheme "Session"))))
Expand Down Expand Up @@ -276,7 +286,7 @@
(log/error e)))

"bearer"
(when-let [session (lookup-session token68 now)]
(when-let [session (lookup-session req token68)]
(->
(select-keys session [::pass/user ::pass/username])
(assoc ::pass/auth-scheme "Bearer")))
Expand Down
9 changes: 5 additions & 4 deletions src/juxt/pass/alpha/openid_connect.clj
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,13 @@

;; Create a pre-auth session
session-token-id! (make-nonce 16)
expires-in (get resource ::pass/expires-in (* 24 3600))
_ (put-session!
req
session-token-id!
(cond-> {::pass/state state ::pass/nonce nonce}
return-to (assoc ::pass/return-to return-to))
(.plusSeconds (.toInstant start-date) expires-in))
(cond-> {::pass/state state
::pass/nonce nonce
:expires_in (* 24 3600)}
return-to (assoc ::pass/return-to return-to)))

query-string
(codec/form-encode
Expand Down
29 changes: 15 additions & 14 deletions src/juxt/pass/alpha/session.clj
Original file line number Diff line number Diff line change
Expand Up @@ -36,35 +36,36 @@

(defn escalate-session
"If provided session-token-id! matches, create a new session with the matched identity"
[{::site/keys [db crux-node resource start-date]
::pass/keys [session-token-id!] :as req} matched-identity]
(let [session (authz/lookup-session session-token-id! start-date)
[{::pass/keys [session-token-id!] :as req} matched-identity]
(let [session (authz/lookup-session req session-token-id!)
_ (assert session)
new-session-token-id! (authz/access-token)
expires-in (get resource ::pass/expires-in (* 24 3600))]
(authz/remove-session! session-token-id!)
new-session-token-id! (authz/access-token)]
(authz/remove-session! req session-token-id!)
(authz/put-session!
req
new-session-token-id!
{::pass/user matched-identity}
(.plusSeconds (.toInstant start-date) expires-in))
{::pass/user matched-identity
"access_token" new-session-token-id!
"expires_in" (* 24 3600)
"user" matched-identity})

(-> req
(set-cookie new-session-token-id!)
(update-in [:ring.response/headers "location"]
(fn [location]
(-> (new URIBuilder location)
(.addParameter "code" new-session-token-id!)
(.toString)))))))
(fn [location]
(-> (new URIBuilder location)
(.addParameter "code" new-session-token-id!)
(.toString)))))))

(defn wrap-associate-session [h]
(fn [{::site/keys [db start-date] :as req}]
(fn [req]
(let [session-token-id!
(-> (assoc req :headers (get req :ring.request/headers))
cookies-request
:cookies (get "id") :value)

session (when session-token-id!
(authz/lookup-session session-token-id! start-date))
(authz/lookup-session req session-token-id!))

subject (some->
(select-keys session [::pass/user ::pass/username])
Expand Down
4 changes: 2 additions & 2 deletions src/juxt/site/alpha/init.clj
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
{"http://localhost:8000"
{::site/access-control-allow-methods #{:post}
::site/access-control-allow-headers #{"authorization" "content-type"}}}
::pass/expires-in (* 60 60 1)}
::pass/expires-in (* 3600 24 7)}

{:crux.db/id (str base-uri "/_site/rules/anyone-can-ask-for-a-token")
::site/type "Rule"
Expand Down Expand Up @@ -194,7 +194,7 @@
::http/methods #{:post}
::http/acceptable "application/x-www-form-urlencoded"
::site/purpose ::site/login
::pass/expires-in (* 3600 24 30)}
::pass/expires-in (* 3600 24 7)}

{:crux.db/id (str base-uri "/_site/rules/anyone-can-post-login-credentials")
::site/type "Rule"
Expand Down
7 changes: 0 additions & 7 deletions src/juxt/site/alpha/repl.clj
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,6 @@
(println "Evicting" (count batch) "records")
(println (apply evict! batch))))))

(defn sessions []
(authn/expire-sessions! (java.util.Date.))
(deref authn/sessions-by-access-token))

(defn clear-sessions []
(reset! authn/sessions-by-access-token {}))

(defn superusers
([] (superusers (config)))
([{::site/keys [base-uri]}]
Expand Down
Loading