mirror of
https://github.com/penpot/penpot.git
synced 2025-05-29 11:56:10 +02:00
Merge branch 'other/ldap' into develop
This commit is contained in:
commit
b0fa8c3bfc
12 changed files with 186 additions and 6 deletions
|
@ -53,6 +53,8 @@
|
||||||
com.draines/postal {:mvn/version "2.0.3"
|
com.draines/postal {:mvn/version "2.0.3"
|
||||||
:exclusions [commons-codec/commons-codec]}
|
:exclusions [commons-codec/commons-codec]}
|
||||||
|
|
||||||
|
puppetlabs/clj-ldap {:mvn/version"0.3.0"}
|
||||||
|
|
||||||
;; exception printing
|
;; exception printing
|
||||||
io.aviso/pretty {:mvn/version "0.1.37"}
|
io.aviso/pretty {:mvn/version "0.1.37"}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,20 @@
|
||||||
:registration-enabled true
|
:registration-enabled true
|
||||||
:registration-domain-whitelist ""
|
:registration-domain-whitelist ""
|
||||||
:debug-humanize-transit true
|
:debug-humanize-transit true
|
||||||
})
|
|
||||||
|
;; LDAP auth disabled by default. Set ldap-auth-host to enable
|
||||||
|
;:ldap-auth-host "ldap.mysupercompany.com"
|
||||||
|
;:ldap-auth-port 389
|
||||||
|
;:ldap-bind-dn "cn=admin,dc=ldap,dc=mysupercompany,dc=com"
|
||||||
|
;:ldap-bind-password "verysecure"
|
||||||
|
;:ldap-auth-ssl false
|
||||||
|
;:ldap-auth-starttls false
|
||||||
|
;:ldap-auth-base-dn "ou=People,dc=ldap,dc=mysupercompany,dc=com"
|
||||||
|
:ldap-auth-user-query "(|(uid=$username)(mail=$username))"
|
||||||
|
:ldap-auth-username-attribute "uid"
|
||||||
|
:ldap-auth-email-attribute "mail"
|
||||||
|
:ldap-auth-fullname-attribute "displayName"
|
||||||
|
:ldap-auth-avatar-attribute "jpegPhoto"})
|
||||||
|
|
||||||
(s/def ::http-server-port ::us/integer)
|
(s/def ::http-server-port ::us/integer)
|
||||||
(s/def ::http-server-debug ::us/boolean)
|
(s/def ::http-server-debug ::us/boolean)
|
||||||
|
@ -78,6 +91,19 @@
|
||||||
(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 ::ldap-auth-host ::us/string)
|
||||||
|
(s/def ::ldap-auth-port ::us/integer)
|
||||||
|
(s/def ::ldap-bind-dn ::us/string)
|
||||||
|
(s/def ::ldap-bind-password ::us/string)
|
||||||
|
(s/def ::ldap-auth-ssl ::us/boolean)
|
||||||
|
(s/def ::ldap-auth-starttls ::us/boolean)
|
||||||
|
(s/def ::ldap-auth-base-dn ::us/string)
|
||||||
|
(s/def ::ldap-auth-user-query ::us/string)
|
||||||
|
(s/def ::ldap-auth-username-attribute ::us/string)
|
||||||
|
(s/def ::ldap-auth-email-attribute ::us/string)
|
||||||
|
(s/def ::ldap-auth-fullname-attribute ::us/string)
|
||||||
|
(s/def ::ldap-auth-avatar-attribute ::us/string)
|
||||||
|
|
||||||
(s/def ::config
|
(s/def ::config
|
||||||
(s/keys :opt-un [::http-server-cors
|
(s/keys :opt-un [::http-server-cors
|
||||||
::http-server-debug
|
::http-server-debug
|
||||||
|
@ -106,7 +132,19 @@
|
||||||
::allow-demo-users
|
::allow-demo-users
|
||||||
::registration-enabled
|
::registration-enabled
|
||||||
::registration-domain-whitelist
|
::registration-domain-whitelist
|
||||||
::image-process-max-threads]))
|
::image-process-max-threads
|
||||||
|
::ldap-auth-host
|
||||||
|
::ldap-auth-port
|
||||||
|
::ldap-bind-dn
|
||||||
|
::ldap-bind-password
|
||||||
|
::ldap-auth-ssl
|
||||||
|
::ldap-auth-starttls
|
||||||
|
::ldap-auth-base-dn
|
||||||
|
::ldap-auth-user-query
|
||||||
|
::ldap-auth-username-attribute
|
||||||
|
::ldap-auth-email-attribute
|
||||||
|
::ldap-auth-fullname-attribute
|
||||||
|
::ldap-auth-avatar-attribute]))
|
||||||
|
|
||||||
(defn env->config
|
(defn env->config
|
||||||
[env]
|
[env]
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
[uxbox.http.handlers :as handlers]
|
[uxbox.http.handlers :as handlers]
|
||||||
[uxbox.http.auth :as auth]
|
[uxbox.http.auth :as auth]
|
||||||
[uxbox.http.auth.google :as google]
|
[uxbox.http.auth.google :as google]
|
||||||
|
[uxbox.http.auth.ldap :as ldap]
|
||||||
[uxbox.http.middleware :as middleware]
|
[uxbox.http.middleware :as middleware]
|
||||||
[uxbox.http.session :as session]
|
[uxbox.http.session :as session]
|
||||||
[uxbox.http.ws :as ws]
|
[uxbox.http.ws :as ws]
|
||||||
|
@ -48,6 +49,8 @@
|
||||||
:method :post}]
|
:method :post}]
|
||||||
["/logout" {:handler auth/logout-handler
|
["/logout" {:handler auth/logout-handler
|
||||||
:method :post}]
|
:method :post}]
|
||||||
|
["/login-ldap" {:handler ldap/auth
|
||||||
|
:method :post}]
|
||||||
|
|
||||||
["/w" {:middleware [session/auth]}
|
["/w" {:middleware [session/auth]}
|
||||||
["/query/:type" {:get handlers/query-handler}]
|
["/query/:type" {:get handlers/query-handler}]
|
||||||
|
|
69
backend/src/uxbox/http/auth/ldap.clj
Normal file
69
backend/src/uxbox/http/auth/ldap.clj
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
(ns uxbox.http.auth.ldap
|
||||||
|
(:require
|
||||||
|
[clj-ldap.client :as client]
|
||||||
|
[clojure.set :as set]
|
||||||
|
[mount.core :refer [defstate]]
|
||||||
|
[uxbox.common.exceptions :as ex]
|
||||||
|
[uxbox.config :as cfg]
|
||||||
|
[uxbox.services.mutations :as sm]
|
||||||
|
[uxbox.http.session :as session]
|
||||||
|
[clojure.tools.logging :as log]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn replace-several [s & {:as replacements}]
|
||||||
|
(reduce-kv clojure.string/replace s replacements))
|
||||||
|
|
||||||
|
(defstate *ldap-pool
|
||||||
|
:start (delay
|
||||||
|
(try
|
||||||
|
(client/connect (merge {:host {:address (:ldap-auth-host cfg/config)
|
||||||
|
:port (:ldap-auth-port cfg/config)}}
|
||||||
|
(-> cfg/config
|
||||||
|
(select-keys [:ldap-auth-ssl
|
||||||
|
:ldap-auth-starttls
|
||||||
|
:ldap-bind-dn
|
||||||
|
:ldap-bind-password])
|
||||||
|
(set/rename-keys {:ldap-auth-ssl :ssl?
|
||||||
|
:ldap-auth-starttls :startTLS?
|
||||||
|
:ldap-bind-dn :bind-dn
|
||||||
|
:ldap-bind-password :password}))))
|
||||||
|
(catch Exception e
|
||||||
|
(log/errorf e "Cannot connect to LDAP %s:%s"
|
||||||
|
(:ldap-auth-host cfg/config) (:ldap-auth-port cfg/config)))))
|
||||||
|
:stop (when (realized? *ldap-pool)
|
||||||
|
(some-> *ldap-pool deref (.close))))
|
||||||
|
|
||||||
|
(defn- auth-with-ldap [username password]
|
||||||
|
(when-some [conn (some-> *ldap-pool deref)]
|
||||||
|
(let [user-search-query (replace-several (:ldap-auth-user-query cfg/config)
|
||||||
|
"$username" username)
|
||||||
|
user-attributes (-> cfg/config
|
||||||
|
(select-keys [:ldap-auth-username-attribute
|
||||||
|
:ldap-auth-email-attribute
|
||||||
|
:ldap-auth-fullname-attribute
|
||||||
|
:ldap-auth-avatar-attribute])
|
||||||
|
vals)]
|
||||||
|
(when-some [user-entry (-> conn
|
||||||
|
(client/search (:ldap-auth-base-dn cfg/config)
|
||||||
|
{:filter user-search-query
|
||||||
|
:sizelimit 1
|
||||||
|
:attributes user-attributes})
|
||||||
|
(first))]
|
||||||
|
(when-not (client/bind? conn (:dn user-entry) password)
|
||||||
|
(ex/raise :type :authentication
|
||||||
|
:code ::wrong-credentials))
|
||||||
|
(set/rename-keys user-entry {(keyword (:ldap-auth-avatar-attribute cfg/config)) :photo
|
||||||
|
(keyword (:ldap-auth-fullname-attribute cfg/config)) :fullname
|
||||||
|
(keyword (:ldap-auth-email-attribute cfg/config)) :email})))))
|
||||||
|
|
||||||
|
(defn auth [req]
|
||||||
|
(let [data (:body-params req)
|
||||||
|
uagent (get-in req [:headers "user-agent"])]
|
||||||
|
(when-some [info (auth-with-ldap (:email data) (:password data))]
|
||||||
|
(let [profile (sm/handle {::sm/type :login-or-register
|
||||||
|
:email (:email info)
|
||||||
|
:fullname (:fullname info)})
|
||||||
|
sid (session/create (:id profile) uagent)]
|
||||||
|
{:status 200
|
||||||
|
:cookies (session/cookies sid)
|
||||||
|
:body profile}))))
|
|
@ -7,11 +7,13 @@
|
||||||
**Only available at build time!**
|
**Only available at build time!**
|
||||||
|
|
||||||
- `-e UXBOX_PUBLIC_URI=...` (defaults to `http://localhost:6060`)
|
- `-e UXBOX_PUBLIC_URI=...` (defaults to `http://localhost:6060`)
|
||||||
|
- `-e UXBOX_GOOGLE_CLIENT_ID=...` (defaults to `true`)
|
||||||
|
- `-e UXBOX_LOGIN_WITH_LDAP=...` (defaults to `false`)
|
||||||
- `-e UXBOX_DEMO_WARNING=...` (defaults to `true`)
|
- `-e UXBOX_DEMO_WARNING=...` (defaults to `true`)
|
||||||
|
|
||||||
## Backend configuration parameters ##
|
## Backend configuration parameters ##
|
||||||
|
|
||||||
Backend accepts a bunch of configuration parameters (detailed abowe),
|
Backend accepts a bunch of configuration parameters (detailed above),
|
||||||
that can be passed in different ways. The preferred one is using
|
that can be passed in different ways. The preferred one is using
|
||||||
environment variables.
|
environment variables.
|
||||||
|
|
||||||
|
@ -41,6 +43,19 @@ respective defaults):
|
||||||
- `UXBOX_REGISTRATION_DOMAIN_WHITELIST=""` (comma-separated domains, defaults to `""` which means that all domains are allowed)
|
- `UXBOX_REGISTRATION_DOMAIN_WHITELIST=""` (comma-separated domains, defaults to `""` which means that all domains are allowed)
|
||||||
- `UXBOX_DEBUG_HUMANIZE_TRANSIT=true`
|
- `UXBOX_DEBUG_HUMANIZE_TRANSIT=true`
|
||||||
|
|
||||||
|
- `UXBOX_LDAP_AUTH_HOST=` (default undefined)
|
||||||
|
- `UXBOX_LDAP_AUTH_PORT=` (default undefined)
|
||||||
|
- `UXBOX_LDAP_AUTH_VERSION=3`
|
||||||
|
- `UXBOX_LDAP_BIND_DN=` (default undefined)
|
||||||
|
- `UXBOX_LDAP_BIND_PASSWORD=` (default undefined)
|
||||||
|
- `UXBOX_LDAP_AUTH_SSL=` (default `false`)
|
||||||
|
- `UXBOX_LDAP_AUTH_STARTTLS=` (default `false`)
|
||||||
|
- `UXBOX_LDAP_AUTH_BASE_DN=` (default undefined)
|
||||||
|
- `UXBOX_LDAP_AUTH_USER_QUERY=(|(uid=$username)(mail=$username))`
|
||||||
|
- `UXBOX_LDAP_AUTH_USERNAME_ATTRIBUTE=uid`
|
||||||
|
- `UXBOX_LDAP_AUTH_EMAIL_ATTRIBUTE=mail`
|
||||||
|
- `UXBOX_LDAP_AUTH_FULLNAME_ATTRIBUTE=displayName`
|
||||||
|
- `UXBOX_LDAP_AUTH_AVATAR_ATTRIBUTE=jpegPhoto`
|
||||||
|
|
||||||
## REPL ##
|
## REPL ##
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,7 @@ function readConfig(data) {
|
||||||
const demoWarn = process.env.UXBOX_DEMO_WARNING;
|
const demoWarn = process.env.UXBOX_DEMO_WARNING;
|
||||||
const deployDate = process.env.UXBOX_DEPLOY_DATE;
|
const deployDate = process.env.UXBOX_DEPLOY_DATE;
|
||||||
const deployCommit = process.env.UXBOX_DEPLOY_COMMIT;
|
const deployCommit = process.env.UXBOX_DEPLOY_COMMIT;
|
||||||
|
const loginWithLDAP = process.env.UXBOX_LOGIN_WITH_LDAP;
|
||||||
|
|
||||||
let cfg = {
|
let cfg = {
|
||||||
demoWarning: demoWarn === "true"
|
demoWarning: demoWarn === "true"
|
||||||
|
@ -130,6 +131,10 @@ function readConfig(data) {
|
||||||
cfg.deployCommit = deployCommit;
|
cfg.deployCommit = deployCommit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loginWithLDAP !== undefined) {
|
||||||
|
cfg.loginWithLDAP = loginWithLDAP;
|
||||||
|
}
|
||||||
|
|
||||||
Object.assign(cfg, data);
|
Object.assign(cfg, data);
|
||||||
|
|
||||||
return JSON.stringify(cfg);
|
return JSON.stringify(cfg);
|
||||||
|
|
|
@ -107,6 +107,15 @@
|
||||||
"es" : "Entrar"
|
"es" : "Entrar"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"auth.login-with-ldap-submit-label" : {
|
||||||
|
"used-in" : [ "src/uxbox/main/ui/auth/login.cljs:108" ],
|
||||||
|
"translations" : {
|
||||||
|
"en" : "Sign in with LDAP",
|
||||||
|
"fr" : "Se connecter via LDAP",
|
||||||
|
"es" : "Entrar con LDAP",
|
||||||
|
"ru" : "Вход через LDAP"
|
||||||
|
}
|
||||||
|
},
|
||||||
"auth.login-subtitle" : {
|
"auth.login-subtitle" : {
|
||||||
"used-in" : [ "src/uxbox/main/ui/auth/login.cljs:89" ],
|
"used-in" : [ "src/uxbox/main/ui/auth/login.cljs:89" ],
|
||||||
"translations" : {
|
"translations" : {
|
||||||
|
|
|
@ -15,10 +15,12 @@
|
||||||
puri (obj/get config "publicURI")
|
puri (obj/get config "publicURI")
|
||||||
wuri (obj/get config "workerURI")
|
wuri (obj/get config "workerURI")
|
||||||
gcid (obj/get config "googleClientID" true)
|
gcid (obj/get config "googleClientID" true)
|
||||||
|
lwl (obj/get config "loginWithLDAP" false)
|
||||||
warn (obj/get config "demoWarning" true)]
|
warn (obj/get config "demoWarning" true)]
|
||||||
(def default-language "en")
|
(def default-language "en")
|
||||||
(def demo-warning warn)
|
(def demo-warning warn)
|
||||||
(def google-client-id gcid)
|
(def google-client-id gcid)
|
||||||
|
(def login-with-ldap lwl)
|
||||||
(def worker-uri wuri)
|
(def worker-uri wuri)
|
||||||
(def public-uri puri)
|
(def public-uri puri)
|
||||||
(def default-theme "default")))
|
(def default-theme "default")))
|
||||||
|
|
|
@ -78,6 +78,30 @@
|
||||||
(rx/of (du/profile-fetched profile)
|
(rx/of (du/profile-fetched profile)
|
||||||
(rt/nav' :dashboard-team {:team-id team-id}))))))
|
(rt/nav' :dashboard-team {:team-id team-id}))))))
|
||||||
|
|
||||||
|
(defn login-with-ldap
|
||||||
|
[{:keys [email password] :as data}]
|
||||||
|
(us/verify ::login-params data)
|
||||||
|
(ptk/reify ::login-with-ldap
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(merge state (dissoc initial-state :route :router)))
|
||||||
|
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [this state s]
|
||||||
|
(let [{:keys [on-error on-success]
|
||||||
|
:or {on-error identity
|
||||||
|
on-success identity}} (meta data)
|
||||||
|
params {:email email
|
||||||
|
:password password
|
||||||
|
:scope "webapp"}]
|
||||||
|
(->> (rx/timer 100)
|
||||||
|
(rx/mapcat #(rp/mutation :login-with-ldap params))
|
||||||
|
(rx/tap on-success)
|
||||||
|
(rx/catch (fn [err]
|
||||||
|
(on-error err)
|
||||||
|
(rx/empty)))
|
||||||
|
(rx/map logged-in))))))
|
||||||
|
|
||||||
;; --- Logout
|
;; --- Logout
|
||||||
|
|
||||||
(def clear-user-data
|
(def clear-user-data
|
||||||
|
|
|
@ -104,5 +104,11 @@
|
||||||
(->> (http/send! {:method :post :uri uri :body params})
|
(->> (http/send! {:method :post :uri uri :body params})
|
||||||
(rx/mapcat handle-response))))
|
(rx/mapcat handle-response))))
|
||||||
|
|
||||||
|
(defmethod mutation :login-with-ldap
|
||||||
|
[id params]
|
||||||
|
(let [uri (str cfg/public-uri "/api/login-ldap")]
|
||||||
|
(->> (http/send! {:method :post :uri uri :body params})
|
||||||
|
(rx/mapcat handle-response))))
|
||||||
|
|
||||||
(def client-error? http/client-error?)
|
(def client-error? http/client-error?)
|
||||||
(def server-error? http/server-error?)
|
(def server-error? http/server-error?)
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
(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)
|
||||||
|
submit-event (mf/use-var da/login)
|
||||||
|
|
||||||
on-error
|
on-error
|
||||||
(fn [form event]
|
(fn [form event]
|
||||||
|
@ -53,7 +54,7 @@
|
||||||
(reset! error? false)
|
(reset! error? false)
|
||||||
(let [params (with-meta (:clean-data form)
|
(let [params (with-meta (:clean-data form)
|
||||||
{:on-error on-error})]
|
{:on-error on-error})]
|
||||||
(st/emit! (da/login params))))]
|
(st/emit! (@submit-event params))))]
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
(when @error?
|
(when @error?
|
||||||
|
@ -78,7 +79,12 @@
|
||||||
:help-icon i/eye
|
:help-icon i/eye
|
||||||
:label (t locale "auth.password-label")}]
|
:label (t locale "auth.password-label")}]
|
||||||
[:& submit-button
|
[:& submit-button
|
||||||
{:label (t locale "auth.login-submit-label")}]]]))
|
{:label (t locale "auth.login-submit-label")
|
||||||
|
:on-click #(reset! submit-event da/login)}]
|
||||||
|
(when cfg/login-with-ldap
|
||||||
|
[:& submit-button
|
||||||
|
{:label (t locale "auth.login-with-ldap-submit-label")
|
||||||
|
:on-click #(reset! submit-event da/login-with-ldap)}])]]))
|
||||||
|
|
||||||
(mf/defc login-page
|
(mf/defc login-page
|
||||||
[{:keys [locale] :as props}]
|
[{:keys [locale] :as props}]
|
||||||
|
|
|
@ -121,12 +121,13 @@
|
||||||
i/arrow-slide]]]))
|
i/arrow-slide]]]))
|
||||||
|
|
||||||
(mf/defc submit-button
|
(mf/defc submit-button
|
||||||
[{:keys [label form] :as props}]
|
[{:keys [label form on-click] :as props}]
|
||||||
(let [form (mf/use-ctx form-ctx)]
|
(let [form (mf/use-ctx form-ctx)]
|
||||||
[:input.btn-primary.btn-large
|
[:input.btn-primary.btn-large
|
||||||
{:name "submit"
|
{:name "submit"
|
||||||
:class (when-not (:valid form) "btn-disabled")
|
:class (when-not (:valid form) "btn-disabled")
|
||||||
:disabled (not (:valid form))
|
:disabled (not (:valid form))
|
||||||
|
:on-click on-click
|
||||||
:value label
|
:value label
|
||||||
:type "submit"}]))
|
:type "submit"}]))
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue