Commit 86069a64 authored by Giorgenes Gelatti's avatar Giorgenes Gelatti

Adds job token auth to nuget

- adds job token support
- adds specs
- refactor unauthorized handling to set
  realm header
parent 18acb2d0
---
title: Allows NuGet to authenticate with Job Token
merge_request: 39147
author:
type: added
......@@ -4,6 +4,8 @@ module API
module Helpers
module Packages
module BasicAuthHelpers
extend ::Gitlab::Utils::Override
module Constants
AUTHENTICATE_REALM_HEADER = 'Www-Authenticate: Basic realm'
AUTHENTICATE_REALM_NAME = 'GitLab Packages Registry'
......@@ -44,12 +46,13 @@ module API
end
def unauthorized_or!
current_user ? yield : unauthorized_with_header!
current_user ? yield : unauthorized!
end
def unauthorized_with_header!
override :unauthorized!
def unauthorized!
header(AUTHENTICATE_REALM_HEADER, AUTHENTICATE_REALM_NAME)
unauthorized!
super
end
end
end
......
......@@ -54,7 +54,9 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project', regexp: POSITIVE_INTEGER_REGEX
end
route_setting :authentication, deploy_token_allowed: true
route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do
authorized_user_project
......@@ -65,7 +67,9 @@ module API
desc 'The NuGet Service Index' do
detail 'This feature was introduced in GitLab 12.6'
end
route_setting :authentication, deploy_token_allowed: true
route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth
get 'index', format: :json do
authorize_read_package!(authorized_user_project)
......@@ -79,10 +83,13 @@ module API
desc 'The NuGet Package Publish endpoint' do
detail 'This feature was introduced in GitLab 12.6'
end
params do
requires :package, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
end
route_setting :authentication, deploy_token_allowed: true
route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth
put do
authorize_upload!(authorized_user_project)
......@@ -107,7 +114,9 @@ module API
forbidden!
end
route_setting :authentication, deploy_token_allowed: true
route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth
put 'authorize' do
authorize_workhorse!(subject: authorized_user_project, has_length: false)
end
......@@ -124,7 +133,9 @@ module API
desc 'The NuGet Metadata Service - Package name level' do
detail 'This feature was introduced in GitLab 12.8'
end
route_setting :authentication, deploy_token_allowed: true
route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth
get 'index', format: :json do
present ::Packages::Nuget::PackagesMetadataPresenter.new(find_packages),
with: ::API::Entities::Nuget::PackagesMetadata
......@@ -136,7 +147,9 @@ module API
params do
requires :package_version, type: String, desc: 'The NuGet package version', regexp: API::NO_SLASH_URL_PART_REGEX
end
route_setting :authentication, deploy_token_allowed: true
route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth
get '*package_version', format: :json do
present ::Packages::Nuget::PackageMetadataPresenter.new(find_package),
with: ::API::Entities::Nuget::PackageMetadata
......@@ -155,7 +168,9 @@ module API
desc 'The NuGet Content Service - index request' do
detail 'This feature was introduced in GitLab 12.8'
end
route_setting :authentication, deploy_token_allowed: true
route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth
get 'index', format: :json do
present ::Packages::Nuget::PackagesVersionsPresenter.new(find_packages),
with: ::API::Entities::Nuget::PackagesVersions
......@@ -168,7 +183,9 @@ module API
requires :package_version, type: String, desc: 'The NuGet package version', regexp: API::NO_SLASH_URL_PART_REGEX
requires :package_filename, type: String, desc: 'The NuGet package filename', regexp: API::NO_SLASH_URL_PART_REGEX
end
route_setting :authentication, deploy_token_allowed: true
route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth
get '*package_version/*package_filename', format: :nupkg do
filename = "#{params[:package_filename]}.#{params[:format]}"
package_file = ::Packages::PackageFileFinder.new(find_package, filename, with_file_name_like: true)
......@@ -198,7 +215,9 @@ module API
desc 'The NuGet Search Service' do
detail 'This feature was introduced in GitLab 12.8'
end
route_setting :authentication, deploy_token_allowed: true
route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth
get format: :json do
search_options = {
include_prerelease_versions: params[:prerelease],
......
......@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe API::NugetPackages do
include WorkhorseHelpers
include PackagesManagerApiSpecHelpers
include HttpBasicAuthHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :public) }
......@@ -20,38 +21,76 @@ RSpec.describe API::NugetPackages do
context 'with valid project' do
using RSpec::Parameterized::TableSyntax
where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
'PUBLIC' | :developer | true | true | 'process nuget service index request' | :success
'PUBLIC' | :guest | true | true | 'process nuget service index request' | :success
'PUBLIC' | :developer | true | false | 'process nuget service index request' | :success
'PUBLIC' | :guest | true | false | 'process nuget service index request' | :success
'PUBLIC' | :developer | false | true | 'process nuget service index request' | :success
'PUBLIC' | :guest | false | true | 'process nuget service index request' | :success
'PUBLIC' | :developer | false | false | 'process nuget service index request' | :success
'PUBLIC' | :guest | false | false | 'process nuget service index request' | :success
'PUBLIC' | :anonymous | false | true | 'process nuget service index request' | :success
'PRIVATE' | :developer | true | true | 'process nuget service index request' | :success
'PRIVATE' | :guest | true | true | 'rejects nuget packages access' | :forbidden
'PRIVATE' | :developer | true | false | 'rejects nuget packages access' | :unauthorized
'PRIVATE' | :guest | true | false | 'rejects nuget packages access' | :unauthorized
'PRIVATE' | :developer | false | true | 'rejects nuget packages access' | :not_found
'PRIVATE' | :guest | false | true | 'rejects nuget packages access' | :not_found
'PRIVATE' | :developer | false | false | 'rejects nuget packages access' | :unauthorized
'PRIVATE' | :guest | false | false | 'rejects nuget packages access' | :unauthorized
'PRIVATE' | :anonymous | false | true | 'rejects nuget packages access' | :unauthorized
end
context 'personal token' do
where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
'PUBLIC' | :developer | true | true | 'process nuget service index request' | :success
'PUBLIC' | :guest | true | true | 'process nuget service index request' | :success
'PUBLIC' | :developer | true | false | 'process nuget service index request' | :success
'PUBLIC' | :guest | true | false | 'process nuget service index request' | :success
'PUBLIC' | :developer | false | true | 'process nuget service index request' | :success
'PUBLIC' | :guest | false | true | 'process nuget service index request' | :success
'PUBLIC' | :developer | false | false | 'process nuget service index request' | :success
'PUBLIC' | :guest | false | false | 'process nuget service index request' | :success
'PUBLIC' | :anonymous | false | true | 'process nuget service index request' | :success
'PRIVATE' | :developer | true | true | 'process nuget service index request' | :success
'PRIVATE' | :guest | true | true | 'rejects nuget packages access' | :forbidden
'PRIVATE' | :developer | true | false | 'rejects nuget packages access' | :unauthorized
'PRIVATE' | :guest | true | false | 'rejects nuget packages access' | :unauthorized
'PRIVATE' | :developer | false | true | 'rejects nuget packages access' | :not_found
'PRIVATE' | :guest | false | true | 'rejects nuget packages access' | :not_found
'PRIVATE' | :developer | false | false | 'rejects nuget packages access' | :unauthorized
'PRIVATE' | :guest | false | false | 'rejects nuget packages access' | :unauthorized
'PRIVATE' | :anonymous | false | true | 'rejects nuget packages access' | :unauthorized
end
with_them do
let(:token) { user_token ? personal_access_token.token : 'wrong' }
let(:headers) { user_role == :anonymous ? {} : build_basic_auth_header(user.username, token) }
with_them do
let(:token) { user_token ? personal_access_token.token : 'wrong' }
let(:headers) { user_role == :anonymous ? {} : build_basic_auth_header(user.username, token) }
subject { get api(url), headers: headers }
subject { get api(url), headers: headers }
before do
project.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility_level, false))
before do
project.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility_level, false))
end
it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
end
end
it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
context 'with job token' do
where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
'PUBLIC' | :developer | true | true | 'process nuget service index request' | :success
'PUBLIC' | :guest | true | true | 'process nuget service index request' | :success
'PUBLIC' | :developer | true | false | 'rejects nuget packages access' | :unauthorized
'PUBLIC' | :guest | true | false | 'rejects nuget packages access' | :unauthorized
'PUBLIC' | :developer | false | true | 'process nuget service index request' | :success
'PUBLIC' | :guest | false | true | 'process nuget service index request' | :success
'PUBLIC' | :developer | false | false | 'rejects nuget packages access' | :unauthorized
'PUBLIC' | :guest | false | false | 'rejects nuget packages access' | :unauthorized
'PUBLIC' | :anonymous | false | true | 'process nuget service index request' | :success
'PRIVATE' | :developer | true | true | 'process nuget service index request' | :success
'PRIVATE' | :guest | true | true | 'rejects nuget packages access' | :forbidden
'PRIVATE' | :developer | true | false | 'rejects nuget packages access' | :unauthorized
'PRIVATE' | :guest | true | false | 'rejects nuget packages access' | :unauthorized
'PRIVATE' | :developer | false | true | 'rejects nuget packages access' | :not_found
'PRIVATE' | :guest | false | true | 'rejects nuget packages access' | :not_found
'PRIVATE' | :developer | false | false | 'rejects nuget packages access' | :unauthorized
'PRIVATE' | :guest | false | false | 'rejects nuget packages access' | :unauthorized
'PRIVATE' | :anonymous | false | true | 'rejects nuget packages access' | :unauthorized
end
with_them do
let(:job) { user_token ? create(:ci_build, project: project, user: user) : double(token: 'wrong') }
let(:headers) { user_role == :anonymous ? {} : job_basic_auth_header(job) }
subject { get api(url), headers: headers }
before do
project.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility_level, false))
end
it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
end
end
end
......
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