mirror of
https://github.com/penpot/penpot.git
synced 2025-05-22 23:36:12 +02:00
✨ Replace random session tokens with JWE tokens.
We still maintain the http session state on the database for to prevent replay attacks to the main application. But internally, on less critical parts of the infraestructure, it usefull have access to the identified user without hit the main database for that information.
This commit is contained in:
parent
ce072937e4
commit
5d2f4bac76
3 changed files with 46 additions and 48 deletions
|
@ -116,7 +116,6 @@
|
||||||
(s/def ::oidc-roles-attr ::us/keyword)
|
(s/def ::oidc-roles-attr ::us/keyword)
|
||||||
(s/def ::host ::us/string)
|
(s/def ::host ::us/string)
|
||||||
(s/def ::http-server-port ::us/integer)
|
(s/def ::http-server-port ::us/integer)
|
||||||
(s/def ::http-session-cookie-name ::us/string)
|
|
||||||
(s/def ::http-session-idle-max-age ::dt/duration)
|
(s/def ::http-session-idle-max-age ::dt/duration)
|
||||||
(s/def ::http-session-updater-batch-max-age ::dt/duration)
|
(s/def ::http-session-updater-batch-max-age ::dt/duration)
|
||||||
(s/def ::http-session-updater-batch-max-size ::us/integer)
|
(s/def ::http-session-updater-batch-max-size ::us/integer)
|
||||||
|
|
|
@ -21,86 +21,85 @@
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[integrant.core :as ig]))
|
[integrant.core :as ig]))
|
||||||
|
|
||||||
|
;; A default cookie name for storing the session. We don't allow
|
||||||
|
;; configure it.
|
||||||
|
(def cookie-name "session-id")
|
||||||
|
|
||||||
;; --- IMPL
|
;; --- IMPL
|
||||||
|
|
||||||
(defn- next-session-id
|
(defn- create-session
|
||||||
([] (next-session-id 96))
|
[{:keys [conn tokens] :as cfg} {:keys [profile-id headers] :as request}]
|
||||||
([n]
|
(let [token (tokens :generate {:iss "authentication"
|
||||||
(-> (bn/random-nonce n)
|
:iat (dt/now)
|
||||||
(bc/bytes->b64u)
|
:uid profile-id})
|
||||||
(bc/bytes->str))))
|
params {:user-agent (get headers "user-agent")
|
||||||
|
:profile-id profile-id
|
||||||
|
:id token}]
|
||||||
|
(db/insert! conn :http-session params)))
|
||||||
|
|
||||||
(defn- create
|
(defn- delete-session
|
||||||
[{:keys [conn] :as cfg} {:keys [profile-id user-agent]}]
|
[{:keys [conn] :as cfg} {:keys [cookies] :as request}]
|
||||||
(let [id (next-session-id)]
|
|
||||||
(db/insert! conn :http-session {:id id
|
|
||||||
:profile-id profile-id
|
|
||||||
:user-agent user-agent})
|
|
||||||
id))
|
|
||||||
|
|
||||||
(defn- delete
|
|
||||||
[{:keys [conn cookie-name] :as cfg} {:keys [cookies] :as request}]
|
|
||||||
(when-let [token (get-in cookies [cookie-name :value])]
|
(when-let [token (get-in cookies [cookie-name :value])]
|
||||||
(db/delete! conn :http-session {:id token}))
|
(db/delete! conn :http-session {:id token}))
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
(defn- retrieve
|
(defn- retrieve-session
|
||||||
[{:keys [conn] :as cfg} token]
|
[{:keys [conn] :as cfg} id]
|
||||||
(when token
|
(when id
|
||||||
(db/exec-one! conn ["select id, profile_id from http_session where id = ?" token])))
|
(db/exec-one! conn ["select id, profile_id from http_session where id = ?" id])))
|
||||||
|
|
||||||
(defn- retrieve-from-request
|
(defn- retrieve-from-request
|
||||||
[{:keys [cookie-name] :as cfg} {:keys [cookies] :as request}]
|
[cfg {:keys [cookies] :as request}]
|
||||||
(->> (get-in cookies [cookie-name :value])
|
(->> (get-in cookies [cookie-name :value])
|
||||||
(retrieve cfg)))
|
(retrieve-session cfg)))
|
||||||
|
|
||||||
(defn- cookies
|
(defn- add-cookies
|
||||||
[{:keys [cookie-name] :as cfg} vals]
|
[response {:keys [id] :as session}]
|
||||||
{cookie-name (merge vals {:path "/" :http-only true})})
|
(assoc response :cookies {"session-id" {:path "/" :http-only true :value id}}))
|
||||||
|
|
||||||
|
(defn- clear-cookies
|
||||||
|
[response]
|
||||||
|
(assoc response :cookies {"session-id" {:value "" :max-age -1}}))
|
||||||
|
|
||||||
(defn- middleware
|
(defn- middleware
|
||||||
[cfg handler]
|
[cfg handler]
|
||||||
(fn [request]
|
(fn [request]
|
||||||
(if-let [{:keys [id profile-id] :as session} (retrieve-from-request cfg request)]
|
(if-let [{:keys [id profile-id] :as session} (retrieve-from-request cfg request)]
|
||||||
(let [events-ch (::events-ch cfg)]
|
(do
|
||||||
(a/>!! events-ch id)
|
(a/>!! (::events-ch cfg) id)
|
||||||
(l/update-thread-context! {:profile-id profile-id})
|
(l/update-thread-context! {:profile-id profile-id})
|
||||||
(handler (assoc request :profile-id profile-id)))
|
(handler (assoc request :profile-id profile-id)))
|
||||||
(handler request))))
|
(handler request))))
|
||||||
|
|
||||||
;; --- STATE INIT: SESSION
|
;; --- STATE INIT: SESSION
|
||||||
|
|
||||||
(s/def ::cookie-name ::cfg/http-session-cookie-name)
|
|
||||||
|
|
||||||
(defmethod ig/pre-init-spec ::session [_]
|
(defmethod ig/pre-init-spec ::session [_]
|
||||||
(s/keys :req-un [::db/pool]
|
(s/keys :req-un [::db/pool]))
|
||||||
:opt-un [::cookie-name]))
|
|
||||||
|
|
||||||
(defmethod ig/prep-key ::session
|
(defmethod ig/prep-key ::session
|
||||||
[_ cfg]
|
[_ cfg]
|
||||||
(merge {:cookie-name "auth-token"
|
(d/merge {:buffer-size 64}
|
||||||
:buffer-size 64}
|
(d/without-nils cfg)))
|
||||||
(d/without-nils cfg)))
|
|
||||||
|
|
||||||
(defmethod ig/init-key ::session
|
(defmethod ig/init-key ::session
|
||||||
[_ {:keys [pool] :as cfg}]
|
[_ {:keys [pool] :as cfg}]
|
||||||
(let [events (a/chan (a/dropping-buffer (:buffer-size cfg)))
|
(let [events (a/chan (a/dropping-buffer (:buffer-size cfg)))
|
||||||
cfg (assoc cfg
|
cfg (-> cfg
|
||||||
:conn pool
|
(assoc :conn pool)
|
||||||
::events-ch events)]
|
(assoc ::events-ch events))]
|
||||||
(-> cfg
|
(-> cfg
|
||||||
(assoc :middleware #(middleware cfg %))
|
(assoc :middleware #(middleware cfg %))
|
||||||
(assoc :create (fn [profile-id]
|
(assoc :create (fn [profile-id]
|
||||||
(fn [request response]
|
(fn [request response]
|
||||||
(let [uagent (get-in request [:headers "user-agent"])
|
(let [request (assoc request :profile-id profile-id)
|
||||||
value (create cfg {:profile-id profile-id :user-agent uagent})]
|
session (create-session cfg request)]
|
||||||
(assoc response :cookies (cookies cfg {:value value}))))))
|
(add-cookies response session)))))
|
||||||
(assoc :delete (fn [request response]
|
(assoc :delete (fn [request response]
|
||||||
(delete cfg request)
|
(delete-session cfg request)
|
||||||
(assoc response
|
(-> response
|
||||||
:status 204
|
(assoc :status 204)
|
||||||
:body ""
|
(assoc :body "")
|
||||||
:cookies (cookies cfg {:value "" :max-age -1})))))))
|
(clear-cookies)))))))
|
||||||
|
|
||||||
(defmethod ig/halt-key! ::session
|
(defmethod ig/halt-key! ::session
|
||||||
[_ data]
|
[_ data]
|
||||||
|
|
|
@ -60,8 +60,8 @@
|
||||||
:storage (ig/ref :app.storage/storage)}
|
:storage (ig/ref :app.storage/storage)}
|
||||||
|
|
||||||
:app.http.session/session
|
:app.http.session/session
|
||||||
{:pool (ig/ref :app.db/pool)
|
{:pool (ig/ref :app.db/pool)
|
||||||
:cookie-name (cf/get :http-session-cookie-name)}
|
:tokens (ig/ref :app.tokens/tokens)}
|
||||||
|
|
||||||
:app.http.session/gc-task
|
:app.http.session/gc-task
|
||||||
{:pool (ig/ref :app.db/pool)
|
{:pool (ig/ref :app.db/pool)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue