diff --git a/app/controllers/api/v2/registration_tokens_controller.rb b/app/controllers/api/v2/registration_tokens_controller.rb new file mode 100644 index 00000000000..ad9cdf88689 --- /dev/null +++ b/app/controllers/api/v2/registration_tokens_controller.rb @@ -0,0 +1,58 @@ +module Api + module V2 + class RegistrationTokensController < V2::BaseController + include Foreman::Controller::UsersMixin + + include Foreman::Controller::Parameters::User + before_action :authenticate, :only => [:invalidate_tokens] + + def resource_class + User + end + + def find_resource(permission = :view_users) + editing_self? ? User.find(User.current.id) : User.authorized(permission).except_hidden.find(params[:id]) + end + + def action_permission + case params[:action] + when 'invalidate_tokens', 'invalidate_jwt' + 'edit' + else + super + end + end + + api :DELETE, '/users/:id/registration_tokens', N_("Invalidate all registration Tokens for a specific user.") + description <<-DOC + The user you specify will no longer be able to register hosts by using their JWTs. + DOC + param :id, String, :desc => N_("ID of the user"), :required => true + + def invalidate_jwt + @user = find_resource(:edit_users) + unless @user + raise ::Foreman::Exception.new(N_("No record found for %s"), params[:id]) + end + @user.jwt_secret&.destroy + process_success _('Successfully invalidated JWTs for %s.' % @user.login) + end + + api :DELETE, "/registration_tokens", N_("Invalidate all JSON Web Tokens (JWTs) for multiple users.") + param :search, String, :required => true + description <<-DOC + The users you specify will no longer be able to register hosts by using their JWTs. + DOC + + def invalidate_tokens + raise ::Foreman::Exception.new(N_("Please provide search parameters")) if params[:search].blank? + @users = resource_scope_for_index(:permission => :edit_users).except_hidden.uniq + if @users.blank? + raise ::Foreman::Exception.new(N_("No record found %s"), params[:search]) + end + JwtSecret.where(user_id: @users).destroy_all + process_success _('Successfully invalidated JWTs for %s.' % @users.pluck(:login).to_sentence) + end + end + end +end diff --git a/app/models/user.rb b/app/models/user.rb index a8ca2a1aed2..fc46ba00efd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -476,6 +476,9 @@ def editing_self?(options = {}) options[:user_id].to_i == id || options[:controller].to_s == 'api/v2/personal_access_tokens' && options[:action] =~ /show|destroy|index|create/ && + options[:user_id].to_i == id || + options[:controller].to_s == 'api/v2/registration_tokens' && + options[:action] =~ /invalidate_jwt|invalidate_tokens/ && options[:user_id].to_i == id end diff --git a/config/initializers/f_foreman_permissions.rb b/config/initializers/f_foreman_permissions.rb index 15e469c150c..7467f0f5e30 100644 --- a/config/initializers/f_foreman_permissions.rb +++ b/config/initializers/f_foreman_permissions.rb @@ -563,7 +563,8 @@ :"api/v2/users" => [:create] map.permission :edit_users, :users => [:edit, :update, :invalidate_jwt], - :"api/v2/users" => [:update] + :"api/v2/users" => [:update], + :"api/v2/registration_tokens" => [:invalidate_tokens, :invalidate_jwt] map.permission :destroy_users, :users => [:destroy], :"api/v2/users" => [:destroy] diff --git a/config/routes/api/v2.rb b/config/routes/api/v2.rb index 3eca161f873..56ad5212282 100644 --- a/config/routes/api/v2.rb +++ b/config/routes/api/v2.rb @@ -218,6 +218,13 @@ 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 + delete 'registration_tokens', :to => 'registration_tokens#invalidate_jwt', :on => :member + end + end + + resources :registration_tokens, :only => [:invalidate_tokens] do + collection do + delete '/', :action => :invalidate_tokens end end diff --git a/test/controllers/api/v2/registration_tokens_controller_test.rb b/test/controllers/api/v2/registration_tokens_controller_test.rb new file mode 100644 index 00000000000..fe6f99978a1 --- /dev/null +++ b/test/controllers/api/v2/registration_tokens_controller_test.rb @@ -0,0 +1,38 @@ +require 'test_helper' + +class Api::V2::RegistrationTokensControllerTest < ActionController::TestCase + test 'user shall invalidate tokens for self' do + user = users(:one) + FactoryBot.create(:jwt_secret, token: 'test_jwt_secret', user: user) + delete :invalidate_jwt, params: { :id => user.id.to_s}, session: set_session_user(user) + user.reload + assert_nil user.jwt_secret + end + + test 'user with edit permission should be able to invalidate jwt for another user' do + setup_user 'edit', 'users' + user = users(:one) + FactoryBot.create(:jwt_secret, token: 'test_jwt_secret', user: user) + delete :invalidate_tokens, params: { :search => "id ^ (#{user.id})"} + user.reload + assert_nil user.jwt_secret + end + + test 'user without edit permission should not be able to invalidate jwt for another user' do + User.current = users(:one) + user = users(:two) + FactoryBot.create(:jwt_secret, token: 'test_jwt_secret', user: user) + delete :invalidate_tokens, params: { :search => "id ^ (#{user.id})"}, session: set_session_user(User.current) + user.reload + assert_response :error + end + + test 'invalidating jwt should fail without search params' do + setup_user 'edit', 'users' + user = users(:two) + FactoryBot.create(:jwt_secret, token: 'test_jwt_secret', user: user) + delete :invalidate_tokens, session: set_session_user(User.current) + user.reload + assert_response :error + end +end