From 432d24dc94a49db6b977fedec2b90c2bd65d5dea Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 22 Apr 2021 07:49:53 +0200 Subject: [PATCH 1/4] :bug: Fix manage.sh script on docker images. --- backend/scripts/manage.template.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/scripts/manage.template.sh b/backend/scripts/manage.template.sh index 31ccabffe..31f261b6b 100644 --- a/backend/scripts/manage.template.sh +++ b/backend/scripts/manage.template.sh @@ -16,4 +16,4 @@ if [ -f ./environ ]; then source ./environ fi -exec $JAVA_CMD $JVM_OPTS -classpath $(cat classpath) -Dlog4j2.configurationFile=./log4j2.xml clojure.main -m app.cli.manage "\$@" +exec $JAVA_CMD $JVM_OPTS -classpath $(cat classpath) -Dlog4j2.configurationFile=./log4j2.xml clojure.main -m app.cli.manage "$@" From 5d2f4bac76918c1948da2eef7d49310a71d72b4e Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sun, 25 Apr 2021 19:43:09 +0200 Subject: [PATCH 2/4] :sparkles: 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. --- backend/src/app/config.clj | 1 - backend/src/app/http/session.clj | 89 ++++++++++++++++---------------- backend/src/app/main.clj | 4 +- 3 files changed, 46 insertions(+), 48 deletions(-) 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) From 8ecc0b3cd950f4860edc42ee515f075111214e34 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 26 Apr 2021 11:19:50 +0200 Subject: [PATCH 3/4] :bug: Fix email registration whitelist handling. --- backend/src/app/rpc/mutations/profile.clj | 6 +++--- frontend/shadow-cljs.edn | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/backend/src/app/rpc/mutations/profile.clj b/backend/src/app/rpc/mutations/profile.clj index dc0ec95fe..3e27d4e5e 100644 --- a/backend/src/app/rpc/mutations/profile.clj +++ b/backend/src/app/rpc/mutations/profile.clj @@ -134,11 +134,11 @@ "Returns true if email's domain is in the given whitelist or if given whitelist is an empty string." [whitelist email] - (if (str/blank? whitelist) + (if (str/empty-or-nil? whitelist) true (let [domains (str/split whitelist #",\s*") - email-domain (second (str/split email #"@"))] - (contains? (set domains) email-domain)))) + domain (second (str/split email #"@" 2))] + (contains? (set domains) domain)))) (def ^:private sql:profile-existence "select exists (select * from profile diff --git a/frontend/shadow-cljs.edn b/frontend/shadow-cljs.edn index e8fd91070..28b0dd0c2 100644 --- a/frontend/shadow-cljs.edn +++ b/frontend/shadow-cljs.edn @@ -2,6 +2,7 @@ :http {:port 3448} :nrepl {:port 3447} :jvm-opts ["-Xmx700m" "-Xms100m" "-XX:+UseSerialGC"] + :dev-http {8888 "classpath:public"} :builds {:main From df11ef4aca9c1eda2d9df332851478d0dc85a89f Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 26 Apr 2021 11:23:37 +0200 Subject: [PATCH 4/4] :fire: Remove unused requires. --- backend/src/app/http/session.clj | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/app/http/session.clj b/backend/src/app/http/session.clj index c03f0995b..2fd3e7983 100644 --- a/backend/src/app/http/session.clj +++ b/backend/src/app/http/session.clj @@ -15,8 +15,6 @@ [app.util.logging :as l] [app.util.time :as dt] [app.worker :as wrk] - [buddy.core.codecs :as bc] - [buddy.core.nonce :as bn] [clojure.core.async :as a] [clojure.spec.alpha :as s] [integrant.core :as ig]))