mirror of
https://github.com/penpot/penpot.git
synced 2025-03-30 00:21:19 -05:00
✨ Login with Gitlab
This commit is contained in:
parent
dcd7e0b3cc
commit
cc1353300e
9 changed files with 207 additions and 1 deletions
|
@ -98,6 +98,10 @@
|
||||||
(s/def ::google-client-id ::us/string)
|
(s/def ::google-client-id ::us/string)
|
||||||
(s/def ::google-client-secret ::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-host ::us/string)
|
||||||
(s/def ::ldap-auth-port ::us/integer)
|
(s/def ::ldap-auth-port ::us/integer)
|
||||||
(s/def ::ldap-bind-dn ::us/string)
|
(s/def ::ldap-bind-dn ::us/string)
|
||||||
|
@ -118,6 +122,9 @@
|
||||||
::http-server-port
|
::http-server-port
|
||||||
::google-client-id
|
::google-client-id
|
||||||
::google-client-secret
|
::google-client-secret
|
||||||
|
::gitlab-client-id
|
||||||
|
::gitlab-client-secret
|
||||||
|
::gitlab-base-uri
|
||||||
::public-uri
|
::public-uri
|
||||||
::database-username
|
::database-username
|
||||||
::database-password
|
::database-password
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
[ring.adapter.jetty9 :as jetty]
|
[ring.adapter.jetty9 :as jetty]
|
||||||
[app.config :as cfg]
|
[app.config :as cfg]
|
||||||
[app.http.auth :as auth]
|
[app.http.auth :as auth]
|
||||||
|
[app.http.auth.gitlab :as gitlab]
|
||||||
[app.http.auth.google :as google]
|
[app.http.auth.google :as google]
|
||||||
[app.http.auth.ldap :as ldap]
|
[app.http.auth.ldap :as ldap]
|
||||||
[app.http.debug :as debug]
|
[app.http.debug :as debug]
|
||||||
|
@ -40,7 +41,9 @@
|
||||||
|
|
||||||
["/oauth"
|
["/oauth"
|
||||||
["/google" {:post google/auth}]
|
["/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
|
["/echo" {:get handlers/echo-handler
|
||||||
:post handlers/echo-handler}]
|
:post handlers/echo-handler}]
|
||||||
|
|
153
backend/src/app/http/auth/gitlab.clj
Normal file
153
backend/src/app/http/auth/gitlab.clj
Normal 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 ""})))
|
||||||
|
|
|
@ -163,6 +163,7 @@ function templatePipeline(options) {
|
||||||
"var appLoginWithLDAP = null;",
|
"var appLoginWithLDAP = null;",
|
||||||
"var appPublicURI = null;",
|
"var appPublicURI = null;",
|
||||||
"var appGoogleClientID = null;",
|
"var appGoogleClientID = null;",
|
||||||
|
"var appGitlabClientID = null;",
|
||||||
"var appDeployDate = null;",
|
"var appDeployDate = null;",
|
||||||
"var appDeployCommit = null;"
|
"var appDeployCommit = null;"
|
||||||
];
|
];
|
||||||
|
|
10
frontend/resources/images/icons/brand-gitlab.svg
Normal file
10
frontend/resources/images/icons/brand-gitlab.svg
Normal 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 (image error) Size: 954 B |
|
@ -63,4 +63,15 @@
|
||||||
margin-bottom: $medium;
|
margin-bottom: $medium;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-gitlab-auth {
|
||||||
|
margin-bottom: $medium;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
(def default-language "en")
|
(def default-language "en")
|
||||||
(def demo-warning (obj/get global "appDemoWarning" false))
|
(def demo-warning (obj/get global "appDemoWarning" false))
|
||||||
(def google-client-id (obj/get global "appGoogleClientID" nil))
|
(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 login-with-ldap (obj/get global "appLoginWithLDAP" false))
|
||||||
(def worker-uri (obj/get global "appWorkerURI" "/js/worker.js"))
|
(def worker-uri (obj/get global "appWorkerURI" "/js/worker.js"))
|
||||||
(def public-uri (or (obj/get global "appPublicURI")
|
(def public-uri (or (obj/get global "appPublicURI")
|
||||||
|
|
|
@ -71,6 +71,12 @@
|
||||||
(->> (http/send! {:method :post :uri uri})
|
(->> (http/send! {:method :post :uri uri})
|
||||||
(rx/mapcat handle-response))))
|
(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
|
(defmethod mutation :upload-media-object
|
||||||
[id params]
|
[id params]
|
||||||
(let [form (js/FormData.)]
|
(let [form (js/FormData.)]
|
||||||
|
|
|
@ -40,6 +40,13 @@
|
||||||
(rx/subs (fn [{:keys [redirect-uri] :as rsp}]
|
(rx/subs (fn [{:keys [redirect-uri] :as rsp}]
|
||||||
(.replace js/location redirect-uri)))))
|
(.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
|
(mf/defc login-form
|
||||||
[{:keys [locale] :as props}]
|
[{:keys [locale] :as props}]
|
||||||
(let [error? (mf/use-state false)
|
(let [error? (mf/use-state false)
|
||||||
|
@ -113,6 +120,13 @@
|
||||||
{:on-click login-with-google}
|
{:on-click login-with-google}
|
||||||
"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.links.demo
|
||||||
[:div.link-entry
|
[:div.link-entry
|
||||||
[:span (t locale "auth.create-demo-profile-label") " "]
|
[:span (t locale "auth.create-demo-profile-label") " "]
|
||||||
|
|
Loading…
Add table
Reference in a new issue