Skip to content
Snippets Groups Projects
Commit 571226f1 authored by Kamil Trzcinski's avatar Kamil Trzcinski
Browse files

Make result to return project and capabilities granted

parent 505dc808
No related branches found
No related tags found
No related merge requests found
Loading
@@ -11,7 +11,7 @@ class JwtController < ApplicationController
Loading
@@ -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
Loading
@@ -20,12 +20,16 @@ class JwtController < ApplicationController
Loading
@@ -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
Loading
@@ -34,18 +38,4 @@ class JwtController < ApplicationController
Loading
@@ -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
Loading
@@ -4,7 +4,7 @@ class Projects::GitHttpClientController < Projects::ApplicationController
Loading
@@ -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
Loading
@@ -34,7 +34,7 @@ class Projects::GitHttpClientController < Projects::ApplicationController
Loading
@@ -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
Loading
@@ -120,12 +120,8 @@ class Projects::GitHttpClientController < Projects::ApplicationController
Loading
@@ -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!
Loading
Loading
Loading
@@ -86,7 +86,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController
Loading
@@ -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
Loading
Loading
Loading
@@ -29,11 +29,11 @@ module LfsHelper
Loading
@@ -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?
Loading
@@ -43,7 +43,7 @@ module LfsHelper
Loading
@@ -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
Loading
Loading
Loading
@@ -4,8 +4,8 @@ module Auth
Loading
@@ -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
   
Loading
@@ -91,33 +91,28 @@ module Auth
Loading
@@ -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
def full?
@access_type == :full
end end
   
def restricted? def has_ability?(ability, requested_project)
@access_type == :restricted @capabilities.include?(ability) && can?(current_user, ability, requested_project)
end end
end end
end end
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:)
Loading
@@ -9,7 +9,7 @@ module Gitlab
Loading
@@ -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
Loading
@@ -81,7 +81,7 @@ module Gitlab
Loading
@@ -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
Loading
@@ -93,7 +93,7 @@ module Gitlab
Loading
@@ -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)
Loading
@@ -101,7 +101,7 @@ module Gitlab
Loading
@@ -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
Loading
@@ -110,7 +110,7 @@ module Gitlab
Loading
@@ -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
   
Loading
@@ -123,12 +123,31 @@ module Gitlab
Loading
@@ -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
Loading
@@ -5,13 +5,13 @@ module Gitlab
Loading
@@ -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
   
Loading
@@ -69,15 +69,15 @@ module Gitlab
Loading
@@ -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
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment