Skip to content

Commit

Permalink
Get jwt from cookie and validation key from file
Browse files Browse the repository at this point in the history
  • Loading branch information
grios-stratio committed Jan 31, 2024
1 parent c0ba2ea commit e422a52
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 39 deletions.
19 changes: 14 additions & 5 deletions src/metabase/stratio/auth.clj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
;; a set can act as a predicate!
(some whitelist groups)))

(defn- tenant-allowed?
[user-tenant]
(let [app-tenant (st.config/config-str :tenant)]
(or (not user-tenant)
(not app-tenant)
(= user-tenant app-tenant))))

(defn- admin?
[groups]
(contains? (set groups) admin-group))
Expand All @@ -46,14 +53,16 @@
superuser? (conj group/admin-group-name)))

(defn- allowed-user
[{:keys [user groups error]}]
[{:keys [user groups email tenant error]}]
(if error
{:error error}
(if (allowed? groups)
(if (and (allowed? groups) (tenant-allowed? tenant))
{:first_name user
:last_name ""
:is_superuser (admin? groups)
:email (if (u/email? user) user (u/lower-case-en (str user dummy-email-domain)))
:email (cond email email
(u/email? user) user
:else (u/lower-case-en (str user dummy-email-domain)))
:login_attributes {:groups groups}}
{:error (str "User " user " not allowed")})))

Expand Down Expand Up @@ -102,8 +111,8 @@
user-inserted)))

(defn create-session-from-headers!
[{headers :headers, :as request}]
(let [user-info (http-headers->user-info headers)
[request]
(let [user-info (http-headers->user-info request)
allowed-user (allowed-user user-info)]
(log/debug "received user info " user-info)
(if (:error allowed-user)
Expand Down
37 changes: 31 additions & 6 deletions src/metabase/stratio/config.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
(ns metabase.stratio.config
(:require [clojure.string :as str]
(:require [buddy.core.keys :as keys]
[clj-http.client :as http]
[clojure.string :as str]
[metabase.config :as config]
[metabase.models.setting :refer [defsetting]]
[metabase.stratio.util :as st.util]))
Expand All @@ -11,8 +13,13 @@
:jwt-header-name "X-USER-TOKEN"
:jwt-username-claim "sub"
:jwt-groups-claim "groups"
:jwt-tenant-claim "tenant"
:jwt-email-claim "mail"
:jwt-public-key-location "url"
:jwt-public-key-endpoint ""
:jwt-public-key-file "/etc/pki/jwt-public-key.pem"
:jwt-insecure-request-pkey "false"
:jwt-cookie-name "stratio-cookie"

;; settings for authentication via headers
:mb-user-header ""
Expand All @@ -32,15 +39,33 @@
(defn config-kw [k] (some-> k config-str keyword))
(defn config-vector [k] (st.util/make-vector (config-str k)))

(defn- ssl-config []
(if (config-bool :jwt-insecure-request-pkey)
{:insecure? true}
{:trust-store (config-str :mb-jetty-ssl-truststore)
:trust-store-pass (config-str :mb-jetty-ssl-truststore-password)}))

(def auto-login-authenticators #{:jwt :headers :gosec-sso})
(def authenticator (config-kw :authenticator))
(def should-auto-login? (contains? auto-login-authenticators authenticator))
(def jwt? (= authenticator :jwt))
(def gosec-sso? (= authenticator :gosec-sso))
(def authenticator (config-kw :authenticator))
(def jwt-public-key-location (config-kw :jwt-public-key-location))
(def should-auto-login? (contains? auto-login-authenticators authenticator))
(def jwt? (= authenticator :jwt))
(def gosec-sso? (= authenticator :gosec-sso))
(def headers? (= authenticator :headers))
(def jwt-cookie-name (config-str :jwt-cookie-name))
(def jwt-public-key (delay
(if (= jwt-public-key-location :file)
(-> (config-str :jwt-public-key-file)
(slurp)
(keys/str->public-key))
(-> (config-str :jwt-public-key-endpoint)
(http/get (ssl-config))
(:body)
(keys/str->public-key)))))

;; We need to define a setting so it can reach frontend via MetabaseSettings object
(defsetting gosec-sso-enabled
"flag to tell the front end if we are behing the sso proxy so when logout redirect to proxy logout"
"flag to tell the front end if we are behind the sso proxy so when logout redirect to proxy logout"
:type :boolean
:default gosec-sso?
:visibility :public
Expand Down
62 changes: 34 additions & 28 deletions src/metabase/stratio/header_user_info.clj
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
(:alg (parse-header token)))


(defn- http-header->jwt-token
(defn- http-headers->jwt-token
[headers]
(let [header-name (st.config/config-str :jwt-header-name)
header-name-lower (str/lower-case header-name)]
Expand All @@ -52,47 +52,53 @@
(contains? headers header-name-lower) (get headers header-name-lower)
:else (throw (Exception. "Could not find Authorization header")))))


(defn- http-cookies->jwt-token
[cookies]
(or (get-in cookies [st.config/jwt-cookie-name :value])
(throw (Exception. (str "Could not find cookie '" st.config/jwt-cookie-name "'")))))


(defn- http-request->jwt-token
[{:keys [headers cookies]}]
(cond
st.config/gosec-sso? (http-cookies->jwt-token cookies)
st.config/jwt? (http-headers->jwt-token headers)))


(defn- verify-token
[token pkey]
(let [alg (get-alg token)]
(jwt/unsign token pkey {:alg alg})))


(defn- ssl-config []
(if (st.config/config-bool :jwt-insecure-request-pkey)
{:insecure? true}
{:trust-store (config/config-str :mb-jetty-ssl-truststore)
:trust-store-pass (config/config-str :mb-jetty-ssl-truststore-password)}))

(defn- get-verification-key
[url]
(-> url
(http/get (ssl-config))
(:body)
(keys/str->public-key)))


(defn- http-headers->user-info-jwt
"Gets user info map {:user username :groups [group1 ... groupN]} from jwt token in headers
or map with :error key if some error happens"
[headers]
(defn- http-request->user-info-jwt
"Gets user info map {:user username, :groups [group1 ... groupN], :email email, :tenant tenant}
from jwt token in headers or in cookie. The :email and :tenant may not be present in the jwt.
If some error happens a map with an :error key is returned."
[request]
(log/debug "Getting user info from JWT token")
(try
(let [username-claim (st.config/config-kw :jwt-username-claim)
groups-claim (st.config/config-kw :jwt-groups-claim)
token (http-header->jwt-token headers)
pkey (get-verification-key (st.config/config-str :jwt-public-key-endpoint))]
email-claim (st.config/config-kw :jwt-email-claim)
tenant-claim (st.config/config-kw :jwt-tenant-claim)
token (http-request->jwt-token request)
pkey @st.config/jwt-public-key]
(cond
(not token) {:error "Could not obtain jwt token from request headers"}
(not pkey) {:error "Could not obtain verification key for jwt token"}
pkey (let [info (-> token
(verify-token pkey)
(select-keys [username-claim groups-claim])
(update-in [groups-claim] st.util/make-vector))
(select-keys [username-claim groups-claim email-claim tenant-claim])
(update-in [groups-claim] st.util/ensure-vector))
user-name (username-claim info)]
(if (empty? user-name)
{:error "No username claim found in token"}
{:user user-name :groups (groups-claim info)}))))
{:user user-name
:groups (groups-claim info)
:email (email-claim info)
:tenant (tenant-claim info)}))))
(catch Exception e
{:error (st.util/stack-trace e)})))

Expand All @@ -116,7 +122,7 @@
(defn http-headers->user-info
"Gets user info map {:user username :groups [group1 ... groupN]} either form jwt token
or headers depending on config; or map with :error key if some error happens"
[headers]
(if st.config/jwt?
(http-headers->user-info-jwt headers)
(http-headers->user-info-headers headers)))
[{headers :headers, :as request}]
(if st.config/headers?
(http-headers->user-info-headers headers)
(http-request->user-info-jwt request)))
7 changes: 7 additions & 0 deletions src/metabase/stratio/util.clj
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,12 @@
(filterv #(not (empty? %))))))


(defn ensure-vector
[string-or-coll]
(if (instance? java.lang.String string-or-coll)
(make-vector string-or-coll)
(vec string-or-coll)))


(defn stack-trace [e]
(with-out-str (clojure.stacktrace/print-stack-trace e)))

0 comments on commit e422a52

Please sign in to comment.