diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index d95cdd90b8c..78020fbb6c5 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -93,6 +93,14 @@ def impersonate end end + def invalidate_jwt + @user = find_resource(:edit_users) + @user.jwt_secret&.destroy + process_success( + :success_msg => _('Successfully invalidated JWTs for %s.') % @user.login + ) + end + def stop_impersonation if session[:impersonated_by].present? user = User.unscoped.find_by_id(session[:impersonated_by]) diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index a782a77ce1c..4475405817c 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -34,6 +34,13 @@ def user_action_buttons(user, additional_actions = []) :data => { :no_turbolink => true }) end + if user != User.current + additional_actions << display_link_if_authorized(_("Invalidate JWTs"), + hash_for_invalidate_jwt_user_path(:id => user.id).merge(:auth_object => user, :permission => "edit_users"), + :method => :patch, :id => user.id, + :data => { :confirm => _("Invalidate all JSON Web Tokens for %s?") % user.name }) + end + delete_btn = display_delete_if_authorized( hash_for_user_path(:id => user).merge(:auth_object => user, :authorizer => authorizer), :data => { :confirm => _("Delete %s?") % user.name }) diff --git a/config/initializers/f_foreman_permissions.rb b/config/initializers/f_foreman_permissions.rb index 4f9146c7b23..15e469c150c 100644 --- a/config/initializers/f_foreman_permissions.rb +++ b/config/initializers/f_foreman_permissions.rb @@ -562,7 +562,7 @@ :users => [:new, :create], :"api/v2/users" => [:create] map.permission :edit_users, - :users => [:edit, :update], + :users => [:edit, :update, :invalidate_jwt], :"api/v2/users" => [:update] map.permission :destroy_users, :users => [:destroy], diff --git a/config/routes.rb b/config/routes.rb index dc9ebb97c6c..e2723eee05b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -256,6 +256,7 @@ end member do post 'impersonate' + patch 'invalidate_jwt' end resources :ssh_keys, only: [:new, :create, :destroy] end diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb index 49d1929eb1b..6b1a4bdae92 100644 --- a/test/controllers/users_controller_test.rb +++ b/test/controllers/users_controller_test.rb @@ -158,6 +158,32 @@ class UsersControllerTest < ActionController::TestCase assert !User.exists?(user.id) end + test "Admin should be able to invalidate jwt for any user" do + User.current = users(:admin) + user = users(:two) + FactoryBot.build(:jwt_secret, token: 'test_jwt_secret', user: user) + patch :invalidate_jwt, params: { :id => user.id } + user.reload + assert_nil user.jwt_secret + end + + test 'user with edit users permission should be able to invalidate jwt for another user' do + User.current = setup_user "edit", "users" + user = users(:two) + FactoryBot.build(:jwt_secret, token: 'test_jwt_secret', user: user) + patch :invalidate_jwt, params: { :id => user.id } + user.reload + assert_nil user.jwt_secret + end + + test 'user without edit users permission should not be able to invalidate jwt for another user' do + User.current = users(:one) + user = users(:two) + FactoryBot.build(:jwt_secret, token: 'test_jwt_secret', user: user) + patch :invalidate_jwt, params: { :id => user.id } + assert_response :forbidden + end + test "should modify session when locale is updated" do as_admin do put :update, params: { :id => users(:admin).id, :user => { :locale => "cs" } }, session: set_session_user