diff --git a/src/metabase/api/session.clj b/src/metabase/api/session.clj index b8856e1b717dcfd82bd8678ebf6e11e5bd738529..19b3ff54986f0a8febdf96fae0e8a515466382e4 100644 --- a/src/metabase/api/session.clj +++ b/src/metabase/api/session.clj @@ -15,7 +15,7 @@ [metabase.models.login-history :refer [LoginHistory]] [metabase.models.pulse :as pulse] [metabase.models.session :refer [Session]] - [metabase.models.setting :as setting] + [metabase.models.setting :as setting :refer [defsetting]] [metabase.models.user :as user :refer [User]] [metabase.public-settings :as public-settings] [metabase.server.middleware.session :as mw.session] @@ -232,9 +232,17 @@ (forgot-password-impl email) api/generic-204-no-content) -(def ^:private ^:const reset-token-ttl-ms - "Number of milliseconds a password reset is considered valid." - (* 48 60 60 1000)) ; token considered valid for 48 hours + +(defsetting reset-token-ttl-hours + (deferred-tru "Number of hours a password reset is considered valid.") + :visibility :internal + :type :integer + :default 48) + +(defn reset-token-ttl-ms + "number of milliseconds a password reset is considered valid." + [] + (* (reset-token-ttl-hours) 60 60 1000)) (defn- valid-reset-token->user "Check if a password reset token is valid. If so, return the `User` ID it corresponds to." @@ -249,7 +257,7 @@ (u.password/bcrypt-verify token reset_token)) ;; check that the reset was triggered within the last 48 HOURS, after that the token is considered expired (let [token-age (- (System/currentTimeMillis) reset_triggered)] - (when (< token-age reset-token-ttl-ms) + (when (< token-age (reset-token-ttl-ms)) user))))))) #_{:clj-kondo/ignore [:deprecated-var]} diff --git a/test/metabase/api/session_test.clj b/test/metabase/api/session_test.clj index 881783f098d0b74a8df0899f7ee96efeaee9611b..a80be1933fd11e8a62baa4cdfe5d89d9676427a0 100644 --- a/test/metabase/api/session_test.clj +++ b/test/metabase/api/session_test.clj @@ -358,6 +358,28 @@ (is (= {:valid false} (mt/client :get 200 "session/password_reset_token_valid", :token token))))))) +(deftest reset-token-ttl-hours-test + (testing "Test reset-token-ttl-hours-test" + (testing "reset-token-ttl-hours-test is reset to default when not set" + (mt/with-temp-env-var-value [mb-reset-token-ttl-hours nil] + (is (= 48 (setting/get-value-of-type :integer :reset-token-ttl-hours))))) + + (testing "reset-token-ttl-hours-test is set to positive value" + (mt/with-temp-env-var-value [mb-reset-token-ttl-hours 36] + (is (= 36 (setting/get-value-of-type :integer :reset-token-ttl-hours))))) + + (testing "reset-token-ttl-hours-test is set to large positive value" + (mt/with-temp-env-var-value [mb-reset-token-ttl-hours (+ Integer/MAX_VALUE 1)] + (is (= (+ Integer/MAX_VALUE 1) (setting/get-value-of-type :integer :reset-token-ttl-hours))))) + + (testing "reset-token-ttl-hours-test is set to zero" + (mt/with-temp-env-var-value [mb-reset-token-ttl-hours 0] + (is (= 0 (setting/get-value-of-type :integer :reset-token-ttl-hours))))) + + (testing "reset-token-ttl-hours-test is set to negative value" + (mt/with-temp-env-var-value [mb-reset-token-ttl-hours -1] + (is (= -1 (setting/get-value-of-type :integer :reset-token-ttl-hours))))))) + (deftest properties-test (reset-throttlers!) (testing "GET /session/properties"