Skip to content

Commit

Permalink
Merge branch 'master' into sccproxy-activations-error-handling
Browse files Browse the repository at this point in the history
  • Loading branch information
jesusbv authored Nov 6, 2024
2 parents 9a33df8 + 2fadb57 commit e50c470
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
include_context 'version header', 3

describe '#activations' do
let(:system) { FactoryBot.create(:system, :with_activated_product) }
let(:system) { FactoryBot.create(:system, :payg, :with_activated_product) }
let(:headers) { auth_header.merge(version_header) }

context 'without valid repository cache' do
Expand Down Expand Up @@ -57,5 +57,68 @@
expect(data[0]['service']['url']).to match(%r{^plugin:/susecloud})
end
end

context 'system is hybrid' do
let(:system) { FactoryBot.create(:system, :hybrid, :with_activated_product) }
let(:plugin_double) { instance_double('InstanceVerification::Providers::Example') }
let(:cache_name) { "repo/cache/127.0.0.1-#{system.login}-#{system.products.first.id}" }
let(:scc_systems_activations_url) { 'https://scc.suse.com/connect/systems/activations' }
let(:body_active) do
{
id: 1,
regcode: '631dc51f',
name: 'Subscription 1',
type: 'FULL',
status: 'ACTIVE',
starts_at: 'null',
expires_at: '2014-03-14T13:10:21.164Z',
system_limit: 6,
systems_count: 1,
service: {
product: {
id: system.activations.first.product.id
}
}
}
end

before do
allow(InstanceVerification::Providers::Example).to receive(:new).and_return(plugin_double)

allow(plugin_double).to(
receive(:instance_valid?).and_return(true)
)
allow(File).to receive(:join).and_call_original
allow(InstanceVerification).to receive(:update_cache)
allow(ZypperAuth).to receive(:verify_instance).and_call_original
stub_request(:get, scc_systems_activations_url).to_return(status: 200, body: [body_active].to_json, headers: {})
headers['X-Instance-Data'] = 'IMDS'
end

context 'no registry' do
it 'refreshes registry cache key only' do
FileUtils.mkdir_p('repo/cache')
expect(InstanceVerification).to receive(:update_cache).with('127.0.0.1', system.login, system.activations.first.product.id)
get '/connect/systems/activations', headers: headers
FileUtils.rm_rf('repo/cache')
data = JSON.parse(response.body)
expect(SccProxy).not_to receive(:product_path_access)
expect(data[0]['service']['url']).to match(%r{^plugin:/susecloud})
end
end

context 'registry' do
it 'refreshes registry cache key only' do
FileUtils.mkdir_p('repo/cache')
FileUtils.touch(cache_name)
expect(InstanceVerification).to receive(:update_cache).with('127.0.0.1', system.login, nil, registry: true)
get '/connect/systems/activations', headers: headers
FileUtils.rm_rf('repo/cache')
data = JSON.parse(response.body)
expect(SccProxy).not_to receive(:product_path_access)
expect(data[0]['service']['url']).to match(%r{^plugin:/susecloud})
end
end
end
end
end
7 changes: 7 additions & 0 deletions engines/scc_proxy/lib/scc_proxy/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,17 @@ def product_class_access(scc_systems_activations, product)
end
end

# rubocop:disable Metrics/PerceivedComplexity
def activations_fail_state(scc_systems_activations, headers, product = nil)
return SccProxy.product_class_access(scc_systems_activations, product) unless product.nil?

active_products_ids = scc_systems_activations.map { |act| act['service']['product']['id'] if act['status'].casecmp('active').zero? }.flatten
x_original_uri = headers.fetch('X-Original-URI', '')
# if there is no product info to compare the activations with
# probably means the query is to refresh credentials
# in any case, verification is true if ALL activations are ACTIVE
return { is_active: (scc_systems_activations.length == active_products_ids.length) } if x_original_uri.empty?

if SccProxy.product_path_access(x_original_uri, active_products_ids)
{ is_active: true }
else
Expand All @@ -270,6 +276,7 @@ def activations_fail_state(scc_systems_activations, headers, product = nil)
end
end
end
# rubocop:enable Metrics/PerceivedComplexity

def scc_check_subscription_expiration(headers, system, product = nil)
scc_systems_activations = SccProxy.get_scc_activations(headers, system)
Expand Down
12 changes: 7 additions & 5 deletions engines/zypper_auth/lib/zypper_auth/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ def auth_logger
Thread.current[:logger]
end

def verify_instance(request, logger, system)
def verify_instance(request, logger, system, params_product_id = nil)
return false unless request.headers['X-Instance-Data']

instance_data = Base64.decode64(request.headers['X-Instance-Data'].to_s)
Expand All @@ -31,7 +31,8 @@ def verify_instance(request, logger, system)
)

is_valid = verification_provider.instance_valid?
return false if is_valid && system.hybrid? && !handle_scc_subscription(request, system, verification_provider)
return false if is_valid && system.hybrid? && !handle_scc_subscription(request, system, verification_provider, logger, params_product_id)

# update repository and registry cache
InstanceVerification.update_cache(request.remote_ip, system.login, base_product.id)
is_valid
Expand All @@ -49,8 +50,9 @@ def verify_instance(request, logger, system)
false
end

def handle_scc_subscription(request, system, verification_provider)
result = SccProxy.scc_check_subscription_expiration(request.headers, system)
def handle_scc_subscription(request, system, verification_provider, logger, params_product_id = nil)
product_class = Product.find_by(id: params_product_id).product_class if params_product_id.present?
result = SccProxy.scc_check_subscription_expiration(request.headers, system.login, system.system_token, logger, system.proxy_byos_mode, product_class)
return true if result[:is_active]

ZypperAuth.zypper_auth_message(request, system, verification_provider, result[:message])
Expand Down Expand Up @@ -128,7 +130,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 ZypperAuth.verify_instance(request, logger, @system, params.fetch('id', nil))
render(xml: { error: 'Instance verification failed' }, status: 403)
end
end
Expand Down

0 comments on commit e50c470

Please sign in to comment.