(ns metabase.sso.settings (:require [clojure.string :as str] [metabase.models.setting :as setting :refer [defsetting]] [metabase.models.setting.multi-setting :refer [define-multi-setting define-multi-setting-impl]] [metabase.premium-features.core :as premium-features] [metabase.util :as u] [metabase.util.i18n :refer [deferred-tru tru]] [metabase.util.json :as json]) (:import (com.unboundid.ldap.sdk DN))) | |
(set! *warn-on-reflection* true) | |
(defsetting ldap-host (deferred-tru "Server hostname.") :encryption :when-encryption-key-set :audit :getter) | |
(defsetting ldap-port (deferred-tru "Server port, usually 389 or 636 if SSL is used.") :encryption :when-encryption-key-set :type :integer :default 389 :audit :getter) | |
(defsetting ldap-security
(deferred-tru "Use SSL, TLS or plain text.")
:type :keyword
:default :none
:audit :raw-value
:setter (fn [new-value]
(when (some? new-value)
(assert (#{:none :ssl :starttls} (keyword new-value))))
(setting/set-value-of-type! :keyword :ldap-security new-value))) | |
(defsetting ldap-bind-dn (deferred-tru "The Distinguished Name to bind as (if any), this user will be used to lookup information about other users.") :encryption :when-encryption-key-set :audit :getter) | |
(defsetting ldap-password (deferred-tru "The password to bind with for the lookup user.") :encryption :when-encryption-key-set :sensitive? true :audit :getter) | |
(defsetting ldap-user-base (deferred-tru "Search base for users. (Will be searched recursively)") :encryption :no :audit :getter) | |
(defsetting ldap-user-filter
(deferred-tru "User lookup filter. The placeholder '''{login}''' will be replaced by the user supplied login.")
:default "(&(objectClass=inetOrgPerson)(|(uid={login})(mail={login})))"
:encryption :no
:audit :getter) | |
(defsetting ldap-attribute-email (deferred-tru "Attribute to use for the user''s email. (usually ''mail'', ''email'' or ''userPrincipalName'')") :default "mail" :encryption :no :getter (fn [] (u/lower-case-en (setting/get-value-of-type :string :ldap-attribute-email))) :audit :getter) | |
(defsetting ldap-attribute-firstname (deferred-tru "Attribute to use for the user''s first name. (usually ''givenName'')") :default "givenName" :getter (fn [] (u/lower-case-en (setting/get-value-of-type :string :ldap-attribute-firstname))) :encryption :no :audit :getter) | |
(defsetting ldap-attribute-lastname (deferred-tru "Attribute to use for the user''s last name. (usually ''sn'')") :encryption :no :default "sn" :getter (fn [] (u/lower-case-en (setting/get-value-of-type :string :ldap-attribute-lastname))) :audit :getter) | |
(defsetting ldap-group-sync (deferred-tru "Enable group membership synchronization with LDAP.") :type :boolean :default false :audit :getter) | |
(defsetting ldap-group-base (deferred-tru "Search base for groups. Not required for LDAP directories that provide a ''memberOf'' overlay, such as Active Directory. (Will be searched recursively)") :audit :getter :encryption :no) | |
(defsetting ldap-group-mappings
;; Should be in the form: {"cn=Some Group,dc=...": [1, 2, 3]} where keys are LDAP group DNs and values are lists of
;; MB groups IDs
(deferred-tru "JSON containing LDAP to Metabase group mappings.")
:encryption :no
:type :json
:cache? false
:default {}
:audit :getter
:getter (fn []
(json/decode (setting/get-value-of-type :string :ldap-group-mappings) #(DN. (str %))))
:setter (fn [new-value]
(cond
(string? new-value)
(recur (json/decode new-value))
(map? new-value)
(do
(doseq [k (keys new-value)]
(when-not (instance? DN k) ; handle DN-encoded keys like we get from the `:getter`
(when-not (DN/isValidDN (u/qualified-name k))
(throw (IllegalArgumentException. (tru "{0} is not a valid DN." (u/qualified-name k)))))))
(setting/set-value-of-type! :json :ldap-group-mappings new-value))))) | |
(defsetting ldap-configured?
(deferred-tru "Have the mandatory LDAP settings (host and user search base) been validated and saved?")
:type :boolean
:visibility :public
:setter :none
:getter (fn [] (boolean (and (ldap-host)
(ldap-user-base))))
:doc false) | |
(defsetting ldap-enabled
(deferred-tru "Is LDAP currently enabled?")
:type :boolean
:visibility :public
:setter (fn [new-value]
(let [new-value (boolean new-value)]
(when new-value
;; Test the LDAP settings before enabling
(let [result ((requiring-resolve 'metabase.sso.ldap/test-current-ldap-details))]
(when-not (= :SUCCESS (:status result))
(throw (ex-info (tru "Unable to connect to LDAP server with current settings")
((requiring-resolve 'metabase.sso.ldap/humanize-error-messages) result))))))
(setting/set-value-of-type! :boolean :ldap-enabled new-value)))
:default false
:audit :getter) | |
Google Auth | |
(defsetting google-auth-client-id
(deferred-tru "Client ID for Google Sign-In.")
:encryption :when-encryption-key-set
:visibility :public
:audit :getter
:setter (fn [client-id]
(if (seq client-id)
(let [trimmed-client-id (str/trim client-id)]
(when-not (str/ends-with? trimmed-client-id ".apps.googleusercontent.com")
(throw (ex-info (tru "Invalid Google Sign-In Client ID: must end with \".apps.googleusercontent.com\)
{:status-code 400})))
(setting/set-value-of-type! :string :google-auth-client-id trimmed-client-id))
(do
(setting/set-value-of-type! :string :google-auth-client-id nil)
(setting/set-value-of-type! :boolean :google-auth-enabled false))))) | |
(defsetting google-auth-configured (deferred-tru "Is Google Sign-In configured?") :type :boolean :setter :none :getter (fn [] (boolean (google-auth-client-id)))) | |
(defsetting google-auth-enabled
(deferred-tru "Is Google Sign-in currently enabled?")
:visibility :public
:type :boolean
:audit :getter
:getter (fn []
(if-some [value (setting/get-value-of-type :boolean :google-auth-enabled)]
value
(boolean (google-auth-client-id))))
:setter (fn [new-value]
(if-let [new-value (boolean new-value)]
(if-not (google-auth-client-id)
(throw (ex-info (tru "Google Sign-In is not configured. Please set the Client ID first.")
{:status-code 400}))
(setting/set-value-of-type! :boolean :google-auth-enabled new-value))
(setting/set-value-of-type! :boolean :google-auth-enabled new-value)))) | |
(define-multi-setting google-auth-auto-create-accounts-domain (deferred-tru "When set, allow users to sign up on their own if their Google account email address is from this domain.") (fn [] (if (premium-features/enable-sso-google?) :ee :oss)) :encryption :when-encryption-key-set) | |
(define-multi-setting-impl google-auth-auto-create-accounts-domain :oss
:getter (fn [] (setting/get-value-of-type :string :google-auth-auto-create-accounts-domain))
:setter (fn [domain]
(when (and domain (str/includes? domain ","))
;; Multiple comma-separated domains requires the `:sso-google` premium feature flag
(throw (ex-info (tru "Invalid domain") {:status-code 400})))
(setting/set-value-of-type! :string :google-auth-auto-create-accounts-domain domain))) | |
Common | |
(define-multi-setting send-new-sso-user-admin-email?
(deferred-tru "Should new email notifications be sent to admins, for all new SSO users?")
(fn [] (if (premium-features/enable-any-sso?)
:ee
:oss))
:type :boolean) | |
(define-multi-setting-impl send-new-sso-user-admin-email? :oss :getter (constantly true) :setter :none) | |