0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-18 10:41:29 -05:00

Login with Gitlab

This commit is contained in:
Vitaly Kornilov 2020-08-24 13:24:36 +03:00 committed by Andrey Antukh
parent dcd7e0b3cc
commit cc1353300e
9 changed files with 207 additions and 1 deletions

View file

@ -98,6 +98,10 @@
(s/def ::google-client-id ::us/string)
(s/def ::google-client-secret ::us/string)
(s/def ::gitlab-client-id ::us/string)
(s/def ::gitlab-client-secret ::us/string)
(s/def ::gitlab-base-uri ::us/string)
(s/def ::ldap-auth-host ::us/string)
(s/def ::ldap-auth-port ::us/integer)
(s/def ::ldap-bind-dn ::us/string)
@ -118,6 +122,9 @@
::http-server-port
::google-client-id
::google-client-secret
::gitlab-client-id
::gitlab-client-secret
::gitlab-base-uri
::public-uri
::database-username
::database-password

View file

@ -15,6 +15,7 @@
[ring.adapter.jetty9 :as jetty]
[app.config :as cfg]
[app.http.auth :as auth]
[app.http.auth.gitlab :as gitlab]
[app.http.auth.google :as google]
[app.http.auth.ldap :as ldap]
[app.http.debug :as debug]
@ -40,7 +41,9 @@
["/oauth"
["/google" {:post google/auth}]
["/google/callback" {:get google/callback}]]
["/google/callback" {:get google/callback}]
["/gitlab" {:post gitlab/auth}]
["/gitlab/callback" {:get gitlab/callback}]]
["/echo" {:get handlers/echo-handler
:post handlers/echo-handler}]

View file

@ -0,0 +1,153 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2020 UXBOX Labs SL
(ns app.http.auth.gitlab
(:require
[clojure.data.json :as json]
[clojure.tools.logging :as log]
[lambdaisland.uri :as uri]
[app.common.exceptions :as ex]
[app.config :as cfg]
[app.db :as db]
[app.services.tokens :as tokens]
[app.services.mutations :as sm]
[app.http.session :as session]
[app.util.http :as http]))
(def default-base-gitlab-uri "https://gitlab.com")
(def scope "read_user")
(defn- build-redirect-url
[]
(let [public (uri/uri (:public-uri cfg/config))]
(str (assoc public :path "/api/oauth/gitlab/callback"))))
(defn- build-oauth-uri
[]
(let [base-uri (uri/uri (:gitlab-base-uri cfg/config default-base-gitlab-uri))]
(assoc base-uri :path "/oauth/authorize")))
(defn- build-token-url
[]
(let [base-uri (uri/uri (:gitlab-base-uri cfg/config default-base-gitlab-uri))]
(str (assoc base-uri :path "/oauth/token"))))
(defn- build-user-info-url
[]
(let [base-uri (uri/uri (:gitlab-base-uri cfg/config default-base-gitlab-uri))]
(str (assoc base-uri :path "/api/v4/user"))))
(defn- get-access-token
[code]
(let [params {:client_id (:gitlab-client-id cfg/config)
:client_secret (:gitlab-client-secret cfg/config)
:code code
:grant_type "authorization_code"
:redirect_uri (build-redirect-url)}
req {:method :post
:headers {"content-type" "application/x-www-form-urlencoded"}
:uri (build-token-url)
:body (uri/map->query-string params)}
res (http/send! req)]
(when (not= 200 (:status res))
(ex/raise :type :internal
:code :invalid-response-from-gitlab
:context {:status (:status res)
:body (:body res)}))
(try
(let [data (json/read-str (:body res))]
(get data "access_token"))
(catch Throwable e
(log/error "unexpected error on parsing response body from gitlab access tooken request" e)
nil))))
(defn- get-user-info
[token]
(let [req {:uri (build-user-info-url)
:headers {"Authorization" (str "Bearer " token)}
:method :get}
res (http/send! req)]
(when (not= 200 (:status res))
(ex/raise :type :internal
:code :invalid-response-from-gitlab
:context {:status (:status res)
:body (:body res)}))
(try
(let [data (json/read-str (:body res))]
;; (clojure.pprint/pprint data)
{:email (get data "email")
:fullname (get data "name")})
(catch Throwable e
(log/error "unexpected error on parsing response body from gitlab access tooken request" e)
nil))))
(defn auth
[req]
(let [token (tokens/create! db/pool {:type :gitlab-oauth})
params {:client_id (:gitlab-client-id cfg/config)
:redirect_uri (build-redirect-url)
:response_type "code"
:state token
:scope scope}
query (uri/map->query-string params)
uri (-> (build-oauth-uri)
(assoc :query query))]
{:status 200
:body {:redirect-uri (str uri)}}))
(defn callback
[req]
(let [token (get-in req [:params :state])
tdata (tokens/retrieve db/pool token)
info (some-> (get-in req [:params :code])
(get-access-token)
(get-user-info))]
(when (not= :gitlab-oauth (:type tdata))
(ex/raise :type :validation
:code ::tokens/invalid-token))
(when-not info
(ex/raise :type :authentication
:code ::unable-to-authenticate-with-gitlab))
(let [profile (sm/handle {::sm/type :login-or-register
:email (:email info)
:fullname (:fullname info)})
uagent (get-in req [:headers "user-agent"])
tdata {:type :authentication
:profile profile}
token (tokens/create! db/pool tdata {:valid {:minutes 10}})
uri (-> (uri/uri (:public-uri cfg/config))
(assoc :path "/#/auth/verify-token")
(assoc :query (uri/map->query-string {:token token})))
sid (session/create (:id profile) uagent)]
{:status 302
:headers {"location" (str uri)}
:cookies (session/cookies sid)
:body ""})))

View file

@ -163,6 +163,7 @@ function templatePipeline(options) {
"var appLoginWithLDAP = null;",
"var appPublicURI = null;",
"var appGoogleClientID = null;",
"var appGitlabClientID = null;",
"var appDeployDate = null;",
"var appDeployCommit = null;"
];

View file

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 13.1072 13.10542" preserveAspectRatio="xMinYMin meet">
<path d="M6.5534 13.1502l2.41333-7.42742H4.14l2.41334 7.42743z" fill="#e24329"/>
<path d="M6.5534 13.15016L4.14 5.72273H.75783l5.79556 7.42743z" fill="#fc6d26"/>
<path d="M.75783 5.72273L.02446 7.97991a.49964.49964 0 00.18147.5586l6.34746 4.6117L.75777 5.72278z" fill="#fca326"/>
<path d="M.75783 5.72278H4.14L2.68654 1.24927c-.0748-.2302-.40045-.23015-.4752 0L.75783 5.72278z" fill="#e24329"/>
<path d="M6.5534 13.15016l2.41333-7.42743h3.38223l-5.79562 7.42743z" fill="#fc6d26"/>
<path d="M12.34896 5.72273l.73336 2.25718" fill="#fca326"/>
<path d="M12.34896 5.72278H8.96673l1.45351-4.47351c.0748-.2302.40045-.23015.4752 0l1.45352 4.47351z" fill="#e24329"/>
<path d="M12.34937 5.72273l.73337 2.25718a.49964.49964 0 01-.18147.5586l-6.34746 4.6117 5.79561-7.42742z" fill="#fca326"/>
</svg>

After

Width:  |  Height:  |  Size: 954 B

View file

@ -63,4 +63,15 @@
margin-bottom: $medium;
text-decoration: none;
}
.btn-gitlab-auth {
margin-bottom: $medium;
text-decoration: none;
.logo {
width: 20px;
height: 20px;
margin-right: 1rem;
}
}
}

View file

@ -14,6 +14,7 @@
(def default-language "en")
(def demo-warning (obj/get global "appDemoWarning" false))
(def google-client-id (obj/get global "appGoogleClientID" nil))
(def gitlab-client-id (obj/get global "appGitlabClientID" nil))
(def login-with-ldap (obj/get global "appLoginWithLDAP" false))
(def worker-uri (obj/get global "appWorkerURI" "/js/worker.js"))
(def public-uri (or (obj/get global "appPublicURI")

View file

@ -71,6 +71,12 @@
(->> (http/send! {:method :post :uri uri})
(rx/mapcat handle-response))))
(defmethod mutation :login-with-gitlab
[id params]
(let [uri (str cfg/public-uri "/api/oauth/gitlab")]
(->> (http/send! {:method :post :uri uri})
(rx/mapcat handle-response))))
(defmethod mutation :upload-media-object
[id params]
(let [form (js/FormData.)]

View file

@ -40,6 +40,13 @@
(rx/subs (fn [{:keys [redirect-uri] :as rsp}]
(.replace js/location redirect-uri)))))
(defn- login-with-gitlab
[event]
(dom/prevent-default event)
(->> (rp/mutation! :login-with-gitlab {})
(rx/subs (fn [{:keys [redirect-uri] :as rsp}]
(.replace js/location redirect-uri)))))
(mf/defc login-form
[{:keys [locale] :as props}]
(let [error? (mf/use-state false)
@ -113,6 +120,13 @@
{:on-click login-with-google}
"Login with Google"])
(when cfg/gitlab-client-id
[:a.btn-ocean.btn-large.btn-gitlab-auth
{:on-click login-with-gitlab}
[:img.logo
{:src "/images/icons/brand-gitlab.svg"}]
"Login with Gitlab"])
[:div.links.demo
[:div.link-entry
[:span (t locale "auth.create-demo-profile-label") " "]