Skip to content
Snippets Groups Projects
Unverified Commit 44b23fe8 authored by Robert Roland's avatar Robert Roland Committed by GitHub
Browse files

Obfuscate database details in the APIs (#13440)

* Obfuscate database details in the APIs

This will stop us from sending sensitive info (passwords, keys) via the
API for authenticated administrators. Note that non-administrator users
were never privvy to these fields.

* Use cleaner form suggested by Cam

* make sensitive field list a const
parent 802dde1a
No related branches found
No related tags found
No related merge requests found
(ns metabase.models.database
(:require [cheshire.generate :refer [add-encoder encode-map]]
[clojure.tools.logging :as log]
[medley.core :as m]
[metabase
[db :as mdb]
[driver :as driver]
......@@ -151,15 +152,22 @@
"The string to replace passwords with when serializing Databases."
"**MetabasePass**")
(def ^:const sensitive-fields
"List of fields that should be obfuscated in API responses, as they contain sensitive data."
[:password :pass :tunnel-pass :tunnel-private-key :tunnel-private-key-passphrase
:access-token :refresh-token :service-account-json])
;; when encoding a Database as JSON remove the `details` for any non-admin User. For admin users they can still see
;; the `details` but remove the password. No one gets to see this in an API response!
;; the `details` but remove anything resembling a password. No one gets to see this in an API response!
(add-encoder
DatabaseInstance
(fn [db json-generator]
(encode-map
(cond
(not (:is_superuser @*current-user*)) (dissoc db :details)
(get-in db [:details :password]) (assoc-in db [:details :password] protected-password)
(get-in db [:details :pass]) (assoc-in db [:details :pass] protected-password) ; MongoDB uses "pass" instead of password
:else db)
(if (not (:is_superuser @*current-user*))
(dissoc db :details)
(update db :details (fn [details]
(reduce
#(m/update-existing %1 %2 (constantly protected-password))
details
sensitive-fields))))
json-generator)))
(ns metabase.models.database-test
(:require [clojure
(:require [cheshire.core :refer [decode encode]]
[clojure
[string :as str]
[test :refer :all]]
[metabase
[models :refer [Database]]
[task :as task]
[test :as mt]]
[metabase.middleware.session :as mw.session]
[metabase.models
[database :as mdb]
[permissions :as perms]
[user :as user]]
[metabase.plugins.classloader :as classloader]
......@@ -47,3 +50,80 @@
(db/delete! Database :id db-id)
(is (= nil
(trigger-for-db db-id))))))))
(deftest sensitive-data-redacted-test
(let [encode-decode (fn [obj] (decode (encode obj)))
;; this is trimmed for the parts we care about in the test
pg-db (mdb/map->DatabaseInstance
{:description nil
:name "testpg"
:details {:additional-options nil
:ssl false
:password "Password1234"
:tunnel-host "localhost"
:port 5432
:dbname "mydb"
:host "localhost"
:tunnel-enabled true
:tunnel-auth-option "ssh-key"
:tunnel-port 22
:tunnel-private-key "PRIVATE KEY IS HERE"
:user "metabase"
:tunnel-user "a-tunnel-user"
:tunnel-private-key-passphrase "Password1234"}
:id 3})
bq-db (mdb/map->DatabaseInstance
{:description nil
:name "testbq"
:details {:use-service-account nil
:dataset-id "office_checkins"
:service-account-json "SERVICE-ACCOUNT-JSON-HERE"
:use-jvm-timezone false
:project-id "metabase-bigquery-driver"}
:id 2
:engine :bigquery})]
(testing "sensitive fields are redacted when database details are encoded"
(testing "details removed for non-admin users"
(mw.session/with-current-user
(mt/user->id :rasta)
(is (= {"description" nil
"name" "testpg"
"id" 3}
(encode-decode pg-db)))
(is (= {"description" nil
"name" "testbq"
"id" 2
"engine" "bigquery"}
(encode-decode bq-db)))))
(testing "details are obfuscated for admin users"
(mw.session/with-current-user
(mt/user->id :crowberto)
(is (= {"description" nil
"name" "testpg"
"details" {"tunnel-user" "a-tunnel-user"
"dbname" "mydb"
"host" "localhost"
"tunnel-auth-option" "ssh-key"
"tunnel-private-key-passphrase" "**MetabasePass**"
"additional-options" nil
"tunnel-port" 22
"user" "metabase"
"tunnel-private-key" "**MetabasePass**"
"ssl" false
"tunnel-enabled" true
"port" 5432
"password" "**MetabasePass**"
"tunnel-host" "localhost"}
"id" 3}
(encode-decode pg-db)))
(is (= {"description" nil
"name" "testbq"
"details" {"use-service-account" nil
"dataset-id" "office_checkins"
"service-account-json" "**MetabasePass**"
"use-jvm-timezone" false
"project-id" "metabase-bigquery-driver"}
"id" 2
"engine" "bigquery"}
(encode-decode bq-db))))))))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment