airgap token check user creation fix (#66770)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -30,7 +30,7 @@
|
||||
(concat ["You can use `./bin/mage <task> --help` to get more information? It works with every task."
|
||||
"Remember: You can check private tasks with `./bin/mage ls`"
|
||||
"Fun fact: The word 'mage' comes from the Latin 'magus', meaning 'wise'"
|
||||
"Pro tip: You can setup autocomplete for mage to speed up your workflow with " (c/cyan "./bin/mage alias.")]
|
||||
(str "Pro tip: You can setup autocomplete for mage to speed up your workflow with " (c/cyan "./bin/mage alias."))]
|
||||
(zen))))
|
||||
|
||||
(defn- print-help []
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
@@ -142,6 +143,7 @@
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
[metabase.logger.core :as logger]
|
||||
[metabase.notification.core :as notification]
|
||||
[metabase.plugins.core :as plugins]
|
||||
[metabase.premium-features.core :as premium-features :refer [defenterprise]]
|
||||
[metabase.premium-features.core :refer [defenterprise]]
|
||||
[metabase.sample-data.core :as sample-data]
|
||||
[metabase.server.core :as server]
|
||||
[metabase.settings.core :as setting]
|
||||
@@ -182,8 +182,6 @@
|
||||
(log/info "Setting up prometheus metrics")
|
||||
(analytics/setup!)
|
||||
(init-status/set-progress! 0.5)
|
||||
(premium-features/airgap-check-user-count)
|
||||
(init-status/set-progress! 0.55)
|
||||
(task/init-scheduler!)
|
||||
(analytics/add-listeners-to-scheduler!)
|
||||
;; run a very quick check to see if we are doing a first time installation
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
|
||||
[metabase.premium-features.token-check
|
||||
;; TODO: move airgap code to a dedicated namespace?
|
||||
airgap-check-user-count
|
||||
assert-valid-airgap-user-count!
|
||||
assert-airgap-allows-user-creation!
|
||||
assert-has-feature
|
||||
assert-has-any-features
|
||||
ee-feature-error
|
||||
|
||||
@@ -169,7 +169,6 @@
|
||||
(let [{:keys [body status] :as resp} (http-fetch base-url token site-uuid)]
|
||||
(cond
|
||||
(http/success? resp) (some-> body json/decode+kw)
|
||||
;; todo: what happens if there's no response here? probably should or here
|
||||
(<= 400 status 499) (or (some-> body json/decode+kw)
|
||||
{:valid false
|
||||
:status "Unable to validate token"
|
||||
@@ -191,14 +190,31 @@
|
||||
(let [max-users (:max-users (decode-airgap-token token))]
|
||||
(when (pos? max-users) max-users)))))
|
||||
|
||||
(defn airgap-check-user-count
|
||||
"Checks that, when in an airgap context, the allowed user count is acceptable."
|
||||
(defn- active-user-count []
|
||||
;; Because we need this count *during* token checks, this uses `t2/table-name` to avoid the `after-select` method
|
||||
;; on users, which calls an EE method that needs ... a token check :|
|
||||
(t2/count (t2/table-name :model/User) :is_active true, :type "personal"))
|
||||
|
||||
(defn assert-valid-airgap-user-count!
|
||||
"Asserts that, in an airgap context, the current user count does not exceed the allowed maximum.
|
||||
Throws if the limit is exceeded. Called when setting the token."
|
||||
[]
|
||||
(when-let [max-users (max-users-allowed)]
|
||||
;; Because we need this count *during* token checks, this uses `t2/table-name` to avoid the `after-select` method
|
||||
;; on users, which calls an EE method that needs ... a token check :|
|
||||
(when (> (t2/count (t2/table-name :model/User) :is_active true, :type "personal") max-users)
|
||||
(throw (Exception. (trs "You have reached the maximum number of users ({0}) for your plan. Please upgrade to add more users." max-users))))))
|
||||
(let [current-users (active-user-count)]
|
||||
(when (> current-users max-users)
|
||||
(throw (Exception.
|
||||
(trs "You have reached the maximum number of users ({0}) for your plan. Please upgrade to add more users."
|
||||
max-users)))))))
|
||||
|
||||
(defn assert-airgap-allows-user-creation!
|
||||
"Asserts that creating a new personal user would not exceed the airgap user limit.
|
||||
Throws if adding another user would overflow the limit. Called in user pre-insert."
|
||||
[]
|
||||
(when-let [max-users (max-users-allowed)]
|
||||
(when (>= (active-user-count) max-users)
|
||||
(throw (Exception.
|
||||
(trs "Adding another user would exceed the maximum number of users ({0}) for your plan. Please upgrade to add more users."
|
||||
max-users))))))
|
||||
|
||||
(mu/defn- decode-token* :- TokenStatus
|
||||
"Decode a token. If you get a positive response about the token, even if it is not valid, return that. Errors will
|
||||
@@ -422,7 +438,7 @@
|
||||
(try
|
||||
(when (seq new-value)
|
||||
(when (mr/validate [:re AirgapToken] new-value)
|
||||
(airgap-check-user-count))
|
||||
(assert-valid-airgap-user-count!))
|
||||
(when-not (or (mr/validate [:re RemoteCheckedToken] new-value)
|
||||
(mr/validate [:re AirgapToken] new-value))
|
||||
(throw (ex-info (tru "Token format is invalid.")
|
||||
|
||||
@@ -120,7 +120,8 @@
|
||||
(validate-user-type! user-type)
|
||||
(validate-user-locale! locale)
|
||||
(validate-sso-setup! sso_source)
|
||||
(premium-features/airgap-check-user-count))
|
||||
(when (or (nil? user-type) (= user-type :personal))
|
||||
(premium-features/assert-airgap-allows-user-creation!)))
|
||||
|
||||
;;; -------------------------------------------------- Password Management --------------------------------------------------
|
||||
|
||||
|
||||
@@ -255,3 +255,49 @@
|
||||
(is (not (mr/validate [:re @#'token-check/RemoteCheckedToken] (apply str (repeat 65 "a")))))
|
||||
(is (not (mr/validate [:re @#'token-check/RemoteCheckedToken] (apply str (repeat 63 "a")))))
|
||||
(is (not (mr/validate [:re @#'token-check/RemoteCheckedToken] (apply str "mb_dev_" (repeat 53 "a")))))))
|
||||
|
||||
(deftest assert-valid-airgap-user-count-test
|
||||
(testing "no limit set - no error"
|
||||
(with-redefs [token-check/max-users-allowed (constantly nil)]
|
||||
(is (nil? (token-check/assert-valid-airgap-user-count!)))))
|
||||
|
||||
(testing "under limit - no error"
|
||||
(with-redefs [token-check/max-users-allowed (constantly 10)
|
||||
token-check/active-user-count (constantly 5)]
|
||||
(is (nil? (token-check/assert-valid-airgap-user-count!)))))
|
||||
|
||||
(testing "at limit - no error"
|
||||
(with-redefs [token-check/max-users-allowed (constantly 10)
|
||||
token-check/active-user-count (constantly 10)]
|
||||
(is (nil? (token-check/assert-valid-airgap-user-count!)))))
|
||||
|
||||
(testing "over limit - throws"
|
||||
(with-redefs [token-check/max-users-allowed (constantly 10)
|
||||
token-check/active-user-count (constantly 11)]
|
||||
(is (thrown-with-msg? Exception
|
||||
#"You have reached the maximum number of users"
|
||||
(token-check/assert-valid-airgap-user-count!))))))
|
||||
|
||||
(deftest assert-airgap-allows-user-creation-test
|
||||
(testing "no limit set - no error"
|
||||
(with-redefs [token-check/max-users-allowed (constantly nil)]
|
||||
(is (nil? (token-check/assert-airgap-allows-user-creation!)))))
|
||||
|
||||
(testing "under limit - no error (room for one more)"
|
||||
(with-redefs [token-check/max-users-allowed (constantly 10)
|
||||
token-check/active-user-count (constantly 9)]
|
||||
(is (nil? (token-check/assert-airgap-allows-user-creation!)))))
|
||||
|
||||
(testing "at limit - throws (no room for another)"
|
||||
(with-redefs [token-check/max-users-allowed (constantly 10)
|
||||
token-check/active-user-count (constantly 10)]
|
||||
(is (thrown-with-msg? Exception
|
||||
#"Adding another user would exceed the maximum"
|
||||
(token-check/assert-airgap-allows-user-creation!)))))
|
||||
|
||||
(testing "over limit - throws"
|
||||
(with-redefs [token-check/max-users-allowed (constantly 10)
|
||||
token-check/active-user-count (constantly 11)]
|
||||
(is (thrown-with-msg? Exception
|
||||
#"Adding another user would exceed the maximum"
|
||||
(token-check/assert-airgap-allows-user-creation!))))))
|
||||
|
||||
Reference in New Issue
Block a user