diff --git a/backend/src/app/config.clj b/backend/src/app/config.clj index 260e00c5f..0e9d4ac5d 100644 --- a/backend/src/app/config.clj +++ b/backend/src/app/config.clj @@ -116,7 +116,6 @@ (s/def ::oidc-roles-attr ::us/keyword) (s/def ::host ::us/string) (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-updater-batch-max-age ::dt/duration) (s/def ::http-session-updater-batch-max-size ::us/integer) diff --git a/backend/src/app/http/session.clj b/backend/src/app/http/session.clj index 2f071089d..c03f0995b 100644 --- a/backend/src/app/http/session.clj +++ b/backend/src/app/http/session.clj @@ -21,86 +21,85 @@ [clojure.spec.alpha :as s] [integrant.core :as ig])) +;; A default cookie name for storing the session. We don't allow +;; configure it. +(def cookie-name "session-id") + ;; --- IMPL -(defn- next-session-id - ([] (next-session-id 96)) - ([n] - (-> (bn/random-nonce n) - (bc/bytes->b64u) - (bc/bytes->str)))) +(defn- create-session + [{:keys [conn tokens] :as cfg} {:keys [profile-id headers] :as request}] + (let [token (tokens :generate {:iss "authentication" + :iat (dt/now) + :uid profile-id}) + params {:user-agent (get headers "user-agent") + :profile-id profile-id + :id token}] + (db/insert! conn :http-session params))) -(defn- create - [{:keys [conn] :as cfg} {:keys [profile-id user-agent]}] - (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}] +(defn- delete-session + [{:keys [conn] :as cfg} {:keys [cookies] :as request}] (when-let [token (get-in cookies [cookie-name :value])] (db/delete! conn :http-session {:id token})) nil) -(defn- retrieve - [{:keys [conn] :as cfg} token] - (when token - (db/exec-one! conn ["select id, profile_id from http_session where id = ?" token]))) +(defn- retrieve-session + [{:keys [conn] :as cfg} id] + (when id + (db/exec-one! conn ["select id, profile_id from http_session where id = ?" id]))) (defn- retrieve-from-request - [{:keys [cookie-name] :as cfg} {:keys [cookies] :as request}] + [cfg {:keys [cookies] :as request}] (->> (get-in cookies [cookie-name :value]) - (retrieve cfg))) + (retrieve-session cfg))) -(defn- cookies - [{:keys [cookie-name] :as cfg} vals] - {cookie-name (merge vals {:path "/" :http-only true})}) +(defn- add-cookies + [response {:keys [id] :as session}] + (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 [cfg handler] (fn [request] (if-let [{:keys [id profile-id] :as session} (retrieve-from-request cfg request)] - (let [events-ch (::events-ch cfg)] - (a/>!! events-ch id) + (do + (a/>!! (::events-ch cfg) id) (l/update-thread-context! {:profile-id profile-id}) (handler (assoc request :profile-id profile-id))) (handler request)))) ;; --- STATE INIT: SESSION -(s/def ::cookie-name ::cfg/http-session-cookie-name) - (defmethod ig/pre-init-spec ::session [_] - (s/keys :req-un [::db/pool] - :opt-un [::cookie-name])) + (s/keys :req-un [::db/pool])) (defmethod ig/prep-key ::session [_ cfg] - (merge {:cookie-name "auth-token" - :buffer-size 64} - (d/without-nils cfg))) + (d/merge {:buffer-size 64} + (d/without-nils cfg))) (defmethod ig/init-key ::session [_ {:keys [pool] :as cfg}] (let [events (a/chan (a/dropping-buffer (:buffer-size cfg))) - cfg (assoc cfg - :conn pool - ::events-ch events)] + cfg (-> cfg + (assoc :conn pool) + (assoc ::events-ch events))] (-> cfg (assoc :middleware #(middleware cfg %)) (assoc :create (fn [profile-id] (fn [request response] - (let [uagent (get-in request [:headers "user-agent"]) - value (create cfg {:profile-id profile-id :user-agent uagent})] - (assoc response :cookies (cookies cfg {:value value})))))) + (let [request (assoc request :profile-id profile-id) + session (create-session cfg request)] + (add-cookies response session))))) (assoc :delete (fn [request response] - (delete cfg request) - (assoc response - :status 204 - :body "" - :cookies (cookies cfg {:value "" :max-age -1}))))))) + (delete-session cfg request) + (-> response + (assoc :status 204) + (assoc :body "") + (clear-cookies))))))) (defmethod ig/halt-key! ::session [_ data] diff --git a/backend/src/app/main.clj b/backend/src/app/main.clj index e40946e14..ab8c96ebb 100644 --- a/backend/src/app/main.clj +++ b/backend/src/app/main.clj @@ -60,8 +60,8 @@ :storage (ig/ref :app.storage/storage)} :app.http.session/session - {:pool (ig/ref :app.db/pool) - :cookie-name (cf/get :http-session-cookie-name)} + {:pool (ig/ref :app.db/pool) + :tokens (ig/ref :app.tokens/tokens)} :app.http.session/gc-task {:pool (ig/ref :app.db/pool)