Allow basic authentication on go get middleware
This commit is contained in:
parent
32fbc12cc5
commit
d1fea99deb
4 changed files with 59 additions and 17 deletions
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Allow basic authentication on go get middleware
|
||||||
|
merge_request: 23497
|
||||||
|
author: Morty Choi @mortyccp
|
||||||
|
type: changed
|
|
@ -169,18 +169,6 @@ module Gitlab
|
||||||
AccessTokenValidationService.new(token).include_any_scope?(scopes)
|
AccessTokenValidationService.new(token).include_any_scope?(scopes)
|
||||||
end
|
end
|
||||||
|
|
||||||
def abilities_for_scopes(scopes)
|
|
||||||
abilities_by_scope = {
|
|
||||||
api: full_authentication_abilities,
|
|
||||||
read_registry: [:read_container_image],
|
|
||||||
read_repository: [:download_code]
|
|
||||||
}
|
|
||||||
|
|
||||||
scopes.flat_map do |scope|
|
|
||||||
abilities_by_scope.fetch(scope.to_sym, [])
|
|
||||||
end.uniq
|
|
||||||
end
|
|
||||||
|
|
||||||
# rubocop: disable CodeReuse/ActiveRecord
|
# rubocop: disable CodeReuse/ActiveRecord
|
||||||
def deploy_token_check(login, password)
|
def deploy_token_check(login, password)
|
||||||
return unless password.present?
|
return unless password.present?
|
||||||
|
@ -246,6 +234,18 @@ module Gitlab
|
||||||
|
|
||||||
public
|
public
|
||||||
|
|
||||||
|
def abilities_for_scopes(scopes)
|
||||||
|
abilities_by_scope = {
|
||||||
|
api: full_authentication_abilities,
|
||||||
|
read_registry: [:read_container_image],
|
||||||
|
read_repository: [:download_code]
|
||||||
|
}
|
||||||
|
|
||||||
|
scopes.flat_map do |scope|
|
||||||
|
abilities_by_scope.fetch(scope.to_sym, [])
|
||||||
|
end.uniq
|
||||||
|
end
|
||||||
|
|
||||||
def build_authentication_abilities
|
def build_authentication_abilities
|
||||||
[
|
[
|
||||||
:read_project,
|
:read_project,
|
||||||
|
|
|
@ -6,6 +6,7 @@ module Gitlab
|
||||||
module Middleware
|
module Middleware
|
||||||
class Go
|
class Go
|
||||||
include ActionView::Helpers::TagHelper
|
include ActionView::Helpers::TagHelper
|
||||||
|
include ActionController::HttpAuthentication::Basic
|
||||||
|
|
||||||
PROJECT_PATH_REGEX = %r{\A(#{Gitlab::PathRegex.full_namespace_route_regex}/#{Gitlab::PathRegex.project_route_regex})/}.freeze
|
PROJECT_PATH_REGEX = %r{\A(#{Gitlab::PathRegex.full_namespace_route_regex}/#{Gitlab::PathRegex.project_route_regex})/}.freeze
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
request = Rack::Request.new(env)
|
request = ActionDispatch::Request.new(env)
|
||||||
|
|
||||||
render_go_doc(request) || @app.call(env)
|
render_go_doc(request) || @app.call(env)
|
||||||
end
|
end
|
||||||
|
@ -110,22 +111,38 @@ module Gitlab
|
||||||
|
|
||||||
def project_for_paths(paths, request)
|
def project_for_paths(paths, request)
|
||||||
project = Project.where_full_path_in(paths).first
|
project = Project.where_full_path_in(paths).first
|
||||||
return unless Ability.allowed?(current_user(request), :read_project, project)
|
return unless Ability.allowed?(current_user(request, project), :read_project, project)
|
||||||
|
|
||||||
project
|
project
|
||||||
end
|
end
|
||||||
|
|
||||||
def current_user(request)
|
def current_user(request, project)
|
||||||
|
current_user_from_access_token_and_warden?(request) || current_user_from_basic_authentication?(request, project)
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_user_from_access_token_and_warden?(request)
|
||||||
authenticator = Gitlab::Auth::RequestAuthenticator.new(request)
|
authenticator = Gitlab::Auth::RequestAuthenticator.new(request)
|
||||||
user = authenticator.find_user_from_access_token || authenticator.find_user_from_warden
|
user = authenticator.find_user_from_access_token || authenticator.find_user_from_warden
|
||||||
|
|
||||||
return unless user&.can?(:access_api)
|
return unless user&.can?(:access_api)
|
||||||
|
|
||||||
# Right now, the `api` scope is the only one that should be able to determine private project existence.
|
# Right now, the `api` scope is the only one that should be able to determine private project existence.
|
||||||
return unless authenticator.valid_access_token?(scopes: [:api])
|
return unless authenticator.valid_access_token?(scopes: [:api])
|
||||||
|
|
||||||
user
|
user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def current_user_from_basic_authentication?(request, project)
|
||||||
|
return unless has_basic_credentials?(request)
|
||||||
|
login, password = user_name_and_password(request)
|
||||||
|
auth_result = Gitlab::Auth.find_for_git_client(login, password, project: project, ip: request.ip)
|
||||||
|
return unless auth_result.success?
|
||||||
|
return unless auth_result.actor&.can?(:access_api)
|
||||||
|
if auth_result.type == :personal_access_token
|
||||||
|
apiScopeAbilities = Gitlab::Auth.abilities_for_scopes([:api])
|
||||||
|
return unless auth_result.authentication_abilities.sort == apiScopeAbilities.sort
|
||||||
|
end
|
||||||
|
|
||||||
|
auth_result.actor
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -135,6 +135,26 @@ describe Gitlab::Middleware::Go do
|
||||||
it_behaves_like 'unauthorized'
|
it_behaves_like 'unauthorized'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'using basic auth' do
|
||||||
|
let(:personal_access_token) { create(:personal_access_token, user: current_user) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(current_user.username, personal_access_token.token)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with api scope' do
|
||||||
|
it_behaves_like 'authenticated'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with read_user scope' do
|
||||||
|
before do
|
||||||
|
personal_access_token.update_attribute(:scopes, [:read_user])
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'unauthorized'
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue