Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #36972 - Make hammer accept unlimited as JWT life time #9951

Merged
merged 1 commit into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions app/controllers/api/v2/registration_commands_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ class RegistrationCommandsController < V2::BaseController
include Foreman::Controller::RegistrationCommands

before_action :find_smart_proxy, if: -> { registration_params['smart_proxy_id'] }

api :POST, "/registration_commands", N_("Generate global registration command")
param :registration_command, Hash, required: false, action_aware: true do
param :organization_id, :number, desc: N_("ID of the Organization to register the host in")
Expand All @@ -15,7 +14,7 @@ class RegistrationCommandsController < V2::BaseController
param :smart_proxy_id, :number, desc: N_("ID of the Smart Proxy. This Proxy must have enabled both the 'Templates' and 'Registration' features")
param :setup_insights, :bool, desc: N_("Set 'host_registration_insights' parameter for the host. If it is set to true, insights client will be installed and registered on Red Hat family operating systems")
param :setup_remote_execution, :bool, desc: N_("Set 'host_registration_remote_execution' parameter for the host. If it is set to true, SSH keys will be installed on the host")
param :jwt_expiration, :number, desc: N_("Expiration of the authorization token (in hours)")
param :jwt_expiration, :number, desc: N_("Expiration of the authorization token (in hours), 0 means 'unlimited'.")
param :insecure, :bool, desc: N_("Enable insecure argument for the initial curl")
param :packages, String, desc: N_("Packages to install on the host when registered. Can be set by `host_packages` parameter, example: `pkg1 pkg2`")
param :update_packages, :bool, desc: N_("Update all packages on the host")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ module Foreman::Controller::RegistrationCommands

private

MIN_VALUE = 0
MAX_VALUE = 999999
DEFAULT_VALUE = 4

def command
args_query = "?#{registration_args.to_query}"
"curl -sS #{insecure} '#{registration_url(@smart_proxy)}#{args_query if args_query != '?'}' #{command_headers} | bash"
Expand All @@ -27,17 +31,40 @@ def registration_url(proxy = nil)
"#{url}/register"
end

def invalid_expiration_error
raise ::Foreman::Exception.new(N_("Invalid value '%s' for jwt_expiration. The value must be between %s and %s. 0 means 'unlimited'."), registration_params['jwt_expiration'], MIN_VALUE, MAX_VALUE)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This broke translations:

MALFORMED: "Invalid value '%s' for jwt_expiration. The value must be between %s and %s. 0 "

I think this is because you can only use %s once. More than that and it becomes ambiguous.

#10176

end

def jwt_expiration_param
param = registration_params['jwt_expiration'] || DEFAULT_VALUE
@jwt_expiration_param ||= begin
if param == 'unlimited'
0
elsif Float(param, exception: false)
param.to_i
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation will not fail validation of strings other than unlimited.

Since you have to accept decimal values, you can still have it validated:

Suggested change
param.to_i
Float(param).to_i

This will accept 11.5, but will fail for unknown words.

else
invalid_expiration_error
end
end
end

def expiration_unlimited?
jwt_expiration_param == 0
end

def expiration_valid?
jwt_expiration_param.between?(MIN_VALUE, MAX_VALUE)
end

def command_headers
jwt_args = {
scope: [{ controller: :registration, actions: [:global, :host] }],
}

if registration_params['jwt_expiration'].present?
jwt_args[:expiration] = registration_params['jwt_expiration'].to_i.hours.to_i if registration_params['jwt_expiration'] != 'unlimited'
if expiration_valid?
jwt_args[:expiration] = jwt_expiration_param.hours.to_i unless expiration_unlimited?
else
jwt_args[:expiration] = 4.hours.to_i
invalid_expiration_error
end

"-H 'Authorization: Bearer #{User.current.jwt_token!(**jwt_args)}'"
end

Expand Down
25 changes: 25 additions & 0 deletions test/controllers/registration_commands_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,31 @@ class RegistrationCommandsControllerTest < ActionController::TestCase

refute JwtToken.new(parsed_token).decode['exp']
end

test '0' do
post :create, params: { jwt_expiration: 0 }, session: set_session_user
command = JSON.parse(@response.body)['command']
parsed_token = command.scan(/(?<=Bearer )(.*)(?=.*)(?=\')/).flatten[0]
refute JwtToken.new(parsed_token).decode['exp']
end

test 'value greater than 999999' do
assert_raise Foreman::Exception do
post :create, params: { jwt_expiration: 1000000 }, session: set_session_user
end
end

test 'value less than 0' do
assert_raise Foreman::Exception do
post :create, params: { jwt_expiration: -1 }, session: set_session_user
end
end

test 'strings except unlimited' do
assert_raise Foreman::Exception do
post :create, params: { jwt_expiration: 'unlimiteded' }, session: set_session_user
end
end
end
end

Expand Down