diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-08-01 01:10:35 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-08-01 01:10:35 +0200 |
| commit | f6c1f0f08f031778a491465d35ac694bfcdc12b0 (patch) | |
| tree | 99aec0f419b1122821124fdb7ae8bdf4bc5831db /test | |
| parent | df90138fb55f7d3652d3d69d58325d7329920f51 (diff) | |
Require a fresh second factor for user management
Administrative actions are gated behind a 30-minute elevation window:
creating and retiring accounts, editing roles, clearing a second factor.
Reading the list is not gated, and content work is untouched.
elevated? is tied to is_admin?, so losing the role closes the window at
once. The window opens when the second factor verifies at login, so an
admin heading straight for user management is already elevated, and closes
on logout with the other session state. Five wrong codes end the session,
mirroring the login challenge.
users#update carries no elevation filter, since self-service reaches it;
the role field is gated in user_params instead and fails closed.
Diffstat (limited to 'test')
| -rw-r--r-- | test/controllers/users_controller_test.rb | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb index fe099928..b6f0970d 100644 --- a/test/controllers/users_controller_test.rb +++ b/test/controllers/users_controller_test.rb | |||
| @@ -19,6 +19,7 @@ class UsersControllerTest < ActionController::TestCase | |||
| 19 | 19 | ||
| 20 | test "get new when logged in as admin" do | 20 | test "get new when logged in as admin" do |
| 21 | login_as :aaron | 21 | login_as :aaron |
| 22 | elevate_session! | ||
| 22 | get :new | 23 | get :new |
| 23 | assert_response :success | 24 | assert_response :success |
| 24 | end | 25 | end |
| @@ -36,6 +37,7 @@ class UsersControllerTest < ActionController::TestCase | |||
| 36 | 37 | ||
| 37 | test "creating new users being logged in as admin" do | 38 | test "creating new users being logged in as admin" do |
| 38 | login_as :aaron | 39 | login_as :aaron |
| 40 | elevate_session! | ||
| 39 | assert_difference "User.count", +1 do | 41 | assert_difference "User.count", +1 do |
| 40 | post :create, params: { | 42 | post :create, params: { |
| 41 | :user => { | 43 | :user => { |
| @@ -53,6 +55,7 @@ class UsersControllerTest < ActionController::TestCase | |||
| 53 | 55 | ||
| 54 | test "creating new admin users being logged in as admin" do | 56 | test "creating new admin users being logged in as admin" do |
| 55 | login_as :aaron | 57 | login_as :aaron |
| 58 | elevate_session! | ||
| 56 | assert_difference "User.count", +1 do | 59 | assert_difference "User.count", +1 do |
| 57 | post :create, params: { | 60 | post :create, params: { |
| 58 | :user => { | 61 | :user => { |
| @@ -154,6 +157,7 @@ class UsersControllerTest < ActionController::TestCase | |||
| 154 | 157 | ||
| 155 | test "an admin deactivates another user, who can no longer sign in" do | 158 | test "an admin deactivates another user, who can no longer sign in" do |
| 156 | login_as :aaron | 159 | login_as :aaron |
| 160 | elevate_session! | ||
| 157 | user = users(:quentin) | 161 | user = users(:quentin) |
| 158 | 162 | ||
| 159 | put :deactivate, params: { :id => user.id } | 163 | put :deactivate, params: { :id => user.id } |
| @@ -165,6 +169,7 @@ class UsersControllerTest < ActionController::TestCase | |||
| 165 | 169 | ||
| 166 | test "reactivation restores the other roles untouched" do | 170 | test "reactivation restores the other roles untouched" do |
| 167 | login_as :aaron | 171 | login_as :aaron |
| 172 | elevate_session! | ||
| 168 | user = users(:quentin) | 173 | user = users(:quentin) |
| 169 | user.update_column(:roles, ["alumni", "redaktion"]) | 174 | user.update_column(:roles, ["alumni", "redaktion"]) |
| 170 | 175 | ||
| @@ -189,6 +194,7 @@ class UsersControllerTest < ActionController::TestCase | |||
| 189 | 194 | ||
| 190 | test "admin user can promote regular users to admins" do | 195 | test "admin user can promote regular users to admins" do |
| 191 | login_as :aaron | 196 | login_as :aaron |
| 197 | elevate_session! | ||
| 192 | user = users(:quentin) | 198 | user = users(:quentin) |
| 193 | put :update, params: { :id => user.id, :user => {:roles => ["admin", "redaktion"]} } | 199 | put :update, params: { :id => user.id, :user => {:roles => ["admin", "redaktion"]} } |
| 194 | 200 | ||
| @@ -212,6 +218,7 @@ class UsersControllerTest < ActionController::TestCase | |||
| 212 | assert user.reload.otp_enrolled?, "non-admin must be refused" | 218 | assert user.reload.otp_enrolled?, "non-admin must be refused" |
| 213 | 219 | ||
| 214 | login_as :aaron | 220 | login_as :aaron |
| 221 | elevate_session! | ||
| 215 | put :reset_otp, params: { :id => user.id } | 222 | put :reset_otp, params: { :id => user.id } |
| 216 | assert_not user.reload.otp_enrolled? | 223 | assert_not user.reload.otp_enrolled? |
| 217 | assert_equal "otp_reset", NodeAction.last.action | 224 | assert_equal "otp_reset", NodeAction.last.action |
| @@ -239,4 +246,19 @@ class UsersControllerTest < ActionController::TestCase | |||
| 239 | get :show, params: { :id => users(:aaron).id } | 246 | get :show, params: { :id => users(:aaron).id } |
| 240 | assert_redirected_to admin_path | 247 | assert_redirected_to admin_path |
| 241 | end | 248 | end |
| 249 | |||
| 250 | test "an admin without an open window is sent to elevation" do | ||
| 251 | login_as :aaron | ||
| 252 | get :new | ||
| 253 | assert_redirected_to new_elevation_path | ||
| 254 | end | ||
| 255 | |||
| 256 | test "an unelevated admin cannot change roles" do | ||
| 257 | login_as :aaron | ||
| 258 | user = users(:quentin) | ||
| 259 | |||
| 260 | put :update, params: { :id => user.id, :user => { :roles => ["admin"] } } | ||
| 261 | |||
| 262 | assert_not user.reload.is_admin? | ||
| 263 | end | ||
| 242 | end | 264 | end |
