Make result to return project and capabilities granted
This commit is contained in:
parent
505dc808b3
commit
571226f166
7 changed files with 60 additions and 60 deletions
|
@ -11,7 +11,7 @@ class JwtController < ApplicationController
|
||||||
service = SERVICES[params[:service]]
|
service = SERVICES[params[:service]]
|
||||||
return head :not_found unless service
|
return head :not_found unless service
|
||||||
|
|
||||||
result = service.new(@project, @user, auth_params).execute(access_type: @access_type)
|
result = service.new(@project, @user, auth_params).execute(capabilities: @capabilities)
|
||||||
|
|
||||||
render json: result, status: result[:http_status]
|
render json: result, status: result[:http_status]
|
||||||
end
|
end
|
||||||
|
@ -20,12 +20,16 @@ class JwtController < ApplicationController
|
||||||
|
|
||||||
def authenticate_project_or_user
|
def authenticate_project_or_user
|
||||||
authenticate_with_http_basic do |login, password|
|
authenticate_with_http_basic do |login, password|
|
||||||
# if it's possible we first try to authenticate project with login and password
|
@auth_result = Gitlab::Auth.find_for_git_client(login, password, ip: request.ip)
|
||||||
@project, @user, @access_type = authenticate_build(login, password)
|
|
||||||
return if @project
|
|
||||||
|
|
||||||
@user, @access_type = authenticate_user(login, password)
|
@user = auth_result.user
|
||||||
return if @user
|
@project = auth_result.project
|
||||||
|
@type = auth_result.type
|
||||||
|
@capabilities = auth_result.capabilities || []
|
||||||
|
|
||||||
|
if @user || @project
|
||||||
|
return # Allow access
|
||||||
|
end
|
||||||
|
|
||||||
render_403
|
render_403
|
||||||
end
|
end
|
||||||
|
@ -34,18 +38,4 @@ class JwtController < ApplicationController
|
||||||
def auth_params
|
def auth_params
|
||||||
params.permit(:service, :scope, :account, :client_id)
|
params.permit(:service, :scope, :account, :client_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def authenticate_build(login, password)
|
|
||||||
return unless login == 'gitlab-ci-token'
|
|
||||||
return unless password
|
|
||||||
|
|
||||||
build = Ci::Build.running.find_by(token: password)
|
|
||||||
return build.project, build.user, :restricted if build
|
|
||||||
end
|
|
||||||
|
|
||||||
def authenticate_user(login, password)
|
|
||||||
user = Gitlab::Auth.find_with_user_password(login, password)
|
|
||||||
Gitlab::Auth.rate_limit!(request.ip, success: user.present?, login: login)
|
|
||||||
return user, :full
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@ class Projects::GitHttpClientController < Projects::ApplicationController
|
||||||
include ActionController::HttpAuthentication::Basic
|
include ActionController::HttpAuthentication::Basic
|
||||||
include KerberosSpnegoHelper
|
include KerberosSpnegoHelper
|
||||||
|
|
||||||
attr_reader :user, :access_type
|
attr_reader :user, :capabilities
|
||||||
|
|
||||||
# Git clients will not know what authenticity token to send along
|
# Git clients will not know what authenticity token to send along
|
||||||
skip_before_action :verify_authenticity_token
|
skip_before_action :verify_authenticity_token
|
||||||
|
@ -34,7 +34,7 @@ class Projects::GitHttpClientController < Projects::ApplicationController
|
||||||
@user = auth_result.user
|
@user = auth_result.user
|
||||||
end
|
end
|
||||||
|
|
||||||
@access_type = auth_result.access_type
|
@capabilities = auth_result.capabilities || []
|
||||||
|
|
||||||
if ci? || user
|
if ci? || user
|
||||||
return # Allow access
|
return # Allow access
|
||||||
|
@ -120,12 +120,8 @@ class Projects::GitHttpClientController < Projects::ApplicationController
|
||||||
@ci.present?
|
@ci.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def full?
|
def has_capability?(capability)
|
||||||
@access_type == :full
|
@capabilities.include?(capability)
|
||||||
end
|
|
||||||
|
|
||||||
def restricted?
|
|
||||||
@access_type == :restricted
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify_workhorse_api!
|
def verify_workhorse_api!
|
||||||
|
|
|
@ -86,7 +86,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController
|
||||||
end
|
end
|
||||||
|
|
||||||
def access
|
def access
|
||||||
@access ||= Gitlab::GitAccess.new(user, project, 'http', access_type: access_type)
|
@access ||= Gitlab::GitAccess.new(user, project, 'http', capabilities: capabilities)
|
||||||
end
|
end
|
||||||
|
|
||||||
def access_check
|
def access_check
|
||||||
|
|
|
@ -29,11 +29,11 @@ module LfsHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def privileged_user_can_download_code?
|
def privileged_user_can_download_code?
|
||||||
full? && user && user.can?(:download_code, project)
|
has_capability?(:download_code) && user && user.can?(:download_code, project)
|
||||||
end
|
end
|
||||||
|
|
||||||
def restricted_user_can_download_code?
|
def restricted_user_can_download_code?
|
||||||
restricted? && user && user.can?(:restricted_download_code, project)
|
has_capability?(:restricted_download_code) && user && user.can?(:restricted_download_code, project)
|
||||||
end
|
end
|
||||||
|
|
||||||
def lfs_upload_access?
|
def lfs_upload_access?
|
||||||
|
@ -43,7 +43,7 @@ module LfsHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def privileged_user_can_push_code?
|
def privileged_user_can_push_code?
|
||||||
full? && user && user.can?(:push_code, project)
|
has_capability?(:push_code) && user && user.can?(:push_code, project)
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_lfs_forbidden
|
def render_lfs_forbidden
|
||||||
|
|
|
@ -4,8 +4,8 @@ module Auth
|
||||||
|
|
||||||
AUDIENCE = 'container_registry'
|
AUDIENCE = 'container_registry'
|
||||||
|
|
||||||
def execute(access_type: access_type)
|
def execute(capabilities: capabilities)
|
||||||
@access_type = access_type
|
@capabilities = capabilities
|
||||||
|
|
||||||
return error('not found', 404) unless registry.enabled
|
return error('not found', 404) unless registry.enabled
|
||||||
|
|
||||||
|
@ -91,33 +91,28 @@ module Auth
|
||||||
private
|
private
|
||||||
|
|
||||||
def restricted_user_can_pull?(requested_project)
|
def restricted_user_can_pull?(requested_project)
|
||||||
return false unless restricted?
|
|
||||||
|
|
||||||
# Restricted can:
|
# Restricted can:
|
||||||
# 1. pull from it's own project (for ex. a build)
|
# 1. pull from it's own project (for ex. a build)
|
||||||
# 2. read images from dependent projects if he is a team member
|
# 2. read images from dependent projects if he is a team member
|
||||||
requested_project == project || can?(current_user, :restricted_read_container_image, requested_project)
|
requested_project == project ||
|
||||||
|
has_ability?(:restricted_read_container_image, requested_project)
|
||||||
end
|
end
|
||||||
|
|
||||||
def privileged_user_can_pull?(requested_project)
|
def privileged_user_can_pull?(requested_project)
|
||||||
full? && can?(current_user, :read_container_image, requested_project)
|
has_ability?(:read_container_image, requested_project)
|
||||||
end
|
end
|
||||||
|
|
||||||
def restricted_user_can_push?(requested_project)
|
def restricted_user_can_push?(requested_project)
|
||||||
# Restricted can push only to project to from which he originates
|
# Restricted can push only to project to from which he originates
|
||||||
restricted? && requested_project == project
|
requested_project == project
|
||||||
end
|
end
|
||||||
|
|
||||||
def privileged_user_can_push?(requested_project)
|
def privileged_user_can_push?(requested_project)
|
||||||
full? && can?(current_user, :create_container_image, requested_project)
|
has_ability?(:create_container_image, requested_project)
|
||||||
end
|
end
|
||||||
|
|
||||||
def full?
|
def has_ability?(ability, requested_project)
|
||||||
@access_type == :full
|
@capabilities.include?(ability) && can?(current_user, ability, requested_project)
|
||||||
end
|
|
||||||
|
|
||||||
def restricted?
|
|
||||||
@access_type == :restricted
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module Gitlab
|
module Gitlab
|
||||||
module Auth
|
module Auth
|
||||||
Result = Struct.new(:user, :type, :access_type)
|
Result = Struct.new(:user, :type, :project, :capabilities)
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def find_for_git_client(login, password, project:, ip:)
|
def find_for_git_client(login, password, project:, ip:)
|
||||||
|
@ -9,7 +9,7 @@ module Gitlab
|
||||||
result = Result.new
|
result = Result.new
|
||||||
|
|
||||||
if valid_ci_request?(login, password, project)
|
if valid_ci_request?(login, password, project)
|
||||||
result.type = :ci
|
result = Result.new(nil, project, :ci, restricted_capabilities)
|
||||||
else
|
else
|
||||||
result = populate_result(login, password)
|
result = populate_result(login, password)
|
||||||
end
|
end
|
||||||
|
@ -81,7 +81,7 @@ module Gitlab
|
||||||
personal_access_token_check(login, password)
|
personal_access_token_check(login, password)
|
||||||
|
|
||||||
if result
|
if result
|
||||||
result.type = nil unless result.user && result.type != :ci
|
result.type = nil unless result.capabilities
|
||||||
|
|
||||||
if result.user && result.user.two_factor_enabled? && result.type == :gitlab_or_ldap
|
if result.user && result.user.two_factor_enabled? && result.type == :gitlab_or_ldap
|
||||||
result.type = :missing_personal_token
|
result.type = :missing_personal_token
|
||||||
|
@ -93,7 +93,7 @@ module Gitlab
|
||||||
|
|
||||||
def user_with_password_for_git(login, password)
|
def user_with_password_for_git(login, password)
|
||||||
user = find_with_user_password(login, password)
|
user = find_with_user_password(login, password)
|
||||||
Result.new(user, :gitlab_or_ldap, :full) if user
|
Result.new(user, :gitlab_or_ldap, nil, full_capabilities) if user
|
||||||
end
|
end
|
||||||
|
|
||||||
def oauth_access_token_check(login, password)
|
def oauth_access_token_check(login, password)
|
||||||
|
@ -101,7 +101,7 @@ module Gitlab
|
||||||
token = Doorkeeper::AccessToken.by_token(password)
|
token = Doorkeeper::AccessToken.by_token(password)
|
||||||
if token && token.accessible?
|
if token && token.accessible?
|
||||||
user = User.find_by(id: token.resource_owner_id)
|
user = User.find_by(id: token.resource_owner_id)
|
||||||
Result.new(user, :oauth, :full)
|
Result.new(user, nil, :oauth, full_capabilities)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -110,7 +110,7 @@ module Gitlab
|
||||||
if login && password
|
if login && password
|
||||||
user = User.find_by_personal_access_token(password)
|
user = User.find_by_personal_access_token(password)
|
||||||
validation = User.by_login(login)
|
validation = User.by_login(login)
|
||||||
Result.new(user, :personal_token, :full) if user == validation
|
Result.new(user, nil, :personal_token, full_capabilities) if user == validation
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -123,12 +123,31 @@ module Gitlab
|
||||||
|
|
||||||
if build.user
|
if build.user
|
||||||
# If user is assigned to build, use restricted credentials of user
|
# If user is assigned to build, use restricted credentials of user
|
||||||
Result.new(build.user, :build, :restricted)
|
Result.new(build.user, build.project, :build, restricted_capabilities)
|
||||||
else
|
else
|
||||||
# Otherwise use generic CI credentials (backward compatibility)
|
# Otherwise use generic CI credentials (backward compatibility)
|
||||||
Result.new(nil, :ci, :restricted)
|
Result.new(nil, build.project, :ci, restricted_capabilities)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def restricted_capabilities
|
||||||
|
[
|
||||||
|
:read_project,
|
||||||
|
:restricted_download_code,
|
||||||
|
:restricted_read_container_image
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
def full_capabilities
|
||||||
|
restricted_capabilities + [
|
||||||
|
:download_code,
|
||||||
|
:push_code,
|
||||||
|
:read_container_image,
|
||||||
|
:update_container_image
|
||||||
|
]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,13 +5,13 @@ module Gitlab
|
||||||
DOWNLOAD_COMMANDS = %w{ git-upload-pack git-upload-archive }
|
DOWNLOAD_COMMANDS = %w{ git-upload-pack git-upload-archive }
|
||||||
PUSH_COMMANDS = %w{ git-receive-pack }
|
PUSH_COMMANDS = %w{ git-receive-pack }
|
||||||
|
|
||||||
attr_reader :actor, :project, :protocol, :user_access, :access_type
|
attr_reader :actor, :project, :protocol, :user_access, :capabilities
|
||||||
|
|
||||||
def initialize(actor, project, protocol, access_type: access_type)
|
def initialize(actor, project, protocol, capabilities: capabilities)
|
||||||
@actor = actor
|
@actor = actor
|
||||||
@project = project
|
@project = project
|
||||||
@protocol = protocol
|
@protocol = protocol
|
||||||
@access_type = access_type
|
@capabilities = capabilities
|
||||||
@user_access = UserAccess.new(user, project: project)
|
@user_access = UserAccess.new(user, project: project)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -69,15 +69,15 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def privileged_user_can_download_code?
|
def privileged_user_can_download_code?
|
||||||
access_type == :full && user_access.can_do_action?(:download_code)
|
capabilities.include?(:download_code) && user_access.can_do_action?(:download_code)
|
||||||
end
|
end
|
||||||
|
|
||||||
def restricted_user_can_download_code?
|
def restricted_user_can_download_code?
|
||||||
access_type == :restricted && user_access.can_do_action?(:restricted_download_code)
|
capabilities.include?(:restricted_download_code) && user_access.can_do_action?(:restricted_download_code)
|
||||||
end
|
end
|
||||||
|
|
||||||
def user_push_access_check(changes)
|
def user_push_access_check(changes)
|
||||||
unless access_type == :full
|
unless capabilities.include?(:push_code)
|
||||||
return build_status_object(false, "You are not allowed to upload code for this project.")
|
return build_status_object(false, "You are not allowed to upload code for this project.")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue