diff --git a/engines/instance_verification/lib/instance_verification/engine.rb b/engines/instance_verification/lib/instance_verification/engine.rb index 77d52c621..1310b1fbb 100644 --- a/engines/instance_verification/lib/instance_verification/engine.rb +++ b/engines/instance_verification/lib/instance_verification/engine.rb @@ -7,13 +7,13 @@ def self.update_cache(remote_ip, system_login, product_id, registry: false) unless registry InstanceVerification.write_cache_file( Rails.application.config.repo_cache_dir, - [remote_ip, system_login, product_id].join('-') + InstanceVerification.build_cache_key(remote_ip, system_login, base_product_id: product_id) ) end InstanceVerification.write_cache_file( Rails.application.config.registry_cache_dir, - [remote_ip, system_login].join('-') + InstanceVerification.build_cache_key(remote_ip, system_login) ) end @@ -22,6 +22,73 @@ def self.write_cache_file(cache_dir, cache_key) FileUtils.touch(File.join(cache_dir, cache_key)) end + def self.verify_instance(request, logger, system) + return false unless request.headers['X-Instance-Data'] + + instance_data = Base64.decode64(request.headers['X-Instance-Data'].to_s) + base_product = system.products.find_by(product_type: 'base') + return false unless base_product + + # check the cache for the system (20 min) + cache_path = File.join( + Rails.application.config.repo_cache_dir, + InstanceVerification.build_cache_key(request.remote_ip, system.login, base_product_id: base_product.id) + ) + if File.exist?(cache_path) + # only update registry cache key + InstanceVerification.update_cache(request.remote_ip, system.login, nil, registry: true) + return true + end + + verification_provider = InstanceVerification.provider.new( + logger, + request, + base_product.attributes.symbolize_keys.slice(:identifier, :version, :arch, :release_type), + instance_data + ) + + is_valid = verification_provider.instance_valid? + # update repository and registry cache + InstanceVerification.update_cache(request.remote_ip, system.login, base_product.id) + is_valid + rescue InstanceVerification::Exception => e + message = '' + if system.proxy_byos + result = SccProxy.scc_check_subscription_expiration(request.headers, system.login, system.system_token, logger) + if result[:is_active] + InstanceVerification.update_cache(request.remote_ip, system.login, base_product.id) + return true + end + + message = result[:message] + else + message = e.message + end + details = [ "System login: #{system.login}", "IP: #{request.remote_ip}" ] + details << "Instance ID: #{verification_provider.instance_id}" if verification_provider.instance_id + details << "Billing info: #{verification_provider.instance_billing_info}" if verification_provider.instance_billing_info + + ZypperAuth.auth_logger.info <<~LOGMSG + Access to the repos denied: #{message} + #{details.join(', ')} + LOGMSG + false + rescue StandardError => e + logger.error('Unexpected instance verification error has occurred:') + logger.error(e.message) + logger.error("System login: #{system.login}, IP: #{request.remote_ip}") + logger.error('Backtrace:') + logger.error(e.backtrace) + false + end + + def self.build_cache_key(remote_ip, login, base_product_id: nil) + cache_key = [remote_ip, login] + cache_key.append(base_product_id) unless base_product_id.nil? + + cache_key.join('-') + end + class Engine < ::Rails::Engine isolate_namespace InstanceVerification config.generators.api_only = true diff --git a/engines/registry/lib/registry/engine.rb b/engines/registry/lib/registry/engine.rb index aa5481f12..74dc75022 100644 --- a/engines/registry/lib/registry/engine.rb +++ b/engines/registry/lib/registry/engine.rb @@ -15,7 +15,7 @@ class Engine < ::Rails::Engine before_action :handle_auth_cache, only: %w[index] def handle_auth_cache - unless ZypperAuth.verify_instance(request, logger, @system) + unless InstanceVerification.verify_instance(request, logger, @system) render(xml: { error: 'Instance verification failed' }, status: :forbidden) end end diff --git a/engines/registry/spec/requests/api/connect/v3/systems/activations_controller_spec.rb b/engines/registry/spec/requests/api/connect/v3/systems/activations_controller_spec.rb index fced324ea..431288bd6 100644 --- a/engines/registry/spec/requests/api/connect/v3/systems/activations_controller_spec.rb +++ b/engines/registry/spec/requests/api/connect/v3/systems/activations_controller_spec.rb @@ -9,7 +9,7 @@ context 'without valid repository cache' do before do headers['X-Instance-Data'] = 'IMDS' - allow(ZypperAuth).to receive(:verify_instance).and_return(true) + allow(InstanceVerification).to receive(:verify_instance).and_return(true) end context 'without X-Instance-Data headers or hw_info' do @@ -31,7 +31,7 @@ # allow(File).to receive(:exist?).with("repo/cache/127.0.0.1-#{system.login}-#{system.products.first.id}").and_return(true) # allow(File).to receive(:exist?) allow(InstanceVerification).to receive(:update_cache) - allow(ZypperAuth).to receive(:verify_instance).and_call_original + allow(InstanceVerification).to receive(:verify_instance).and_call_original headers['X-Instance-Data'] = 'IMDS' end diff --git a/engines/zypper_auth/lib/zypper_auth/engine.rb b/engines/zypper_auth/lib/zypper_auth/engine.rb index 1c87a5de6..78fce5b0f 100644 --- a/engines/zypper_auth/lib/zypper_auth/engine.rb +++ b/engines/zypper_auth/lib/zypper_auth/engine.rb @@ -5,66 +5,6 @@ def auth_logger Thread.current[:logger].reopen Thread.current[:logger] end - - def verify_instance(request, logger, system) - return false unless request.headers['X-Instance-Data'] - - instance_data = Base64.decode64(request.headers['X-Instance-Data'].to_s) - - base_product = system.products.find_by(product_type: 'base') - return false unless base_product - - # check the cache for the system (20 min) - cache_key = [request.remote_ip, system.login, base_product.id].join('-') - cache_path = File.join(Rails.application.config.repo_cache_dir, cache_key) - if File.exist?(cache_path) - # only update registry cache key - InstanceVerification.update_cache(request.remote_ip, system.login, nil, registry: true) - return true - end - - verification_provider = InstanceVerification.provider.new( - logger, - request, - base_product.attributes.symbolize_keys.slice(:identifier, :version, :arch, :release_type), - instance_data - ) - - is_valid = verification_provider.instance_valid? - # update repository and registry cache - InstanceVerification.update_cache(request.remote_ip, system.login, base_product.id) - is_valid - rescue InstanceVerification::Exception => e - message = '' - if system.proxy_byos - result = SccProxy.scc_check_subscription_expiration(request.headers, system.login, system.system_token, logger) - if result[:is_active] - InstanceVerification.update_cache(request.remote_ip, system.login, base_product.id) - return true - end - - message = result[:message] - else - message = e.message - end - details = [ "System login: #{system.login}", "IP: #{request.remote_ip}" ] - details << "Instance ID: #{verification_provider.instance_id}" if verification_provider.instance_id - details << "Billing info: #{verification_provider.instance_billing_info}" if verification_provider.instance_billing_info - - ZypperAuth.auth_logger.info <<~LOGMSG - Access to the repos denied: #{message} - #{details.join(', ')} - LOGMSG - - false - rescue StandardError => e - logger.error('Unexpected instance verification error has occurred:') - logger.error(e.message) - logger.error("System login: #{system.login}, IP: #{request.remote_ip}") - logger.error('Backtrace:') - logger.error(e.backtrace) - false - end end class Engine < ::Rails::Engine @@ -126,7 +66,7 @@ def make_repo_url(base_url, repo_local_path, service_name = nil) # additional validation for zypper service XML controller before_action :verify_instance def verify_instance - unless ZypperAuth.verify_instance(request, logger, @system) + unless InstanceVerification.verify_instance(request, logger, @system) render(xml: { error: 'Instance verification failed' }, status: 403) end end @@ -138,7 +78,7 @@ def verify_instance # additional validation for strict_authentication auth subrequest def path_allowed?(path) return false unless original_path_allowed?(path) - ZypperAuth.verify_instance(request, logger, @system) + InstanceVerification.verify_instance(request, logger, @system) end end end