From 7f4429d33b22c55d42fd62ff418fab3f8fc1b566 Mon Sep 17 00:00:00 2001 From: Ian Ballou Date: Thu, 18 Jul 2024 11:55:50 -0400 Subject: [PATCH] Fixes #37661 - block users properly from pushing content --- .../container_gateway_api.rb | 74 ++++++++++++++++--- .../container_gateway_main.rb | 3 + test/container_gateway_api_test.rb | 45 ++++++++++- 3 files changed, 108 insertions(+), 14 deletions(-) diff --git a/lib/smart_proxy_container_gateway/container_gateway_api.rb b/lib/smart_proxy_container_gateway/container_gateway_api.rb index dc9d454..f85ccff 100644 --- a/lib/smart_proxy_container_gateway/container_gateway_api.rb +++ b/lib/smart_proxy_container_gateway/container_gateway_api.rb @@ -50,18 +50,28 @@ class Api < ::Sinatra::Base end end + put '/v2/*/manifests/*/?' do + throw_unsupported_error + end + get '/v2/*/blobs/*/?' do - repository = params[:splat][0] - digest = params[:splat][1] - handle_repo_auth(repository, auth_header, request) - pulp_response = container_gateway_main.blobs(repository, digest, translated_headers_for_proxy) - if pulp_response.code.to_i >= 400 - status pulp_response.code.to_i - body pulp_response.body - else - redirection_location = pulp_response['location'] - redirect to(redirection_location) - end + head_or_get_blobs + end + + head '/v2/*/blobs/*/?' do + head_or_get_blobs + end + + post '/v2/*/blobs/uploads/?' do + throw_unsupported_error + end + + put '/v2/*/blobs/uploads/*/?' do + throw_unsupported_error + end + + patch '/v2/*/blobs/uploads/*/?' do + throw_unsupported_error end get '/v2/*/tags/list/?' do @@ -198,6 +208,46 @@ class Api < ::Sinatra::Base private + def head_or_get_blobs + repository = params[:splat][0] + digest = params[:splat][1] + handle_repo_auth(repository, auth_header, request) + pulp_response = container_gateway_main.blobs(repository, digest, translated_headers_for_proxy) + if pulp_response.code.to_i >= 400 + status pulp_response.code.to_i + body pulp_response.body + else + redirection_location = pulp_response['location'] + redirect to(redirection_location) + end + end + + def throw_unsupported_error + content_type :json + body ({ + "errors" => [ + { + "code" => "UNSUPPORTED", + "message" => "Pushing content is unsupported" + } + ] + }.to_json) + halt 404 + end + + def throw_repo_not_found_error + content_type :json + body ({ + "errors" => [ + { + "code" => "NAME_UNKNOWN", + "message" => "Repository name unknown" + } + ] + }.to_json) + halt 404 + end + def translated_headers_for_proxy current_headers = {} env = request.env.select do |key, _value| @@ -220,7 +270,7 @@ def handle_repo_auth(repository, auth_header, request) return if container_gateway_main.authorized_for_repo?(repository, user_token_is_valid, username) redirect_authorization_headers - halt 401, "unauthorized" + throw_repo_not_found_error end def redirect_authorization_headers diff --git a/lib/smart_proxy_container_gateway/container_gateway_main.rb b/lib/smart_proxy_container_gateway/container_gateway_main.rb index 885781c..0e10165 100644 --- a/lib/smart_proxy_container_gateway/container_gateway_main.rb +++ b/lib/smart_proxy_container_gateway/container_gateway_main.rb @@ -160,6 +160,9 @@ def update_user_repositories(username, repositories) end end + # Returns: + # true if the user is authorized to access the repo, or + # false if the user is not authorized to access the repo or if it does not exist def authorized_for_repo?(repo_name, user_token_is_valid, username = nil) repository = database.connection[:repositories][{ name: repo_name }] diff --git a/test/container_gateway_api_test.rb b/test/container_gateway_api_test.rb index cebe048..d7202f1 100644 --- a/test/container_gateway_api_test.rb +++ b/test/container_gateway_api_test.rb @@ -133,16 +133,57 @@ def test_redirects_blob_request assert_equal('', last_response.body) end + def test_redirects_blob_head_request + ::Proxy::ContainerGateway::Api.any_instance.expects(:handle_repo_auth).returns({}) + redirect_headers = { 'location' => "#{::Proxy::ContainerGateway::Plugin.settings.pulp_endpoint}" \ + "/pulp/container/library/test_repo/blobs/test_digest?validate_token=test_token" } + stub_request(:get, "#{::Proxy::ContainerGateway::Plugin.settings.pulp_endpoint}" \ + "/pulpcore_registry/v2/library/test_repo/blobs/test_digest"). + to_return(:status => 302, :body => '', :headers => redirect_headers) + + head '/v2/library/test_repo/blobs/test_digest' + assert last_response.redirect?, "Last response was not a redirect: #{last_response.body}" + assert_equal('', last_response.body) + end + def test_unauthorized_for_manifests @container_gateway_main.expects(:authorized_for_repo?).returns(false) get '/v2/test_repo/manifests/test_tag' - assert_equal 401, last_response.status + assert_equal 404, last_response.status end def test_unauthorized_for_blobs @container_gateway_main.expects(:authorized_for_repo?).returns(false) get '/v2/test_repo/blobs/test_digest' - assert_equal 401, last_response.status + assert_equal 404, last_response.status + end + + def test_put_manifests + put '/v2/library/test_repo/manifests/test_tag' + assert_equal 404, last_response.status + assert_equal({ "errors" => [{ "code" => "UNSUPPORTED", "message" => "Pushing content is unsupported" }] }, + JSON.parse(last_response.body)) + end + + def test_post_blob_uploads + post '/v2/library/test_repo/blobs/uploads/' + assert_equal 404, last_response.status + assert_equal({ "errors" => [{ "code" => "UNSUPPORTED", "message" => "Pushing content is unsupported" }] }, + JSON.parse(last_response.body)) + end + + def test_put_blob_uploads + put '/v2/library/test_repo/blobs/uploads/test_digest' + assert_equal 404, last_response.status + assert_equal({ "errors" => [{ "code" => "UNSUPPORTED", "message" => "Pushing content is unsupported" }] }, + JSON.parse(last_response.body)) + end + + def test_patch_blob_uploads + put '/v2/library/test_repo/blobs/uploads/test_digest' + assert_equal 404, last_response.status + assert_equal({ "errors" => [{ "code" => "UNSUPPORTED", "message" => "Pushing content is unsupported" }] }, + JSON.parse(last_response.body)) end def test_put_repository_list