From eeb34c37f7471ed3b9485b2515b4f1363c5a6b98 Mon Sep 17 00:00:00 2001 From: Girija Soni Date: Thu, 24 Oct 2024 17:09:47 +0530 Subject: [PATCH] Fixes #37936 - As a user, I want to invalidate jwt for specific user --- app/controllers/api/v2/users_controller.rb | 23 +++++++++++++++++++--- app/controllers/users_controller.rb | 11 ++++++++++- app/helpers/users_helper.rb | 7 +++++++ app/models/concerns/jwt_auth.rb | 4 ++++ config/routes.rb | 1 + config/routes/api/v2.rb | 1 + 6 files changed, 43 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v2/users_controller.rb b/app/controllers/api/v2/users_controller.rb index 12fc971a351..8a5ffcd7ba2 100644 --- a/app/controllers/api/v2/users_controller.rb +++ b/app/controllers/api/v2/users_controller.rb @@ -12,8 +12,8 @@ class UsersController < V2::BaseController ['compute_attributes'] before_action :find_optional_nested_object - skip_before_action :authorize, :only => [:extlogin] - before_action :authenticate, :only => [:extlogin] + skip_before_action :authorize, :only => [:extlogin, :invalidate_jwt] + before_action :authenticate, :only => [:extlogin, :invalidate_jwt] api :GET, "/users/", N_("List all users") api :GET, "/auth_source_ldaps/:auth_source_ldap_id/users", N_("List all users for LDAP authentication source") @@ -96,7 +96,7 @@ def create api :PUT, "/users/:id/", N_("Update a user") description <<-DOC Adds role 'Default role' to the user if it is not already present. - Only another admin can change the admin account attribute. + Only another admin can change the admin account attribute. DOC param :id, String, :required => true param_group :user_update @@ -111,6 +111,23 @@ def update end end + api :PATCH, "/users/:id/invalidate_jwt", N_("Get vm attributes of host") + param :id, String, :required => true + description <<-DOC + Invalidate JWT for a specific user + DOC + + def invalidate_jwt + @user = User.find(params[:id]) + if !@user + render :json => { :error => _("User %s does not exist.") % @user.login} + elsif !User.current.can?(:edit_users, @user) + deny_access N_("User %s does not have permissions to invalidate JWT." % User.current.login) + elsif User.current.can?(:edit_users, @user) && @user.invalidate_jwt.blank? + process_success _('Successfully invalidated JWT for %s.' % @user.login) + end + end + api :DELETE, "/users/:id/", N_("Delete a user") param :id, String, :required => true diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index d95cdd90b8c..205763c2f44 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -8,7 +8,7 @@ class UsersController < ApplicationController rescue_from ActionController::InvalidAuthenticityToken, with: :login_token_reload skip_before_action :require_mail, :only => [:edit, :update, :logout, :stop_impersonation] skip_before_action :require_login, :check_user_enabled, :authorize, :session_expiry, :update_activity_time, :set_taxonomy, :set_gettext_locale_db, :only => [:login, :logout, :extlogout] - skip_before_action :authorize, :only => [:extlogin, :impersonate, :stop_impersonation] + skip_before_action :authorize, :only => [:extlogin, :impersonate, :stop_impersonation, :invalidate_jwt] before_action :require_admin, :only => :impersonate after_action :update_activity_time, :only => :login before_action :verify_active_session, :only => :login @@ -93,6 +93,15 @@ def impersonate end end + def invalidate_jwt + @user = find_resource(:edit_users) + if @user.invalidate_jwt.blank? + process_success( + :success_msg => _('Successfully invalidated JWT for %s.') % @user.login + ) + end + 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..99e10481d1b 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 JWT"), + hash_for_invalidate_jwt_user_path(:id => user.id).merge(:auth_object => user, :permission => "edit_users"), + :method => :patch, :id => user.id, + :data => { :confirm => _("Invalidate 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/app/models/concerns/jwt_auth.rb b/app/models/concerns/jwt_auth.rb index 182a33d86b4..c4ef0a3a768 100644 --- a/app/models/concerns/jwt_auth.rb +++ b/app/models/concerns/jwt_auth.rb @@ -8,6 +8,10 @@ def jwt_secret! jwt_secret || create_jwt_secret! end + def invalidate_jwt + User.find_by(id: id).jwt_secret&.destroy + end + # expiration: integer, eg: 4.hours.to_i # scope: example: [{ controller: :registration, actions: [:global, :host] }] def jwt_token!(expiration: nil, scope: []) 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/config/routes/api/v2.rb b/config/routes/api/v2.rb index 3eca161f873..ba47132b3b4 100644 --- a/config/routes/api/v2.rb +++ b/config/routes/api/v2.rb @@ -218,6 +218,7 @@ resources :mail_notifications, :only => [:create, :destroy, :update] get 'mail_notifications', :to => 'mail_notifications#user_mail_notifications', :on => :member get 'extlogin', :to => 'users#extlogin', :on => :collection + patch 'invalidate_jwt', :to => 'users#invalidate_jwt', :on => :member end end