diff --git a/backend/src/app/auth/oidc.clj b/backend/src/app/auth/oidc.clj index 226f842907..0e766769ba 100644 --- a/backend/src/app/auth/oidc.clj +++ b/backend/src/app/auth/oidc.clj @@ -45,7 +45,7 @@ (defn- discover-oidc-config [cfg {:keys [base-uri skip-ssrf-check?] :as provider}] (let [uri (u/join base-uri ".well-known/openid-configuration") - rsp (http/req cfg {:method :get :uri (dm/str uri)} {:skip-ssrf-check? (boolean skip-ssrf-check?)})] + rsp (http/req cfg {:method :get :uri (dm/str uri)} {:skip-ssrf-check? skip-ssrf-check?})] (if (= 200 (:status rsp)) (let [data (-> rsp :body json/decode) @@ -107,7 +107,7 @@ (defn- fetch-oidc-jwks [cfg jwks-uri {:keys [skip-ssrf-check?]}] - (let [{:keys [status body]} (http/req cfg {:method :get :uri jwks-uri} {:skip-ssrf-check? (boolean skip-ssrf-check?)})] + (let [{:keys [status body]} (http/req cfg {:method :get :uri jwks-uri} {:skip-ssrf-check? skip-ssrf-check?})] (if (= 200 status) (-> body json/decode :keys process-oidc-jwks) (ex/raise :type ::internal @@ -773,8 +773,7 @@ :base-uri (some-> (or base-url issuer) (str/rtrim "/") (str "/")) - :scopes (into default-oidc-scopes - (when scopes (str/split scopes " "))) + :scopes (into default-oidc-scopes (or scopes #{})) :skip-ssrf-check? true})) (defn- auth-handler @@ -815,13 +814,9 @@ session (session/get-session request) exp (ct/in-future {:hours 48})] (when (and session organization-id) - (let [props (or (some-> (:props session) db/decode-transit-pgobject) {}) - sso-map (get props :sso {}) - props' (assoc props :sso (assoc sso-map organization-id exp))] - (db/update! cfg :http-session-v2 - {:props (db/tjson props')} - {:id (:id session)} - {::db/return-keys false}))) + (let [props (-> (or (:props session) {}) + (update :sso assoc organization-id exp))] + (session/update-session (::session/manager cfg) (assoc session :props props)))) (redirect-response dest-url)) (let [provider (resolve-provider cfg state) diff --git a/backend/src/app/http/session.clj b/backend/src/app/http/session.clj index c3ec302e45..93481aea19 100644 --- a/backend/src/app/http/session.clj +++ b/backend/src/app/http/session.clj @@ -68,17 +68,24 @@ (def ^:private valid-params? (sm/validator schema:params)) +(defn- decode-session + [session] + (cond-> session + (db/pgobject? (:props session)) + (update :props db/decode-transit-pgobject))) + (defn- database-manager [pool] (reify ISessionManager (read-session [_ id] (if (string? id) - ;; Backward compatibility + ;; Backward compatibility: http_session (v1) has no props column (let [session (db/exec-one! pool (sql/select :http-session {:id id}))] (-> session (assoc :modified-at (:updated-at session)) (dissoc :updated-at))) - (db/exec-one! pool (sql/select :http-session-v2 {:id id})))) + (some-> (db/exec-one! pool (sql/select :http-session-v2 {:id id})) + (decode-session)))) (create-session [_ params] (assert (valid-params? params) "expect valid session params") @@ -100,7 +107,9 @@ (assoc :created-at modified-at) (assoc :modified-at modified-at))) (db/update! pool :http-session-v2 - {:modified-at modified-at} + (cond-> {:modified-at modified-at} + (some? (:props session)) + (assoc :props (db/tjson (:props session)))) {:id (:id session)} {::db/return-keys true})))) @@ -129,9 +138,10 @@ session)) (update-session [_ session] - (let [modified-at (ct/now)] - (swap! cache update (:id session) assoc :modified-at modified-at) - (assoc session :modified-at modified-at))) + (let [modified-at (ct/now) + session (assoc session :modified-at modified-at)] + (swap! cache assoc (:id session) session) + session)) (delete-session [_ id] (swap! cache dissoc id) diff --git a/backend/src/app/migrations.clj b/backend/src/app/migrations.clj index b65b92003b..2cf444ad04 100644 --- a/backend/src/app/migrations.clj +++ b/backend/src/app/migrations.clj @@ -486,8 +486,8 @@ {:name "0149-mod-file-library-rel-synced-at" :fn (mg/resource "app/migrations/sql/0149-mod-file-library-rel-synced-at.sql")} - {:name "0150-mod-http_session_v2" - :fn (mg/resource "app/migrations/sql/0150-mod-http_session_v2.sql")}]) + {:name "0150-mod-http-session-v2" + :fn (mg/resource "app/migrations/sql/0150-mod-http-session-v2.sql")}]) (defn apply-migrations! [pool name migrations] diff --git a/backend/src/app/migrations/sql/0150-mod-http_session_v2.sql b/backend/src/app/migrations/sql/0150-mod-http-session-v2.sql similarity index 100% rename from backend/src/app/migrations/sql/0150-mod-http_session_v2.sql rename to backend/src/app/migrations/sql/0150-mod-http-session-v2.sql diff --git a/backend/src/app/nitrate.clj b/backend/src/app/nitrate.clj index 0c2ac928d9..2439d2b077 100644 --- a/backend/src/app/nitrate.clj +++ b/backend/src/app/nitrate.clj @@ -16,7 +16,6 @@ [app.common.time :as ct] [app.common.types.organization :as cto] [app.config :as cf] - [app.db :as db] [app.http.client :as http] [app.http.session :as session] [app.rpc :as-alias rpc] @@ -447,7 +446,7 @@ [:base-url [:maybe :string]] [:client-secret [:maybe :string]] [:issuer [:maybe :string]] - [:scopes [:maybe :string]]]) + [:scopes [:maybe [::sm/set ::sm/text]]]]) (defn- get-org-sso-by-team-api [cfg {:keys [team-id] :as params}] @@ -520,13 +519,13 @@ (if-not (:active sso) {:authorized true :sso sso} (if (or (:issuer sso) (:base-url sso)) - (let [props (some-> (:props session) db/decode-transit-pgobject) + (let [props (:props session) sso-map (get props :sso {}) organization-id (:organization-id sso) exp (get sso-map organization-id) now (ct/now) - authorized (boolean (and (ct/inst? exp) - (ct/is-after? exp now)))] + authorized (and (ct/inst? exp) + (ct/is-after? exp now))] {:authorized authorized :sso sso}) {:authorized false :sso sso})))) diff --git a/backend/src/app/rpc/commands/nitrate.clj b/backend/src/app/rpc/commands/nitrate.clj index 6157a7d811..f000b94922 100644 --- a/backend/src/app/rpc/commands/nitrate.clj +++ b/backend/src/app/rpc/commands/nitrate.clj @@ -628,7 +628,7 @@ (sv/defmethod ::auth-sso "Check if a user needs to login into the organization SSO. Returns {:authorized true} when SSO is not active for the team. - Returns {:authorized false :auth-url } when SSO is active; + Returns {:authorized false :redirect-uri } when SSO is active; the client must redirect there. The OIDC provider itself handles re-authentication transparently if the user already has an active SSO session." {::rpc/auth true @@ -648,8 +648,8 @@ :organization-id organization-id :issuer issuer :exp (ct/in-future "4h")}) - auth-url (oidc/build-auth-redirect-uri oidc-provider state-token)] + redirect-uri (oidc/build-auth-redirect-uri oidc-provider state-token)] {:authorized false - :auth-url auth-url}) + :redirect-uri redirect-uri}) {:authorized false - :auth-url nil})))) + :redirect-uri nil})))) diff --git a/frontend/src/app/main/ui/routes.cljs b/frontend/src/app/main/ui/routes.cljs index 42ae7646a8..24acac8250 100644 --- a/frontend/src/app/main/ui/routes.cljs +++ b/frontend/src/app/main/ui/routes.cljs @@ -114,10 +114,10 @@ (if (some? team-id) (->> (rp/cmd! :auth-sso {:team-id team-id :url url}) (rx/subs! - (fn [{:keys [authorized auth-url]}] + (fn [{:keys [authorized redirect-uri]}] (if authorized (st/emit! (rt/navigated match send-event-info?)) - (when auth-url (st/emit! (rt/nav-raw :uri (str auth-url)))))) + (when redirect-uri (st/emit! (rt/nav-raw :uri (str redirect-uri)))))) (fn [cause] (errors/on-error cause)))) (st/emit! (rt/navigated match send-event-info?)))))