diff --git a/enterprise/backend/src/metabase_enterprise/advanced_config/models/pulse_channel.clj b/enterprise/backend/src/metabase_enterprise/advanced_config/models/pulse_channel.clj index 5bc61de21ddc6a85eb9158710588d06204ece77a..addac1ae095bb1861f000fdd1d55085e6fed1d67 100644 --- a/enterprise/backend/src/metabase_enterprise/advanced_config/models/pulse_channel.clj +++ b/enterprise/backend/src/metabase_enterprise/advanced_config/models/pulse_channel.clj @@ -8,6 +8,7 @@ (defsetting subscription-allowed-domains (deferred-tru "Allowed email address domain(s) for new Dashboard Subscriptions and Alerts. To specify multiple domains, separate each domain with a comma, with no space in between. To allow all domains, leave the field empty. This setting doesn’t affect existing subscriptions.") + :encryption :no :visibility :public :export? true :feature :email-allow-list diff --git a/enterprise/backend/src/metabase_enterprise/enhancements/integrations/ldap.clj b/enterprise/backend/src/metabase_enterprise/enhancements/integrations/ldap.clj index cae4a48bc4c5fab80bf81bf8cbf7d8c7ca0f6820..2095616f8ecbfc63b915c8851437bcd05dd988bc 100644 --- a/enterprise/backend/src/metabase_enterprise/enhancements/integrations/ldap.clj +++ b/enterprise/backend/src/metabase_enterprise/enhancements/integrations/ldap.clj @@ -29,14 +29,16 @@ ;; TODO - maybe we want to add a csv setting type? (defsetting ldap-sync-user-attributes-blacklist (deferred-tru "Comma-separated list of user attributes to skip syncing for LDAP users.") - :default "userPassword,dn,distinguishedName" - :type :csv - :audit :getter) + :encryption :no + :default "userPassword,dn,distinguishedName" + :type :csv + :audit :getter) (defsetting ldap-group-membership-filter (deferred-tru "Group membership lookup filter. The placeholders '{dn}' and '{uid}' will be replaced by the user''s Distinguished Name and UID, respectively.") - :default "(member={dn})" - :audit :getter) + :encryption :no + :default "(member={dn})" + :audit :getter) (defn- syncable-user-attributes [m] (when (ldap-sync-user-attributes) diff --git a/enterprise/backend/src/metabase_enterprise/llm/settings.clj b/enterprise/backend/src/metabase_enterprise/llm/settings.clj index 021e7472f6a8c98caa53198d0532ee12e86e641f..ccf64778262f61cfef090e7fe1e1b389d903dcbc 100644 --- a/enterprise/backend/src/metabase_enterprise/llm/settings.clj +++ b/enterprise/backend/src/metabase_enterprise/llm/settings.clj @@ -5,6 +5,7 @@ (defsetting ee-openai-model (deferred-tru "The OpenAI Model (e.g. 'gpt-4', 'gpt-3.5-turbo')") + :encryption :no :visibility :settings-manager :default "gpt-4-turbo-preview" :export? false @@ -12,6 +13,7 @@ (defsetting ee-openai-api-key (deferred-tru "The OpenAI API Key used in Metabase Enterprise.") + :encryption :no :visibility :settings-manager :export? false :doc "This feature is experimental.") diff --git a/enterprise/backend/src/metabase_enterprise/sso/integrations/sso_settings.clj b/enterprise/backend/src/metabase_enterprise/sso/integrations/sso_settings.clj index 7119447eb942849e582604c825c06259f53d5fdc..d20a655efa392644c0bbd8589fdb94565d4eea9b 100644 --- a/enterprise/backend/src/metabase_enterprise/sso/integrations/sso_settings.clj +++ b/enterprise/backend/src/metabase_enterprise/sso/integrations/sso_settings.clj @@ -54,8 +54,9 @@ don''t have one.") (defsetting saml-identity-provider-uri (deferred-tru "This is the URL where your users go to log in to your identity provider. Depending on which IdP you''re using, this usually looks like `https://your-org-name.example.com` or `https://example.com/app/my_saml_app/abc123/sso/saml`") - :feature :sso-saml - :audit :getter) + :encryption :when-encryption-key-set + :feature :sso-saml + :audit :getter) (mu/defn- validate-saml-idp-cert "Validate that an encoded identity provider certificate is valid, or throw an Exception." @@ -70,33 +71,38 @@ using, this usually looks like `https://your-org-name.example.com` or `https://e (defsetting saml-identity-provider-certificate (deferred-tru "Encoded certificate for the identity provider. Depending on your IdP, you might need to download this, open it in a text editor, then copy and paste the certificate's contents here.") - :feature :sso-saml - :audit :no-value - :setter (fn [new-value] - ;; when setting the idp cert validate that it's something we - (when new-value - (validate-saml-idp-cert new-value)) - (setting/set-value-of-type! :string :saml-identity-provider-certificate new-value))) + :feature :sso-saml + :audit :no-value + :encryption :no + :setter (fn [new-value] + ;; when setting the idp cert validate that it's something we + (when new-value + (validate-saml-idp-cert new-value)) + (setting/set-value-of-type! :string :saml-identity-provider-certificate new-value))) (defsetting saml-identity-provider-issuer (deferred-tru "This is a unique identifier for the IdP. Often referred to as Entity ID or simply 'Issuer'. Depending on your IdP, this usually looks something like `http://www.example.com/141xkex604w0Q5PN724v`") - :feature :sso-saml - :audit :getter) + :encryption :when-encryption-key-set + :feature :sso-saml + :audit :getter) (defsetting saml-application-name (deferred-tru "This application name will be used for requests to the Identity Provider") - :default "Metabase" - :feature :sso-saml - :audit :getter) + :default "Metabase" + :feature :sso-saml + :audit :getter + :encryption :when-encryption-key-set) (defsetting saml-keystore-path (deferred-tru "Absolute path to the Keystore file to use for signing SAML requests") - :feature :sso-saml - :audit :getter) + :encryption :when-encryption-key-set + :feature :sso-saml + :audit :getter) (defsetting saml-keystore-password (deferred-tru "Password for opening the keystore") + :encryption :when-encryption-key-set :default "changeit" :sensitive? true :feature :sso-saml @@ -105,27 +111,31 @@ on your IdP, this usually looks something like `http://www.example.com/141xkex60 (defsetting saml-keystore-alias (deferred-tru "Alias for the key that {0} should use for signing SAML requests" (public-settings/application-name-for-setting-descriptions)) - :default "metabase" - :feature :sso-saml - :audit :getter) + :encryption :when-encryption-key-set + :default "metabase" + :feature :sso-saml + :audit :getter) (defsetting saml-attribute-email (deferred-tru "SAML attribute for the user''s email address") - :default "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" - :feature :sso-saml - :audit :getter) + :default "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" + :feature :sso-saml + :encryption :when-encryption-key-set + :audit :getter) (defsetting saml-attribute-firstname (deferred-tru "SAML attribute for the user''s first name") - :default "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" - :feature :sso-saml - :audit :getter) + :default "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" + :encryption :when-encryption-key-set + :feature :sso-saml + :audit :getter) (defsetting saml-attribute-lastname (deferred-tru "SAML attribute for the user''s last name") - :default "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" - :feature :sso-saml - :audit :getter) + :default "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" + :encryption :when-encryption-key-set + :feature :sso-saml + :audit :getter) (defsetting saml-group-sync (deferred-tru "Enable group membership synchronization with SAML.") @@ -136,21 +146,23 @@ on your IdP, this usually looks something like `http://www.example.com/141xkex60 (defsetting saml-attribute-group (deferred-tru "SAML attribute for group syncing") - :default "member_of" - :feature :sso-saml - :audit :getter) + :default "member_of" + :feature :sso-saml + :audit :getter + :encryption :when-encryption-key-set) (defsetting saml-group-mappings ;; Should be in the form: {"groupName": [1, 2, 3]} where keys are SAML groups and values are lists of MB groups IDs (deferred-tru "JSON containing SAML to {0} group mappings." (public-settings/application-name-for-setting-descriptions)) - :type :json - :cache? false - :default {} - :feature :sso-saml - :audit :getter - :setter (comp (partial setting/set-value-of-type! :json :saml-group-mappings) - (partial mu/validate-throw validate-group-mappings))) + :encryption :when-encryption-key-set + :type :json + :cache? false + :default {} + :feature :sso-saml + :audit :getter + :setter (comp (partial setting/set-value-of-type! :json :saml-group-mappings) + (partial mu/validate-throw validate-group-mappings))) (defsetting saml-configured (deferred-tru "Are the mandatory SAML settings configured?") @@ -187,40 +199,46 @@ on your IdP, this usually looks something like `http://www.example.com/141xkex60 (defsetting jwt-identity-provider-uri (deferred-tru "URL of JWT based login page") - :feature :sso-jwt - :audit :getter) + :encryption :when-encryption-key-set + :feature :sso-jwt + :audit :getter) (defsetting jwt-shared-secret (deferred-tru (str "String used to seed the private key used to validate JWT messages." " " "A hexadecimal-encoded 256-bit key (i.e., a 64-character string) is strongly recommended.")) - :type :string - :feature :sso-jwt - :audit :no-value) + :encryption :when-encryption-key-set + :type :string + :feature :sso-jwt + :audit :no-value) (defsetting jwt-attribute-email (deferred-tru "Key to retrieve the JWT user's email address") - :default "email" - :feature :sso-jwt - :audit :getter) + :encryption :when-encryption-key-set + :default "email" + :feature :sso-jwt + :audit :getter) (defsetting jwt-attribute-firstname (deferred-tru "Key to retrieve the JWT user's first name") - :default "first_name" - :feature :sso-jwt - :audit :getter) + :encryption :when-encryption-key-set + :default "first_name" + :feature :sso-jwt + :audit :getter) (defsetting jwt-attribute-lastname (deferred-tru "Key to retrieve the JWT user's last name") - :default "last_name" - :feature :sso-jwt - :audit :getter) + :encryption :when-encryption-key-set + :default "last_name" + :feature :sso-jwt + :audit :getter) (defsetting jwt-attribute-groups (deferred-tru "Key to retrieve the JWT user's groups") - :default "groups" - :feature :sso-jwt - :audit :getter) + :default "groups" + :feature :sso-jwt + :encryption :when-encryption-key-set + :audit :getter) (defsetting jwt-group-sync (deferred-tru "Enable group membership synchronization with JWT.") @@ -233,14 +251,15 @@ on your IdP, this usually looks something like `http://www.example.com/141xkex60 ;; Should be in the form: {"groupName": [1, 2, 3]} where keys are JWT groups and values are lists of MB groups IDs (deferred-tru "JSON containing JWT to {0} group mappings." (public-settings/application-name-for-setting-descriptions)) - :type :json - :cache? false - :default {} - :feature :sso-jwt - :audit :getter - :setter (comp (partial setting/set-value-of-type! :json :jwt-group-mappings) - (partial mu/validate-throw validate-group-mappings)) - :doc "JSON object containing JWT to Metabase group mappings, where keys are JWT groups and values are lists of Metabase groups IDs.") + :encryption :when-encryption-key-set + :type :json + :cache? false + :default {} + :feature :sso-jwt + :audit :getter + :setter (comp (partial setting/set-value-of-type! :json :jwt-group-mappings) + (partial mu/validate-throw validate-group-mappings)) + :doc "JSON object containing JWT to Metabase group mappings, where keys are JWT groups and values are lists of Metabase groups IDs.") (defsetting jwt-configured (deferred-tru "Are the mandatory JWT settings configured?") diff --git a/enterprise/backend/test/metabase_enterprise/advanced_config/file/settings_test.clj b/enterprise/backend/test/metabase_enterprise/advanced_config/file/settings_test.clj index 9ed4550a4f69e9150cb9116d0c85e04078d1a616..1928f868779b9ed6a18bab21d4875a039a5bd663 100644 --- a/enterprise/backend/test/metabase_enterprise/advanced_config/file/settings_test.clj +++ b/enterprise/backend/test/metabase_enterprise/advanced_config/file/settings_test.clj @@ -13,7 +13,8 @@ (defsetting config-from-file-settings-test-setting "Internal test setting." - :visibility :internal) + :visibility :internal + :encryption :no) (deftest settings-test (testing "Should be able to set settings with config-from-file" diff --git a/src/metabase/analytics/snowplow.clj b/src/metabase/analytics/snowplow.clj index 31e6d25358fae887c00a120ea283548474518f4b..e3c478de0a9a88e575519d2b8e0612e04ec0c84b 100644 --- a/src/metabase/analytics/snowplow.clj +++ b/src/metabase/analytics/snowplow.clj @@ -62,7 +62,7 @@ (deferred-tru (str "Unique identifier to be used in Snowplow analytics, to identify this instance of Metabase. " "This is a public setting since some analytics events are sent prior to initial setup.")) - :encryption :never + :encryption :no :visibility :public :base setting/uuid-nonce-base :doc false) @@ -90,6 +90,7 @@ (defsetting snowplow-url (deferred-tru "The URL of the Snowplow collector to send analytics events to.") + :encryption :no :default (if config/is-prod? "https://sp.metabase.com" ;; See the iglu-schema-registry repo for instructions on how to run Snowplow Micro locally for development diff --git a/src/metabase/api/embed/common.clj b/src/metabase/api/embed/common.clj index 0700d678163acd7bb7f7434065c38afa606a4472..725950d5b57cde163b1ee76a5a2695113ba57b38 100644 --- a/src/metabase/api/embed/common.clj +++ b/src/metabase/api/embed/common.clj @@ -336,6 +336,7 @@ (defsetting entity-id-translation-counter (deferred-tru "A counter for tracking the number of entity_id -> id translations. Whenever we call [[model->entity-ids->ids]], we increment this counter by the number of translations.") + :encryption :no :visibility :internal :export? false :audit :never diff --git a/src/metabase/api/geojson.clj b/src/metabase/api/geojson.clj index 1a1ab46667a83a156c4ccb595df22d8263a591e6..ead44a8e2d93f495254ce7c83f4b6ebe9cac2ae6 100644 --- a/src/metabase/api/geojson.clj +++ b/src/metabase/api/geojson.clj @@ -112,14 +112,15 @@ (defsetting custom-geojson (deferred-tru "JSON containing information about custom GeoJSON files for use in map visualizations instead of the default US State or World GeoJSON.") - :type :json - :getter (fn [] (merge (setting/get-value-of-type :json :custom-geojson) (builtin-geojson))) - :setter (fn [new-value] - ;; remove the built-in keys you can't override them and we don't want those to be subject to validation. - (let [new-value (not-empty (reduce dissoc new-value (keys (builtin-geojson))))] - (when new-value - (validate-geojson new-value)) - (setting/set-value-of-type! :json :custom-geojson new-value))) + :encryption :no + :type :json + :getter (fn [] (merge (setting/get-value-of-type :json :custom-geojson) (builtin-geojson))) + :setter (fn [new-value] + ;; remove the built-in keys you can't override them and we don't want those to be subject to validation. + (let [new-value (not-empty (reduce dissoc new-value (keys (builtin-geojson))))] + (when new-value + (validate-geojson new-value)) + (setting/set-value-of-type! :json :custom-geojson new-value))) :visibility :public :export? true :audit :raw-value) diff --git a/src/metabase/driver.clj b/src/metabase/driver.clj index ae3656917d6369112f488e78f3fa25c7b6132f11..bda48e7741401ebaa607bb9fdc0de31e67888a82 100644 --- a/src/metabase/driver.clj +++ b/src/metabase/driver.clj @@ -61,6 +61,7 @@ (defsetting report-timezone (deferred-tru "Connection timezone to use when executing queries. Defaults to system timezone.") + :encryption :no :visibility :settings-manager :export? true :audit :getter diff --git a/src/metabase/email.clj b/src/metabase/email.clj index 9fad6f2a1007bb6e1a329500655aaeaedae65dd4..f629273c9c23f4a66185899ee628bd82f6a2274b 100644 --- a/src/metabase/email.clj +++ b/src/metabase/email.clj @@ -23,12 +23,14 @@ (defsetting email-from-address (deferred-tru "The email address you want to use for the sender of emails.") + :encryption :no :default "notifications@metabase.com" :visibility :settings-manager :audit :getter) (defsetting email-from-name (deferred-tru "The name you want to use for the sender of emails.") + :encryption :no :visibility :settings-manager :audit :getter) @@ -46,6 +48,7 @@ (defsetting email-reply-to (deferred-tru "The email address you want the replies to go to, if different from the from address.") + :encryption :no :type :json :visibility :settings-manager :audit :getter @@ -56,28 +59,33 @@ (defsetting email-smtp-host (deferred-tru "The address of the SMTP server that handles your emails.") + :encryption :when-encryption-key-set :visibility :settings-manager :audit :getter) (defsetting email-smtp-username (deferred-tru "SMTP username.") + :encryption :when-encryption-key-set :visibility :settings-manager :audit :getter) (defsetting email-smtp-password (deferred-tru "SMTP password.") + :encryption :when-encryption-key-set :visibility :settings-manager :sensitive? true :audit :getter) (defsetting email-smtp-port (deferred-tru "The port your SMTP server uses for outgoing emails.") + :encryption :when-encryption-key-set :type :integer :visibility :settings-manager :audit :getter) (defsetting email-smtp-security (deferred-tru "SMTP secure connection protocol. (tls, ssl, starttls, or none)") + :encryption :when-encryption-key-set :type :keyword :default :none :visibility :settings-manager diff --git a/src/metabase/embed/settings.clj b/src/metabase/embed/settings.clj index 95daad375c2018d636dc944362ecc64a669b643c..7c228af0f26fd0de388e4d0314b2a502f724e37d 100644 --- a/src/metabase/embed/settings.clj +++ b/src/metabase/embed/settings.clj @@ -15,7 +15,8 @@ (public-settings/application-name-for-setting-descriptions)) :feature :embedding :visibility :public - :audit :getter) + :audit :getter + :encryption :no) (defsetting enable-embedding (deferred-tru "Allow admins to securely embed questions and dashboards within other applications?") diff --git a/src/metabase/integrations/common.clj b/src/metabase/integrations/common.clj index 5e0ea7ad350bf48bd3f1ac8660b1ad5f7da50c64..c349f2659a615b3bfb9bdd6e86600240a60108d2 100644 --- a/src/metabase/integrations/common.clj +++ b/src/metabase/integrations/common.clj @@ -61,7 +61,8 @@ (deferred-tru "Should new email notifications be sent to admins, for all new SSO users?") (fn [] (if (premium-features/enable-any-sso?) :ee - :oss))) + :oss)) + :type :boolean) (define-multi-setting-impl send-new-sso-user-admin-email? :oss :getter (fn [] (constantly true)) diff --git a/src/metabase/integrations/google.clj b/src/metabase/integrations/google.clj index aa9df64dd9edb2c4412b637f9b05d92a9bd13648..64fcc5bb828f923d668a8930000a3799a53a0c5c 100644 --- a/src/metabase/integrations/google.clj +++ b/src/metabase/integrations/google.clj @@ -27,6 +27,7 @@ (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] diff --git a/src/metabase/integrations/google/interface.clj b/src/metabase/integrations/google/interface.clj index dd662e5c01340593fd3e874dcf0c9aded91d6b74..54de44d96be58dea61323976e8abd6b5ff9ac6d9 100644 --- a/src/metabase/integrations/google/interface.clj +++ b/src/metabase/integrations/google/interface.clj @@ -7,4 +7,5 @@ #_{:clj-kondo/ignore [:missing-docstring]} (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))) + (fn [] (if (premium-features/enable-sso-google?) :ee :oss)) + :encryption :when-encryption-key-set) diff --git a/src/metabase/integrations/ldap.clj b/src/metabase/integrations/ldap.clj index f10219bb3228b11d678b99b32b1b4b82751677a0..df131aefa7e629a57fb35e736358777e746ae44d 100644 --- a/src/metabase/integrations/ldap.clj +++ b/src/metabase/integrations/ldap.clj @@ -24,13 +24,15 @@ (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.") - :type :integer - :default 389 - :audit :getter) + :encryption :when-encryption-key-set + :type :integer + :default 389 + :audit :getter) (defsetting ldap-security (deferred-tru "Use SSL, TLS or plain text.") @@ -44,39 +46,46 @@ (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)") - :audit :getter) + :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})))" - :audit :getter) + :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" - :getter (fn [] (u/lower-case-en (setting/get-value-of-type :string :ldap-attribute-email))) - :audit :getter) + :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))) - :audit :getter) + :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'')") - :default "sn" - :getter (fn [] (u/lower-case-en (setting/get-value-of-type :string :ldap-attribute-lastname))) - :audit :getter) + :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.") @@ -86,28 +95,30 @@ (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) + :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.") - :type :json - :cache? false - :default {} - :audit :getter - :getter (fn [] - (json/parse-string (setting/get-value-of-type :string :ldap-group-mappings) #(DN. (str %)))) - :setter (fn [new-value] - (cond - (string? new-value) - (recur (json/parse-string new-value)) - - (map? new-value) - (do (doseq [k (keys new-value)] - (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))))) + :encryption :no + :type :json + :cache? false + :default {} + :audit :getter + :getter (fn [] + (json/parse-string (setting/get-value-of-type :string :ldap-group-mappings) #(DN. (str %)))) + :setter (fn [new-value] + (cond + (string? new-value) + (recur (json/parse-string new-value)) + + (map? new-value) + (do (doseq [k (keys new-value)] + (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?") diff --git a/src/metabase/integrations/slack.clj b/src/metabase/integrations/slack.clj index a367e5dce74d417e928c100fbb15c7e13c7bd300..b9b201d63f684b677e4c816b0748386c9fa37f10 100644 --- a/src/metabase/integrations/slack.clj +++ b/src/metabase/integrations/slack.clj @@ -23,6 +23,7 @@ (str "Deprecated Slack API token for connecting the Metabase Slack bot. " "Please use a new Slack app integration instead.")) :deprecated "0.42.0" + :encryption :when-encryption-key-set :visibility :settings-manager :doc false :audit :never) @@ -31,6 +32,7 @@ (deferred-tru (str "Bot user OAuth token for connecting the Metabase Slack app. " "This should be used for all new Slack integrations starting in Metabase v0.42.0.")) + :encryption :when-encryption-key-set :visibility :settings-manager :getter (fn [] (-> (setting/get-value-of-type :string :slack-app-token) @@ -57,6 +59,7 @@ (defsetting slack-cached-channels-and-usernames "A cache shared between instances for storing an instance's slack channels and users." + :encryption :when-encryption-key-set :visibility :internal :type :json :doc false @@ -76,6 +79,7 @@ (defsetting slack-files-channel (deferred-tru "The name of the channel to which Metabase files should be initially uploaded") :default "metabase_files" + :encryption :no :visibility :settings-manager :audit :getter :setter (fn [channel-name] diff --git a/src/metabase/metabot/settings.clj b/src/metabase/metabot/settings.clj index a7fda854ace10a8372023188879d752208ea813b..62f3270c8120af785eb657205e4d79d882c2cd1f 100644 --- a/src/metabase/metabot/settings.clj +++ b/src/metabase/metabot/settings.clj @@ -8,29 +8,35 @@ (defsetting openai-model (deferred-tru "The OpenAI Model (e.g. 'gpt-4-turbo-preview', 'gpt-4', 'gpt-3.5-turbo')") + :encryption :no :visibility :settings-manager :default "gpt-4-turbo-preview") (defsetting openai-api-key (deferred-tru "The OpenAI API Key.") + :encryption :when-encryption-key-set :visibility :settings-manager) (defsetting openai-organization (deferred-tru "The OpenAI Organization ID.") + :encryption :when-encryption-key-set :visibility :settings-manager) (defsetting metabot-default-embedding-model (deferred-tru "The default embeddings model to be used for metabot.") + :encryption :no :visibility :internal :default "text-embedding-ada-002") (defsetting metabot-get-prompt-templates-url (deferred-tru "The URL in which metabot versioned prompt templates are stored.") + :encryption :when-encryption-key-set :visibility :settings-manager :default "https://stkxezsr2kcnkhusi3fgcc5nqm0ttgfx.lambda-url.us-east-1.on.aws/") (defsetting metabot-feedback-url (deferred-tru "The URL to which metabot feedback is posted.") + :encryption :when-encryption-key-set :visibility :settings-manager :default "https://amtix3l3qvitb2qxstaqtcoqby0monuf.lambda-url.us-east-1.on.aws/") diff --git a/src/metabase/models/cloud_migration.clj b/src/metabase/models/cloud_migration.clj index 43e7be9f254ae64f1a681dd3b5629da48cc6ddfa..04685651c79fed05d0d2435032f0fa481a7ede70 100644 --- a/src/metabase/models/cloud_migration.clj +++ b/src/metabase/models/cloud_migration.clj @@ -43,6 +43,7 @@ (defsetting store-url (deferred-tru "Store URL.") + :encryption :no :visibility :admin ;; should be :internal, but FE doesn't get internal settings :default (str "https://store" (when (store-use-staging) ".staging") ".metabase.com") :doc false @@ -50,6 +51,7 @@ (defsetting store-api-url (deferred-tru "Store API URL.") + :encryption :no :visibility :internal :default (str "https://store-api" (when (store-use-staging) ".staging") ".metabase.com") :doc false @@ -57,6 +59,7 @@ (defsetting migration-dump-file (deferred-tru "Dump file for migrations.") + :encryption :no :visibility :internal :default nil :doc false @@ -64,6 +67,7 @@ (defsetting migration-dump-version (deferred-tru "Custom dump version for migrations.") + :encryption :no :visibility :internal ;; Use a known version on staging when there's no real version. ;; This will cause the restore to fail on cloud unless you also set `migration-dump-file` to diff --git a/src/metabase/models/setting.clj b/src/metabase/models/setting.clj index a698cc69ebc7082cd2f0ad898063d98d29c15bb2..0d394b96f9de9f62b6a1cbd588924c23e3834bae 100644 --- a/src/metabase/models/setting.clj +++ b/src/metabase/models/setting.clj @@ -271,9 +271,10 @@ ;; where this setting should be visible (default: :admin) [:visibility Visibility] - ;; should this setting be encrypted `:never` or `:maybe` (when `MB_ENCRYPTION_SECRET_KEY` is set). - ;; Defaults to `:maybe` (except for `:boolean` typed settings, where it defaults to `:never`) - [:encryption [:enum :never :maybe]] + ;; should this setting be encrypted. Available options are `:no` or `:when-encryption-key-set` (the setting will be + ;; encrypted when `MB_ENCRYPTION_SECRET_KEY` is set, otherwise we can't encrypt). This is required for `:timestamp`, + ;; `:json`, and `:csv`-typed settings. Defaults to `:no` for all other types. + [:encryption [:enum :no :when-encryption-key-set]] ;; should this setting be serialized? [:export? :boolean] @@ -388,7 +389,7 @@ (core/get *database-local-values* setting-name)))) (defn- prohibits-encryption? [setting-or-name] - (= :never (:encryption (resolve-setting setting-or-name)))) + (= :no (:encryption (resolve-setting setting-or-name)))) (defn- allows-user-local-values? [setting] (#{:only :allowed} (:user-local (resolve-setting setting)))) @@ -953,6 +954,42 @@ (binding [config/*disable-setting-cache* (not cache?)] (set-with-audit-logging! setting new-value bypass-read-only?)))) +(defn- extract-encryption-or-default + "Encryption is turned off or on according to (in order of preference): + + - the value you specify in `defsetting`, + + - ON for settings marked as `sensitive?` + + - ON for settings with a setter of `:none` (the specific value here doesn't really matter, we just don't want the + caller to need to provide a value) + + - OFF for types unlikely to contain secrets. As of this writing, that's booleans, numbers, keywords, and timestamps + + If none of these conditions are met (a non-`:sensitive?` string/json/csv value you're storing in the database, and + you didn't provide a value) then we'll throw an exception telling you that you need to provide it. This way, when we + add new settings, we'll think about their sensitivity level and make a conscious decision about whether they need to + be encrypted or not." + [setting] + (or + (:encryption setting) + ;; NOTE: if none of the below conditions is met, users of `defsetting` will be required to + ;; provide a value for `:encryption`. + ;; + ;; if a setting is `:sensitive?`, default to encrypting it + (when (:sensitive? setting) + :when-encryption-key-set) + ;; if a setting isn't stored in the DB, the value doesn't really matter, but provide + ;; a default so the caller doesn't have to + (when (= (:setter setting) :none) + :when-encryption-key-set) + ;; if the setting isn't a type likely to contain secrets, default to plaintext + (when (contains? #{:boolean :integer :positive-integer :double :keyword :timestamp} (:type setting)) + :no) + + (throw (ex-info (trs "`:encryption` is a required option for setting {0}" (:name setting)) + {:setting setting})))) + ;;; +----------------------------------------------------------------------------------------------------------------+ ;;; | register-setting! | ;;; +----------------------------------------------------------------------------------------------------------------+ @@ -977,7 +1014,7 @@ :init nil :tag (default-tag-for-type setting-type) :visibility :admin - :encryption (if (= setting-type :boolean) :never :maybe) + :encryption (extract-encryption-or-default setting) :export? false :sensitive? false :cache? true diff --git a/src/metabase/models/user.clj b/src/metabase/models/user.clj index d80a08a2457a3c8e8f989d91fec4e69615bcd201..b2fcb921c70e9848d0cb0feae3512a8051c575f2 100644 --- a/src/metabase/models/user.clj +++ b/src/metabase/models/user.clj @@ -454,6 +454,7 @@ (defsetting last-acknowledged-version (deferred-tru "The last version for which a user dismissed the 'What's new?' modal.") + :encryption :no :user-local :only :type :string) diff --git a/src/metabase/public_settings.clj b/src/metabase/public_settings.clj index 541331ab282d2e22334dea71743f75f0a106ca07..8b167a5cc4ea6acae032b7c7a3d6916f8cbdb90c 100644 --- a/src/metabase/public_settings.clj +++ b/src/metabase/public_settings.clj @@ -26,6 +26,7 @@ (defsetting application-name (deferred-tru "Replace the word “Metabase†wherever it appears.") + :encryption :no :visibility :public :export? true :type :string @@ -74,6 +75,7 @@ ;; Don't i18n this docstring because it's not user-facing! :) "Unique identifier used for this instance of {0}. This is set once and only once the first time it is fetched via its magic getter. Nice!" + :encryption :no :visibility :authenticated :base setting/uuid-nonce-base :doc false) @@ -118,14 +120,15 @@ (defsetting version-info (deferred-tru "Information about available versions of Metabase.") - :type :json - :audit :never - :default {} - :doc false - :getter (fn [] - (let [raw-vi (setting/get-value-of-type :json :version-info) - current-major (config/current-major-version)] - (version-info* raw-vi {:current-major current-major :upgrade-threshold-value (upgrade-threshold)})))) + :encryption :no + :type :json + :audit :never + :default {} + :doc false + :getter (fn [] + (let [raw-vi (setting/get-value-of-type :json :version-info) + current-major (config/current-major-version)] + (version-info* raw-vi {:current-major current-major :upgrade-threshold-value (upgrade-threshold)})))) (defsetting version-info-last-checked (deferred-tru "Indicates when Metabase last checked for new versions.") @@ -146,6 +149,7 @@ (defsetting site-name (deferred-tru "The name used for this instance of {0}." (application-name-for-setting-descriptions)) + :encryption :no :default "Metabase" :audit :getter :visibility :settings-manager @@ -153,6 +157,7 @@ (defsetting custom-homepage (deferred-tru "Pick one of your dashboards to serve as homepage. Users without dashboard access will be directed to the default homepage.") + :encryption :no :default false :type :boolean :audit :getter @@ -160,6 +165,7 @@ (defsetting custom-homepage-dashboard (deferred-tru "ID of dashboard to use as a homepage") + :encryption :no :type :integer :visibility :public :audit :getter) @@ -171,6 +177,7 @@ in [[metabase.public-settings.premium-features/fetch-token-status]]. (`site-uuid` is used for anonymous analytics/stats and if we sent it along with the premium features token check API request it would no longer be anonymous.)" + :encryption :when-encryption-key-set :visibility :internal :base setting/uuid-nonce-base :doc false) @@ -178,12 +185,14 @@ (defsetting site-uuid-for-version-info-fetching "A *different* site-wide UUID that we use for the version info fetching API calls. Do not use this for any other applications. (See [[site-uuid-for-premium-features-token-checks]] for more reasoning.)" + :encryption :when-encryption-key-set :visibility :internal :base setting/uuid-nonce-base) (defsetting site-uuid-for-unsubscribing-url "UUID that we use for generating urls users to unsubscribe from alerts. The hash is generated by hash(secret_uuid + email + subscription_id) = url. Do not use this for any other applications. (See #29955)" + :encryption :when-encryption-key-set :visibility :internal :base setting/uuid-nonce-base) @@ -207,6 +216,7 @@ (deferred-tru (str "This URL is used for things like creating links in emails, auth redirects, and in some embedding scenarios, " "so changing it could break functionality or get you locked out of this instance.")) + :encryption :when-encryption-key-set :visibility :public :audit :getter :getter (fn [] @@ -234,7 +244,7 @@ :visibility :public :export? true :audit :getter - :encryption :never + :encryption :no :getter (fn [] (let [value (setting/get-value-of-type :string :site-locale)] (when (i18n/available-locale? value) @@ -248,6 +258,7 @@ (defsetting admin-email (deferred-tru "The email address users should be referred to if they encounter a problem.") :visibility :authenticated + :encryption :when-encryption-key-set :audit :getter) (defsetting anon-tracking-enabled @@ -260,6 +271,7 @@ (defsetting map-tile-server-url (deferred-tru "The map tile server URL template used in map visualizations, for example from OpenStreetMaps or MapBox.") + :encryption :no :default "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" :visibility :public :audit :getter) @@ -276,6 +288,7 @@ (defsetting landing-page (deferred-tru "Enter a URL of the landing page to show the user. This overrides the custom homepage setting above.") + :encryption :no :visibility :public :export? true :type :string @@ -325,6 +338,7 @@ (defsetting persisted-model-refresh-cron-schedule (deferred-tru "cron syntax string to schedule refreshing persisted models.") + :encryption :no :type :string :default "0 0 0/6 * * ? *" :visibility :admin @@ -366,6 +380,7 @@ (defsetting notification-link-base-url (deferred-tru "By default \"Site Url\" is used in notification links, but can be overridden.") + :encryption :no :visibility :internal :type :string :feature :whitelabel @@ -375,12 +390,14 @@ (defsetting deprecation-notice-version (deferred-tru "Metabase version for which a notice about usage of deprecated features has been shown.") + :encryption :no :visibility :admin :doc false :audit :never) (defsetting loading-message (deferred-tru "Choose the message to show while a query is running.") + :encryption :no :visibility :public :export? true :feature :whitelabel @@ -390,6 +407,7 @@ (defsetting application-colors (deferred-tru "Choose the colors used in the user interface throughout Metabase and others specifically for the charts. You need to refresh your browser to see your changes take effect.") + :encryption :no :visibility :public :export? true :type :json @@ -423,6 +441,7 @@ To change the chart colors: (defsetting application-font (deferred-tru "Replace “Lato†as the font family.") + :encryption :no :visibility :public :export? true :type :string @@ -437,6 +456,7 @@ To change the chart colors: (defsetting application-font-files (deferred-tru "Tell us where to find the file for each font weight. You don’t need to include all of them, but it’ll look better if you do.") + :encryption :no :visibility :public :export? true :type :json @@ -473,6 +493,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting application-logo-url (deferred-tru "Upload a file to replace the Metabase logo on the top bar.") + :encryption :no :visibility :public :export? true :type :string @@ -483,6 +504,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting application-favicon-url (deferred-tru "Upload a file to use as the favicon.") + :encryption :no :visibility :public :export? true :type :string @@ -501,6 +523,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting login-page-illustration (deferred-tru "Options for displaying the illustration on the login page.") + :encryption :no :visibility :public :export? true :type :string @@ -510,6 +533,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting login-page-illustration-custom (deferred-tru "The custom illustration for the login page.") + :encryption :no :visibility :public :export? true :type :string @@ -518,6 +542,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting landing-page-illustration (deferred-tru "Options for displaying the illustration on the landing page.") + :encryption :no :visibility :public :export? true :type :string @@ -527,6 +552,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting landing-page-illustration-custom (deferred-tru "The custom illustration for the landing page.") + :encryption :no :visibility :public :export? true :type :string @@ -535,6 +561,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting no-data-illustration (deferred-tru "Options for displaying the illustration when there are no results after running a question.") + :encryption :no :visibility :public :export? true :type :string @@ -544,6 +571,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting no-data-illustration-custom (deferred-tru "The custom illustration for when there are no results after running a question.") + :encryption :no :visibility :public :export? true :type :string @@ -552,6 +580,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting no-object-illustration (deferred-tru "Options for displaying the illustration when there are no results after searching.") + :encryption :no :visibility :public :export? true :type :string @@ -561,6 +590,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting no-object-illustration-custom (deferred-tru "The custom illustration for when there are no results after searching.") + :encryption :no :visibility :public :export? true :type :string @@ -602,6 +632,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting help-link-custom-destination (deferred-tru "Custom URL for the help link.") + :encryption :no :visibility :public :type :string :audit :getter @@ -654,6 +685,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting custom-formatting (deferred-tru "Object keyed by type, containing formatting settings") + :encryption :no :type :json :export? true :default {} @@ -701,6 +733,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting source-address-header (deferred-tru "Identify the source of HTTP requests by this header's value, instead of its remote address.") + :encryption :no :default "X-Forwarded-For" :export? true :audit :getter @@ -742,6 +775,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting has-sample-database? "Whether this instance has a Sample Database database" + :type :boolean :visibility :authenticated :setter :none :getter (fn [] (t2/exists? :model/Database, :is_sample true)) @@ -873,6 +907,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting uploads-settings (deferred-tru "Upload settings") + :encryption :when-encryption-key-set ; this doesn't really have an effect as this setting is not stored as a setting model :visibility :authenticated :export? false ; the data is exported with a database export, so we don't need to export a setting :type :json @@ -979,6 +1014,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting uploads-schema-name (deferred-tru "Schema name for uploads") :deprecated "0.50.0" + :encryption :no :visibility :internal :export? false :type :string @@ -987,6 +1023,7 @@ See [fonts](../configuring-metabase/fonts.md).") (defsetting uploads-table-prefix (deferred-tru "Prefix for upload table names") + :encryption :no :deprecated "0.50.0" :visibility :internal :export? false diff --git a/src/metabase/server/middleware/auth.clj b/src/metabase/server/middleware/auth.clj index cc04fc517ddf965112bacca68d471cfb96dd08df..3d6ee714da92f4e9830c33b028f6a9ab73394b59 100644 --- a/src/metabase/server/middleware/auth.clj +++ b/src/metabase/server/middleware/auth.clj @@ -33,6 +33,7 @@ (defsetting api-key "When set, this API key is required for all API requests." + :encryption :when-encryption-key-set :visibility :internal :doc "Middleware that enforces validation of the client via the request header X-Metabase-Apikey. If the header is available, then it’s validated against MB_API_KEY. diff --git a/src/metabase/server/middleware/session.clj b/src/metabase/server/middleware/session.clj index 7bc41fabaf67f9286a319148e69ea532a06be1cf..77cd908d1e92e3634e8c795e889b977ad86f6658 100644 --- a/src/metabase/server/middleware/session.clj +++ b/src/metabase/server/middleware/session.clj @@ -509,24 +509,25 @@ ;; Should be in the form "{\"amount\":60,\"unit\":\"minutes\"}" where the unit is one of "seconds", "minutes" or "hours". ;; The amount is nillable. (deferred-tru "Time before inactive users are logged out. By default, sessions last indefinitely.") - :type :json - :default nil - :getter (fn [] - (let [value (setting/get-value-of-type :json :session-timeout)] - (if-let [error-key (check-session-timeout value)] - (do (log/warn (case error-key - :amount-must-be-positive "Session timeout amount must be positive." - :amount-must-be-less-than-100-years "Session timeout must be less than 100 years.")) - nil) - value))) - :setter (fn [new-value] - (when-let [error-key (check-session-timeout new-value)] - (throw (ex-info (case error-key - :amount-must-be-positive "Session timeout amount must be positive." - :amount-must-be-less-than-100-years "Session timeout must be less than 100 years.") - {:status-code 400}))) - (setting/set-value-of-type! :json :session-timeout new-value)) - :doc "Has to be in the JSON format `\"{\"amount\":120,\"unit\":\"minutes\"}\"` where the unit is one of \"seconds\", \"minutes\" or \"hours\".") + :encryption :no + :type :json + :default nil + :getter (fn [] + (let [value (setting/get-value-of-type :json :session-timeout)] + (if-let [error-key (check-session-timeout value)] + (do (log/warn (case error-key + :amount-must-be-positive "Session timeout amount must be positive." + :amount-must-be-less-than-100-years "Session timeout must be less than 100 years.")) + nil) + value))) + :setter (fn [new-value] + (when-let [error-key (check-session-timeout new-value)] + (throw (ex-info (case error-key + :amount-must-be-positive "Session timeout amount must be positive." + :amount-must-be-less-than-100-years "Session timeout must be less than 100 years.") + {:status-code 400}))) + (setting/set-value-of-type! :json :session-timeout new-value)) + :doc "Has to be in the JSON format `\"{\"amount\":120,\"unit\":\"minutes\"}\"` where the unit is one of \"seconds\", \"minutes\" or \"hours\".") (defn session-timeout->seconds "Convert the session-timeout setting value to seconds." diff --git a/src/metabase/util/embed.clj b/src/metabase/util/embed.clj index 9ff0f5cbf731b2352cdad99106db3e4755f0ce9c..7a74ebe99dca93f4b34082039e378eedd68c8ef5 100644 --- a/src/metabase/util/embed.clj +++ b/src/metabase/util/embed.clj @@ -58,6 +58,7 @@ (defsetting embedding-secret-key (deferred-tru "Secret key used to sign JSON Web Tokens for requests to `/api/embed` endpoints.") + :encryption :when-encryption-key-set :visibility :admin :audit :no-value :setter (fn [new-value] diff --git a/test/metabase/api/session_test.clj b/test/metabase/api/session_test.clj index 1a29e151c0135ccab8aa85305ed2092b6fd5f745..0dd6391f11483be50f5d9285c6aff81c568b3658 100644 --- a/test/metabase/api/session_test.clj +++ b/test/metabase/api/session_test.clj @@ -453,6 +453,7 @@ (testing "Includes user-local settings" (defsetting test-session-api-setting "test setting" + :encryption :no :user-local :only :type :string :default "FOO") diff --git a/test/metabase/api/setting_test.clj b/test/metabase/api/setting_test.clj index 03ae6f14886faa5b7b72e4c93a3da9d73b7da251..cf29dd9f6d578c35be75cd858a4ce49e2576ce14 100644 --- a/test/metabase/api/setting_test.clj +++ b/test/metabase/api/setting_test.clj @@ -32,7 +32,8 @@ (defsetting test-settings-manager-visibility (deferred-tru "Setting to test the `:settings-manager` visibility level. This only shows up in dev.") - :visibility :settings-manager) + :visibility :settings-manager + :encryption :when-encryption-key-set) ;; ## Helper Fns (defn- fetch-test-settings diff --git a/test/metabase/models/setting/multi_setting_test.clj b/test/metabase/models/setting/multi_setting_test.clj index 12a5fc209fcf8b7eb3a52f1e17cc6f2a20ae66b0..b69ceabc8e34e460ddf811a9ca21c660dd1b90f3 100644 --- a/test/metabase/models/setting/multi_setting_test.clj +++ b/test/metabase/models/setting/multi_setting_test.clj @@ -12,7 +12,8 @@ (multi-setting/define-multi-setting ^:private multi-setting-test-bird-name "A test Setting." (fn [] *parakeet*) - :visibility :internal) + :visibility :internal + :encryption :no) (multi-setting/define-multi-setting-impl multi-setting-test-bird-name :green-friend :getter (constantly "Green Friend") diff --git a/test/metabase/models/setting_test.clj b/test/metabase/models/setting_test.clj index 8742605554173dfd2cd5600d02ccd3e30d80b3ff..cabd53da09ec2f0d630a60e9e5ff1f126b77d9ff 100644 --- a/test/metabase/models/setting_test.clj +++ b/test/metabase/models/setting_test.clj @@ -27,15 +27,18 @@ ;; ## TEST SETTINGS DEFINITIONS (defsetting test-setting-1 - "Test setting - this only shows up in dev (1)") + "Test setting - this only shows up in dev (1)" + :encryption :when-encryption-key-set) (defsetting test-setting-2 "Test setting - this only shows up in dev (2)" - :default "[Default Value]") + :default "[Default Value]" + :encryption :when-encryption-key-set) (defsetting test-setting-3 "Test setting - this only shows up in dev (3)" - :visibility :internal) + :visibility :internal + :encryption :when-encryption-key-set) (defsetting test-boolean-setting "Test setting - this only shows up in dev (3)" @@ -44,26 +47,31 @@ (defsetting test-json-setting "Test setting - this only shows up in dev (4)" - :type :json) + :type :json + :encryption :when-encryption-key-set) (defsetting test-csv-setting "Test setting - this only shows up in dev (5)" :visibility :internal - :type :csv) + :type :csv + :encryption :when-encryption-key-set) (defsetting ^:private test-csv-setting-with-default "Test setting - this only shows up in dev (6)" :visibility :internal :type :csv - :default ["A" "B" "C"]) + :default ["A" "B" "C"] + :encryption :when-encryption-key-set) (defsetting test-env-setting "Test setting - this only shows up in dev (7)" - :visibility :internal) + :visibility :internal + :encryption :when-encryption-key-set) (defsetting toucan-name "Name for the Metabase Toucan mascot." - :visibility :internal) + :visibility :internal + :encryption :when-encryption-key-set) (defsetting test-setting-calculated-getter "Test setting - this only shows up in dev (8)" @@ -74,7 +82,8 @@ (defsetting test-setting-custom-init "Test setting - this only shows up in dev (0)" :type :string - :init (comp str random-uuid)) + :init (comp str random-uuid) + :encryption :when-encryption-key-set) (def ^:private ^:dynamic *enabled?* false) @@ -82,34 +91,37 @@ "Setting to test the `:enabled?` property of settings. This only shows up in dev." :visibility :internal :type :string - :enabled? (fn [] *enabled?*)) + :enabled? (fn [] *enabled?*) + :encryption :when-encryption-key-set) (defsetting test-enabled-setting-default "Setting to test the `:enabled?` property of settings. This only shows up in dev." :visibility :internal :type :string :default "setting-default" - :enabled? (fn [] *enabled?*)) + :enabled? (fn [] *enabled?*) + :encryption :when-encryption-key-set) (defsetting test-feature-setting "Setting to test the `:feature` property of settings. This only shows up in dev." :visibility :internal :type :string :default "setting-default" - :feature :test-feature) + :feature :test-feature + :encryption :when-encryption-key-set) (defsetting test-never-encrypted-setting "Setting to test the `:encryption` property of settings. This only shows up in dev." :visibility :internal :type :string - :encryption :never + :encryption :no :feature :test-feature) (defsetting test-boolean-encrypted-setting "Setting to test that a boolean setting can be encrypted, even though the default is not to. This only shows up in dev." :visibility :internal :type :boolean - :encryption :maybe + :encryption :when-encryption-key-set :feature :test-feature) ;; ## HELPER FUNCTIONS @@ -222,13 +234,15 @@ (defsetting test-no-default-with-base-setting "Setting to test the `:base` property of settings. This only shows up in dev." :visibility :internal - :base base-options) + :base base-options + :encryption :when-encryption-key-set) (defsetting test-default-with-base-setting "Setting to test the `:base` property of settings. This only shows up in dev." :visibility :internal :base base-options - :default "fully-bespoke") + :default "fully-bespoke" + :encryption :when-encryption-key-set) (deftest ^:parallel defsetting-with-base-test (testing "A setting which specifies some base options" @@ -426,7 +440,8 @@ setting))))))) (defsetting test-i18n-setting - (deferred-tru "Test setting - with i18n")) + (deferred-tru "Test setting - with i18n") + :encryption :when-encryption-key-set) (deftest validate-description-test (testing "Validate setting description with i18n string" @@ -444,7 +459,8 @@ (description))))))))) (defsetting test-dynamic-i18n-setting - (deferred-tru "Test setting - with i18n: {0}" (test-i18n-setting))) + (deferred-tru "Test setting - with i18n: {0}" (test-i18n-setting)) + :encryption :when-encryption-key-set) (deftest dynamic-description-test (testing "Descriptions with i18n string should update if it depends on another setting's value." @@ -645,7 +661,8 @@ (defsetting uncached-setting "A test setting that should *not* be cached." :visibility :internal - :cache? false) + :cache? false + :encryption :when-encryption-key-set) (deftest uncached-settings-test (encryption-test/with-secret-key nil @@ -724,23 +741,28 @@ (defsetting test-internal-setting "test Setting" - :visibility :internal) + :visibility :internal + :encryption :when-encryption-key-set) (defsetting test-public-setting (deferred-tru "test Setting") - :visibility :public) + :visibility :public + :encryption :when-encryption-key-set) (defsetting test-authenticated-setting (deferred-tru "test Setting") - :visibility :authenticated) + :visibility :authenticated + :encryption :when-encryption-key-set) (defsetting test-settings-manager-setting (deferred-tru "test Setting") - :visibility :settings-manager) + :visibility :settings-manager + :encryption :when-encryption-key-set) (defsetting test-admin-setting (deferred-tru "test Setting") - :visibility :admin) + :visibility :admin + :encryption :when-encryption-key-set) (deftest can-read-setting-test (testing "no authenticated user" @@ -783,18 +805,21 @@ "test Setting" :visibility :internal :type :integer - :database-local :only) + :database-local :only + :encryption :when-encryption-key-set) (defsetting ^:private test-database-local-allowed-setting (deferred-tru "test Setting") :visibility :authenticated :type :integer - :database-local :allowed) + :database-local :allowed + :encryption :when-encryption-key-set) (defsetting ^:private test-database-local-never-setting "test Setting" :visibility :internal - :type :integer) ; `:never` should be the default + :type :integer + :encryption :when-encryption-key-set) ; `:no` should be the default for `:database-local` (deftest database-local-settings-test (doseq [[database-local-type {:keys [setting-name setting-getter-fn setting-setter-fn returns]}] @@ -883,7 +908,8 @@ (deferred-tru "test Setting") :visibility :authenticated :database-local :only - :default "DEFAULT") + :default "DEFAULT" + :encryption :when-encryption-key-set) (deftest database-local-only-settings-test (testing "Disallow setting Database-local-only Settings" @@ -926,16 +952,19 @@ (defsetting test-user-local-only-setting (deferred-tru "test Setting") :visibility :authenticated - :user-local :only) + :user-local :only + :encryption :when-encryption-key-set) (defsetting test-user-local-allowed-setting (deferred-tru "test Setting") :visibility :authenticated - :user-local :allowed) + :user-local :allowed + :encryption :when-encryption-key-set) (defsetting ^:private test-user-local-never-setting (deferred-tru "test Setting") - :visibility :internal) ; `:never` should be the default + :visibility :internal + :encryption :when-encryption-key-set) ; `:no` should be the default for `:user-local` (deftest user-local-settings-test (testing "Reading and writing a user-local-only setting in the context of a user uses the user-local value" @@ -989,7 +1018,8 @@ (defsetting test-user-local-and-db-local-setting (deferred-tru "test Setting") :user-local :allowed - :database-local :allowed))))) + :database-local :allowed + :encryption :when-encryption-key-set))))) (deftest identity-hash-test (testing "Settings are hashed based on the key" @@ -1045,7 +1075,8 @@ :type :string :default "setting-default" :enabled? (fn [] false) - :feature :test-feature))))) + :feature :test-feature + :encryption :when-encryption-key-set))))) ;;; ------------------------------------------------- Misc tests ------------------------------------------------------- @@ -1069,7 +1100,8 @@ (defsetting ^:private test-integer-setting "test Setting" :visibility :internal - :type :integer) + :type :integer + :encryption :when-encryption-key-set) (deftest integer-setting-test (testing "Should be able to set integer setting with a string" @@ -1085,15 +1117,15 @@ (testing "Should not be able to define a setting with a retired name" (with-redefs [setting/retired-setting-names #{"retired-setting"}] (try - (defsetting retired-setting (deferred-tru "A retired setting name")) + (defsetting retired-setting (deferred-tru "A retired setting name") :encryption :when-encryption-key-set) (catch Exception e (is (= "Setting name 'retired-setting' is retired; use a different name instead" (ex-message e)))))))) (deftest duplicated-setting-name (testing "can re-register a setting in the same ns (redefining or reloading ns)" - (is (defsetting foo (deferred-tru "A testing setting") :visibility :public)) - (is (defsetting foo (deferred-tru "A testing setting") :visibility :public))) + (is (defsetting foo (deferred-tru "A testing setting") :visibility :public :encryption :when-encryption-key-set)) + (is (defsetting foo (deferred-tru "A testing setting") :visibility :public :encryption :when-encryption-key-set))) (testing "if attempt to register in a different ns throws an error" (let [current-ns (ns-name *ns*)] (try @@ -1101,7 +1133,7 @@ (:require [metabase.models.setting :refer [defsetting]] [metabase.util.i18n :as i18n :refer [deferred-tru]])) - (defsetting foo (deferred-tru "A testing setting") :visibility :public) + (defsetting foo (deferred-tru "A testing setting") :visibility :public :encryption :when-encryption-key-set) (catch Exception e (is (=? {:existing-setting {:description (deferred-tru "A testing setting") @@ -1119,7 +1151,8 @@ (defsetting test-setting-with-question-mark? "Test setting - this only shows up in dev (6)" - :visibility :internal) + :visibility :internal + :encryption :when-encryption-key-set) (deftest munged-setting-name-test (testing "Only valid characters used for environment lookup" @@ -1138,29 +1171,34 @@ (m/map-vals #(select-keys % [:name :munged-name]) (try (defsetting test-setting-with-question-mark???? "Test setting - this only shows up in dev (6)" - :visibility :internal) + :visibility :internal + :encryption :when-encryption-key-set) (catch Exception e (ex-data e))))))) (testing "Munge collision on first definition" (defsetting test-setting-normal "Test setting - this only shows up in dev (6)" - :visibility :internal) + :visibility :internal + :encryption :when-encryption-key-set) (is (= {:existing-setting {:name :test-setting-normal, :munged-name "test-setting-normal"}, :new-setting {:name :test-setting-normal??, :munged-name "test-setting-normal"}} (m/map-vals #(select-keys % [:name :munged-name]) (try (defsetting test-setting-normal?? "Test setting - this only shows up in dev (6)" - :visibility :internal) + :visibility :internal + :encryption :when-encryption-key-set) (catch Exception e (ex-data e))))))) (testing "Munge collision on second definition" (defsetting test-setting-normal-1?? "Test setting - this only shows up in dev (6)" - :visibility :internal) + :visibility :internal + :encryption :when-encryption-key-set) (is (= {:new-setting {:munged-name "test-setting-normal-1", :name :test-setting-normal-1}, :existing-setting {:munged-name "test-setting-normal-1", :name :test-setting-normal-1??}} (m/map-vals #(select-keys % [:name :munged-name]) (try (defsetting test-setting-normal-1 "Test setting - this only shows up in dev (6)" - :visibility :internal) + :visibility :internal + :encryption :when-encryption-key-set) (catch Exception e (ex-data e))))))) (testing "Removes characters not-compliant with shells" (is (= "aa1aa-b2b_cc3c" @@ -1210,14 +1248,16 @@ (try (walk/macroexpand-all `(defsetting ~'test-asdf-asdf-asdf - "untranslated description")) + "untranslated description" + :encryption :when-encryption-key-set)) (catch Exception e (is (re-matches #"defsetting docstrings must be a \*deferred\* i18n form.*" (:cause (Throwable->map e))))))))) (defsetting test-setting-audit-never "Test setting with no auditing" - :audit :never) + :audit :never + :encryption :when-encryption-key-set) (defsetting test-setting-audit-raw-value "Test setting with auditing raw values" @@ -1226,15 +1266,17 @@ (defsetting test-setting-audit-getter "Test setting with auditing values returned from getter" - :type :string - :getter (constantly "GETTER VALUE") - :audit :getter) + :type :string + :getter (constantly "GETTER VALUE") + :audit :getter + :encryption :when-encryption-key-set) (defsetting test-sensitive-setting-audit "Test that a sensitive setting has its value obfuscated before being audited" :type :string :sensitive? true - :audit :getter) + :audit :getter + :encryption :when-encryption-key-set) (deftest setting-audit-test (mt/with-premium-features #{:audit-app} @@ -1293,6 +1335,7 @@ (deferred-tru "Audited user-local setting") :visibility :authenticated :user-local :only + :encryption :when-encryption-key-set :audit :raw-value) (deftest user-local-settings-audit-test @@ -1319,11 +1362,13 @@ (defsetting exported-setting "This setting would be serialized" :export? true + :encryption :when-encryption-key-set ;; make sure it's internal so it doesn't interfere with export test :visibility :internal) (defsetting non-exported-setting "This setting would not be serialized" + :encryption :when-encryption-key-set :export? false) (deftest export?-test @@ -1354,7 +1399,8 @@ (defmacro define-setting-for-type [format] `(defsetting ~(validation-setting-symbol format) "Setting to test validation of this format - this only shows up in dev" - :type ~(keyword (name format)))) + :type ~(keyword (name format)) + :encryption :when-encryption-key-set)) (defmacro get-parse-exception [format raw-value] `(mt/with-temp-env-var-value! [~(symbol (str "mb-" (validation-setting-symbol format))) ~raw-value] @@ -1554,6 +1600,6 @@ (deftest boolean-settings-default-to-never-encrypted (testing "Boolean settings default to never encrypted" - (is (= :never (:encryption (setting/resolve-setting :test-boolean-setting))))) + (is (= :no (:encryption (setting/resolve-setting :test-boolean-setting))))) (testing "Boolean settings can be encrypted" - (is (= :maybe (:encryption (setting/resolve-setting :test-boolean-encrypted-setting)))))) + (is (= :when-encryption-key-set (:encryption (setting/resolve-setting :test-boolean-encrypted-setting)))))) diff --git a/test/metabase/test/data/interface.clj b/test/metabase/test/data/interface.clj index 30805fd67964410b2d74ad8cdd8febab32718048..99de1584098173327cd3366d900e685521399c9e 100644 --- a/test/metabase/test/data/interface.clj +++ b/test/metabase/test/data/interface.clj @@ -40,6 +40,7 @@ (defsetting database-source-dataset-name "The name of the test dataset this Database was created from, if any." + :encryption :no :visibility :internal :type :string :database-local :only) diff --git a/test/metabase/test/util_test.clj b/test/metabase/test/util_test.clj index 5b806fad98e195543f1126e3cec801b7b8299f02..5903e61f32445de523202909d5373c8bd2f95c11 100644 --- a/test/metabase/test/util_test.clj +++ b/test/metabase/test/util_test.clj @@ -35,7 +35,8 @@ "Another internal test setting" :visibility :internal :default ["A" "B" "C"] - :type :csv) + :type :csv + :encryption :no) (deftest with-temporary-setting-values-test (testing "`with-temporary-setting-values` should do its thing"