diff --git a/backend/src/app/auth/oidc.clj b/backend/src/app/auth/oidc.clj index 93330b4e4d..7668a49b99 100644 --- a/backend/src/app/auth/oidc.clj +++ b/backend/src/app/auth/oidc.clj @@ -36,17 +36,6 @@ [integrant.core :as ig] [yetti.response :as-alias yres])) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; HELPERS -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defn obfuscate-string - [s] - (if (< (count s) 10) - (apply str (take (count s) (repeat "*"))) - (str (subs s 0 5) - (apply str (take (- (count s) 5) (repeat "*")))))) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; OIDC PROVIDER (GENERIC) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -177,7 +166,7 @@ (l/inf :hint "provider initialized" :provider (:id provider) :client-id (:client-id provider) - :client-secret (obfuscate-string (:client-secret provider))) + :client-secret (d/obfuscate-string (:client-secret provider))) provider) (catch Throwable cause @@ -222,7 +211,7 @@ (l/inf :hint "provider initialized" :provider (:id provider) :client-id (:client-id provider) - :client-secret (obfuscate-string (:client-secret provider))) + :client-secret (d/obfuscate-string (:client-secret provider))) provider) (catch Throwable cause @@ -299,7 +288,7 @@ (l/inf :hint "provider initialized" :provider (:id provider) :client-id (:client-id provider) - :client-secret (obfuscate-string (:client-secret provider))) + :client-secret (d/obfuscate-string (:client-secret provider))) provider) (catch Throwable cause @@ -341,7 +330,7 @@ :provider "gitlab" :base-uri (:base-uri provider) :client-id (:client-id provider) - :client-secret (obfuscate-string (:client-secret provider))) + :client-secret (d/obfuscate-string (:client-secret provider))) provider) (catch Throwable cause (ex/raise :type ::internal @@ -361,7 +350,7 @@ (l/inf :hint "provider initialized" :provider (:id provider) :client-id (:client-id provider) - :client-secret (obfuscate-string (:client-secret provider))) + :client-secret (d/obfuscate-string (:client-secret provider))) provider) (catch Throwable cause @@ -459,7 +448,7 @@ (l/trc :hint "fetch access token" :provider (:id provider) :client-id (:client-id provider) - :client-secret (obfuscate-string (:client-secret provider)) + :client-secret (d/obfuscate-string (:client-secret provider)) :grant-type (:grant_type params) :redirect-uri (:redirect_uri params)) @@ -512,7 +501,7 @@ [cfg provider tdata] (l/trc :hint "fetch user info" :uri (:user-uri provider) - :token (obfuscate-string (:token/access tdata))) + :token (d/obfuscate-string (:token/access tdata))) (let [params {:uri (:user-uri provider) :headers {"Authorization" (str (:token/type tdata) " " (:token/access tdata))} diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index 015246c005..6f05c439da 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -1024,6 +1024,26 @@ :clj (sort comp-fn items)))) +(defn obfuscate-string + "Obfuscates potentially sensitive values. + + - One-arg arity: + * For strings shorter than 10 characters, all characters are replaced by `*`. + * For longer strings, the first 5 characters are preserved and the rest obfuscated. + - Two-arg arity accepts a boolean `full?` that, when true, replaces the whole value + by `*`, preserving only the length." + ([v] + (obfuscate-string v false)) + ([v full?] + (let [s (str v) + n (count s)] + (cond + (zero? n) s + full? (apply str (repeat n "*")) + (< n 10) (apply str (repeat n "*")) + :else (str (subs s 0 5) + (apply str (repeat (- n 5) "*"))))))) + (defn reorder "Reorder a vector by moving one of their items from some position to some space between positions. It clamps the position numbers to a valid range." diff --git a/common/src/app/common/exceptions.cljc b/common/src/app/common/exceptions.cljc index 6def4ef91c..8a0a9cf834 100644 --- a/common/src/app/common/exceptions.cljc +++ b/common/src/app/common/exceptions.cljc @@ -10,6 +10,7 @@ (:refer-clojure :exclude [instance?]) (:require #?(:clj [clojure.stacktrace :as strace]) + [app.common.data :refer [obfuscate-string]] [app.common.pprint :as pp] [app.common.schema :as sm] [clojure.core :as c] @@ -19,6 +20,10 @@ (:import clojure.lang.IPersistentMap))) +(def ^:private sensitive-fields + "Keys whose values must be obfuscated in validation explains." + #{:password :old-password :token :invitation-token}) + #?(:clj (set! *warn-on-reflection* true)) (def ^:dynamic *data-length* 8) @@ -110,7 +115,25 @@ (explain (:explain data) opts) (contains? data ::sm/explain) - (sm/humanize-explain (::sm/explain data) opts))) + (let [exp (::sm/explain data) + sanitize-map (fn sanitize-map [m] + (reduce-kv + (fn [acc k v] + (let [k* (if (string? k) (keyword k) k)] + (cond + (contains? sensitive-fields k*) + (assoc acc k (if (map? v) + (sanitize-map v) + (obfuscate-string v true))) + + (map? v) (assoc acc k (sanitize-map v)) + :else (assoc acc k v)))) + {} + m)) + sanitize-explain (fn [exp] + (cond-> exp + (:value exp) (update :value sanitize-map)))] + (sm/humanize-explain (sanitize-explain exp) opts)))) #?(:clj (defn format-throwable