Commit f7dc91a5 authored by Steve Mokris's avatar Steve Mokris Committed by Mark Chao

Allow anonymous access to public Conan packages

- Allow access to ping endpoint without a token
- Allow access to download endpoints without a token, if the project
  is public
- Instead of throwing UnauthorizedError when no token is provided,
  continue with anonymous privileges
- Update tests to reflect the above changes
- Add test for downloading without a token
parent 31b2c00c
......@@ -44,7 +44,7 @@ module Packages
name, version, username, _ = query.split(/[@\/]/)
full_path = Packages::Conan::Metadatum.full_path_from(package_username: username)
project = Project.find_by_full_path(full_path)
return unless current_user.can?(:read_package, project)
return unless Ability.allowed?(current_user, :read_package, project)
result = project.packages.with_name(name).with_version(version).order_created.last
[result&.conan_recipe].compact
......
---
title: Allow anonymous access to public Conan packages
merge_request: 54047
author: Steve Mokris @smokris
type: changed
......@@ -171,6 +171,10 @@ convention.
## Authenticate to the Package Registry
GitLab requires authentication to upload packages, and to install packages
from private and internal projects. (You can, however, install packages
from public projects without authentication.)
To authenticate to the Package Registry, you need one of the following:
- A [personal access token](../../../user/profile/personal_access_tokens.md)
......@@ -302,8 +306,9 @@ file.
Prerequisites:
- The Conan remote [must be configured](#add-the-package-registry-as-a-conan-remote).
- [Authentication](#authenticate-to-the-package-registry) with the
Package Registry must be configured.
- For private and internal projects, you must configure
[Authentication](#authenticate-to-the-package-registry)
with the Package Registry.
1. In the project where you want to install the package as a dependency, open
`conanfile.txt`. Or, in the root of your project, create a file called
......
......@@ -42,7 +42,7 @@ module API
# Personal access token will be extracted from Bearer or Basic authorization
# in the overridden find_personal_access_token or find_user_from_job_token helpers
authenticate!
authenticate_non_get!
end
desc 'Ping the Conan API' do
......@@ -71,6 +71,10 @@ module API
end
namespace 'users' do
before do
authenticate!
end
format :txt
content_type :txt, 'text/plain'
......
......@@ -221,7 +221,7 @@ module API
def find_user_from_job_token
return unless route_authentication_setting[:job_token_allowed]
job = find_job_from_token || raise(::Gitlab::Auth::UnauthorizedError)
job = find_job_from_token || return
@current_authenticated_job = job # rubocop:disable Gitlab/ModuleWithInstanceVariables
job.user
......
# frozen_string_literal: true
RSpec.shared_examples 'conan ping endpoint' do
it 'responds with 401 Unauthorized when no token provided' do
it 'responds with 200 OK when no token provided' do
get api(url)
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'responds with 200 OK when valid token is provided' do
jwt = build_jwt(personal_access_token)
get api(url), headers: build_token_auth_header(jwt.encoded)
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['X-Conan-Server-Capabilities']).to eq("")
end
it 'responds with 200 OK when valid job token is provided' do
jwt = build_jwt_from_job(job)
get api(url), headers: build_token_auth_header(jwt.encoded)
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['X-Conan-Server-Capabilities']).to eq("")
end
it 'responds with 200 OK when valid deploy token is provided' do
jwt = build_jwt_from_deploy_token(deploy_token)
get api(url), headers: build_token_auth_header(jwt.encoded)
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['X-Conan-Server-Capabilities']).to eq("")
end
it 'responds with 401 Unauthorized when invalid access token ID is provided' do
jwt = build_jwt(double(id: 12345), user_id: personal_access_token.user_id)
get api(url), headers: build_token_auth_header(jwt.encoded)
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'responds with 401 Unauthorized when invalid user is provided' do
jwt = build_jwt(personal_access_token, user_id: 12345)
get api(url), headers: build_token_auth_header(jwt.encoded)
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'responds with 401 Unauthorized when the provided JWT is signed with different secret' do
jwt = build_jwt(personal_access_token, secret: SecureRandom.base64(32))
get api(url), headers: build_token_auth_header(jwt.encoded)
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'responds with 401 Unauthorized when invalid JWT is provided' do
get api(url), headers: build_token_auth_header('invalid-jwt')
expect(response).to have_gitlab_http_status(:unauthorized)
end
context 'packages feature disabled' do
it 'responds with 404 Not Found' do
stub_packages_setting(enabled: false)
......@@ -72,7 +22,10 @@ RSpec.shared_examples 'conan search endpoint' do
before do
project.update_column(:visibility_level, Gitlab::VisibilityLevel::PUBLIC)
get api(url), headers: headers, params: params
# Do not pass the HTTP_AUTHORIZATION header,
# in order to test that this public project's packages
# are visible to anonymous search.
get api(url), params: params
end
subject { json_response['results'] }
......@@ -109,6 +62,33 @@ RSpec.shared_examples 'conan authenticate endpoint' do
end
end
it 'responds with 401 Unauthorized when an invalid access token ID is provided' do
jwt = build_jwt(double(id: 12345), user_id: personal_access_token.user_id)
get api(url), headers: build_token_auth_header(jwt.encoded)
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'responds with 401 Unauthorized when invalid user is provided' do
jwt = build_jwt(personal_access_token, user_id: 12345)
get api(url), headers: build_token_auth_header(jwt.encoded)
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'responds with 401 Unauthorized when the provided JWT is signed with different secret' do
jwt = build_jwt(personal_access_token, secret: SecureRandom.base64(32))
get api(url), headers: build_token_auth_header(jwt.encoded)
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'responds with 401 UnauthorizedOK when invalid JWT is provided' do
get api(url), headers: build_token_auth_header('invalid-jwt')
expect(response).to have_gitlab_http_status(:unauthorized)
end
context 'when valid JWT access token is provided' do
it 'responds with 200' do
subject
......@@ -507,19 +487,37 @@ RSpec.shared_examples 'delete package endpoint' do
end
end
RSpec.shared_examples 'allows download with no token' do
context 'with no private token' do
let(:headers) { {} }
it 'returns 200' do
subject
expect(response).to have_gitlab_http_status(:ok)
end
end
end
RSpec.shared_examples 'denies download with no token' do
context 'with no private token' do
let(:headers) { {} }
it 'returns 400' do
it 'returns 404' do
subject
expect(response).to have_gitlab_http_status(:unauthorized)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
RSpec.shared_examples 'a public project with packages' do
before do
project.update_column(:visibility_level, Gitlab::VisibilityLevel::PUBLIC)
end
it_behaves_like 'allows download with no token'
it 'returns the file' do
subject
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment