From e3bad997fde53ed93fdf56af7ee7de06a911d156 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 17 Feb 2021 16:52:04 +0100 Subject: [PATCH] :sparkles: Port fixes from google oauth handlers to github and gitlab. --- backend/src/app/http/auth/github.clj | 89 +++++++++++++-------------- backend/src/app/http/auth/gitlab.clj | 92 ++++++++++++++-------------- backend/src/app/http/auth/google.clj | 18 +++--- 3 files changed, 100 insertions(+), 99 deletions(-) diff --git a/backend/src/app/http/auth/github.clj b/backend/src/app/http/auth/github.clj index 26753bc05..3d8552efa 100644 --- a/backend/src/app/http/auth/github.clj +++ b/backend/src/app/http/auth/github.clj @@ -12,6 +12,7 @@ [app.common.exceptions :as ex] [app.common.spec :as us] [app.config :as cfg] + [app.http.auth.google :as gg] [app.util.http :as http] [app.util.time :as dt] [clojure.data.json :as json] @@ -67,7 +68,7 @@ nil))) (defn- get-user-info - [token] + [_ token] (try (let [req {:uri (str user-info-url) :headers {"authorization" (str "token " token)} @@ -77,58 +78,56 @@ (when (= 200 (:status res)) (let [data (json/read-str (:body res))] {:email (get data "email") + :backend "github" :fullname (get data "name")}))) (catch Exception e (log/error e "unexpected exception on get-user-info") nil))) -(defn auth - [{:keys [tokens] :as cfg} _request] - (let [state (tokens :generate {:iss :github-oauth :exp (dt/in-future "15m")}) - params {:client_id (:client-id cfg/config) - :redirect_uri (build-redirect-url cfg) - :state state - :scope scope} - query (u/map->query-string params) - uri (-> authorize-uri - (assoc :query query))] +(defn- retrieve-info + [{:keys [tokens] :as cfg} request] + (let [token (get-in request [:params :state]) + state (tokens :verify {:token token :iss :github-oauth}) + info (some->> (get-in request [:params :code]) + (get-access-token cfg state) + (get-user-info cfg))] + (when-not info + (ex/raise :type :internal + :code :unable-to-auth)) + + (cond-> info + (some? (:invitation-token state)) + (assoc :invitation-token (:invitation-token state))))) + +(defn auth-handler + [{:keys [tokens] :as cfg} request] + (let [invitation (get-in request [:params :invitation-token]) + state (tokens :generate {:iss :github-oauth + :invitation-token invitation + :exp (dt/in-future "15m")}) + params {:client_id (:client-id cfg/config) + :redirect_uri (build-redirect-url cfg) + :state state + :scope scope} + query (u/map->query-string params) + uri (-> authorize-uri + (assoc :query query))] {:status 200 :body {:redirect-uri (str uri)}})) -(defn callback - [{:keys [tokens rpc session] :as cfg} request] +(defn- callback-handler + [{:keys [session] :as cfg} request] (try - (let [state (get-in request [:params :state]) - _ (tokens :verify {:token state :iss :github-oauth}) - info (some->> (get-in request [:params :code]) - (get-access-token cfg state) - (get-user-info)) - - _ (when-not info - (ex/raise :type :internal - :code :unable-to-auth)) - - method-fn (get-in rpc [:methods :mutation :login-or-register]) - profile (method-fn {:email (:email info) - :backend "github" - :fullname (:fullname info)}) - token (tokens :generate - {:iss :auth - :exp (dt/in-future "15m") - :profile-id (:id profile)}) - uri (-> (u/uri (:public-uri cfg/config)) - (assoc :path "/#/auth/verify-token") - (assoc :query (u/map->query-string {:token token}))) - sxf ((:create session) (:id profile)) - rsp {:status 302 :headers {"location" (str uri)} :body ""}] - (sxf request rsp)) + (let [info (retrieve-info cfg request) + profile (gg/register-profile cfg info) + uri (gg/generate-redirect-uri cfg profile) + sxf ((:create session) (:id profile))] + (->> (gg/redirect-response uri) + (sxf request))) (catch Exception _e - (let [uri (-> (u/uri (:public-uri cfg)) - (assoc :path "/#/auth/login") - (assoc :query (u/map->query-string {:error "unable-to-auth"})))] - {:status 302 - :headers {"location" (str uri)} - :body ""})))) + (-> (gg/generate-error-redirect-uri cfg) + (gg/redirect-response))))) + ;; --- ENTRY POINT @@ -153,8 +152,8 @@ [_ cfg] (if (and (:client-id cfg) (:client-secret cfg)) - {:auth-handler #(auth cfg %) - :callback-handler #(callback cfg %)} + {:auth-handler #(auth-handler cfg %) + :callback-handler #(callback-handler cfg %)} {:auth-handler default-handler :callback-handler default-handler})) diff --git a/backend/src/app/http/auth/gitlab.clj b/backend/src/app/http/auth/gitlab.clj index f253016b0..e932dfdba 100644 --- a/backend/src/app/http/auth/gitlab.clj +++ b/backend/src/app/http/auth/gitlab.clj @@ -12,6 +12,7 @@ [app.common.data :as d] [app.common.exceptions :as ex] [app.common.spec :as us] + [app.http.auth.google :as gg] [app.util.http :as http] [app.util.time :as dt] [clojure.data.json :as json] @@ -76,62 +77,61 @@ (when (= 200 (:status res)) (let [data (json/read-str (:body res))] {:email (get data "email") + :backend "gitlab" :fullname (get data "name")}))) (catch Exception e (log/error e "unexpected exception on get-user-info") nil))) -(defn auth - [{:keys [tokens] :as cfg} _request] - (let [token (tokens :generate {:iss :gitlab-oauth - :exp (dt/in-future "15m")}) - params {:client_id (:client-id cfg) - :redirect_uri (build-redirect-url cfg) - :response_type "code" - :state token - :scope scope} - query (u/map->query-string params) - uri (-> (build-oauth-uri cfg) - (assoc :query query))] +(defn- retrieve-info + [{:keys [tokens] :as cfg} request] + (let [token (get-in request [:params :state]) + state (tokens :verify {:token token :iss :gitlab-oauth}) + info (some->> (get-in request [:params :code]) + (get-access-token cfg) + (get-user-info cfg))] + (when-not info + (ex/raise :type :internal + :code :unable-to-auth)) + + (cond-> info + (some? (:invitation-token state)) + (assoc :invitation-token (:invitation-token state))))) + + +(defn- auth-handler + [{:keys [tokens] :as cfg} request] + (let [invitation (get-in request [:params :invitation-token]) + state (tokens :generate + {:iss :gitlab-oauth + :invitation-token invitation + :exp (dt/in-future "15m")}) + + params {:client_id (:client-id cfg) + :redirect_uri (build-redirect-url cfg) + :response_type "code" + :state state + :scope scope} + query (u/map->query-string params) + uri (-> (build-oauth-uri cfg) + (assoc :query query))] {:status 200 :body {:redirect-uri (str uri)}})) -(defn callback - [{:keys [tokens rpc session] :as cfg} request] +(defn- callback-handler + [{:keys [session] :as cfg} request] (try - (let [token (get-in request [:params :state]) - _ (tokens :verify {:token token :iss :gitlab-oauth}) - info (some->> (get-in request [:params :code]) - (get-access-token cfg) - (get-user-info cfg)) - _ (when-not info - (ex/raise :type :internal - :code :unable-to-auth)) - - method-fn (get-in rpc [:methods :mutation :login-or-register]) - profile (method-fn {:email (:email info) - :backend "gitlab" - :fullname (:fullname info)}) - token (tokens :generate {:iss :auth - :exp (dt/in-future "15m") - :profile-id (:id profile)}) - - uri (-> (u/uri (:public-uri cfg)) - (assoc :path "/#/auth/verify-token") - (assoc :query (u/map->query-string {:token token}))) - - sxf ((:create session) (:id profile)) - rsp {:status 302 :headers {"location" (str uri)} :body ""}] - (sxf request rsp)) + (let [info (retrieve-info cfg request) + profile (gg/register-profile cfg info) + uri (gg/generate-redirect-uri cfg profile) + sxf ((:create session) (:id profile))] + (->> (gg/redirect-response uri) + (sxf request))) (catch Exception _e - (let [uri (-> (u/uri (:public-uri cfg)) - (assoc :path "/#/auth/login") - (assoc :query (u/map->query-string {:error "unable-to-auth"})))] - {:status 302 - :headers {"location" (str uri)} - :body ""})))) + (-> (gg/generate-error-redirect-uri cfg) + (gg/redirect-response))))) (s/def ::client-id ::us/not-empty-string) (s/def ::client-secret ::us/not-empty-string) @@ -162,7 +162,7 @@ [_ cfg] (if (and (:client-id cfg) (:client-secret cfg)) - {:auth-handler #(auth cfg %) - :callback-handler #(callback cfg %)} + {:auth-handler #(auth-handler cfg %) + :callback-handler #(callback-handler cfg %)} {:auth-handler default-handler :callback-handler default-handler})) diff --git a/backend/src/app/http/auth/google.clj b/backend/src/app/http/auth/google.clj index be6a0e5fe..3f082d064 100644 --- a/backend/src/app/http/auth/google.clj +++ b/backend/src/app/http/auth/google.clj @@ -56,7 +56,7 @@ nil))) (defn- get-user-info - [token] + [_ token] (try (let [req {:uri "https://openidconnect.googleapis.com/v1/userinfo" :headers {"Authorization" (str "Bearer " token)} @@ -65,6 +65,7 @@ (when (= 200 (:status res)) (let [data (json/read-str (:body res))] {:email (get data "email") + :backend "google" :fullname (get data "name")}))) (catch Exception e (log/error e "unexpected exception on get-user-info") @@ -76,7 +77,7 @@ state (tokens :verify {:token token :iss :google-oauth}) info (some->> (get-in request [:params :code]) (get-access-token cfg) - (get-user-info))] + (get-user-info cfg))] (when-not info (ex/raise :type :internal :code :unable-to-auth)) @@ -85,17 +86,17 @@ (some? (:invitation-token state)) (assoc :invitation-token (:invitation-token state))))) -(defn- register-profile +(defn register-profile [{:keys [rpc] :as cfg} info] (let [method-fn (get-in rpc [:methods :mutation :login-or-register]) profile (method-fn {:email (:email info) - :backend "google" + :backend (:backend info) :fullname (:fullname info)})] (cond-> profile (some? (:invitation-token info)) (assoc :invitation-token (:invitation-token info))))) -(defn- generate-redirect-uri +(defn generate-redirect-uri [{:keys [tokens] :as cfg} profile] (let [token (or (:invitation-token profile) (tokens :generate {:iss :auth @@ -105,13 +106,13 @@ (assoc :path "/#/auth/verify-token") (assoc :query (u/map->query-string {:token token}))))) -(defn- generate-error-redirect-uri +(defn generate-error-redirect-uri [cfg] (-> (u/uri (:public-uri cfg)) (assoc :path "/#/auth/login") (assoc :query (u/map->query-string {:error "unable-to-auth"})))) -(defn- redirect-response +(defn redirect-response [uri] {:status 302 :headers {"location" (str uri)} @@ -145,7 +146,8 @@ profile (register-profile cfg info) uri (generate-redirect-uri cfg profile) sxf ((:create session) (:id profile))] - (sxf request (redirect-response uri))) + (->> (redirect-response uri) + (sxf request))) (catch Exception _e (-> (generate-error-redirect-uri cfg) (redirect-response)))))