diff options
author | Kamil Trzcinski <ayufan@ayufan.eu> | 2016-08-08 12:01:25 +0200 |
---|---|---|
committer | Kamil Trzcinski <ayufan@ayufan.eu> | 2016-09-13 13:30:26 +0200 |
commit | 505dc808b3c0dc98413506446d368b91b56ff682 (patch) | |
tree | 1f6d5c7fe805bf5ff11a4f5696d73e11d71ca3a6 /app | |
parent | 45afdbef0de58f6de207b057e47151611d2ad7e6 (diff) | |
download | gitlab-ce-505dc808b3c0dc98413506446d368b91b56ff682.tar.gz |
Use a permissions of user to access all dependent projects from CI jobs (this also includes a container images, and in future LFS files)
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/jwt_controller.rb | 18 | ||||
-rw-r--r-- | app/controllers/projects/git_http_client_controller.rb | 12 | ||||
-rw-r--r-- | app/controllers/projects/git_http_controller.rb | 2 | ||||
-rw-r--r-- | app/helpers/lfs_helper.rb | 16 | ||||
-rw-r--r-- | app/models/ci/build.rb | 13 | ||||
-rw-r--r-- | app/models/project.rb | 6 | ||||
-rw-r--r-- | app/policies/project_policy.rb | 15 | ||||
-rw-r--r-- | app/services/auth/container_registry_authentication_service.rb | 40 |
8 files changed, 91 insertions, 31 deletions
diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb index 66ebdcc37a7..ca02df28b91 100644 --- a/app/controllers/jwt_controller.rb +++ b/app/controllers/jwt_controller.rb @@ -11,7 +11,7 @@ class JwtController < ApplicationController service = SERVICES[params[:service]] return head :not_found unless service - result = service.new(@project, @user, auth_params).execute + result = service.new(@project, @user, auth_params).execute(access_type: @access_type) render json: result, status: result[:http_status] end @@ -21,10 +21,10 @@ class JwtController < ApplicationController def authenticate_project_or_user authenticate_with_http_basic do |login, password| # if it's possible we first try to authenticate project with login and password - @project = authenticate_project(login, password) + @project, @user, @access_type = authenticate_build(login, password) return if @project - @user = authenticate_user(login, password) + @user, @access_type = authenticate_user(login, password) return if @user render_403 @@ -35,15 +35,17 @@ class JwtController < ApplicationController params.permit(:service, :scope, :account, :client_id) end - def authenticate_project(login, password) - if login == 'gitlab-ci-token' - Project.with_builds_enabled.find_by(runners_token: password) - 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) - user + return user, :full end end diff --git a/app/controllers/projects/git_http_client_controller.rb b/app/controllers/projects/git_http_client_controller.rb index f5ce63fdfed..0f72dc8437c 100644 --- a/app/controllers/projects/git_http_client_controller.rb +++ b/app/controllers/projects/git_http_client_controller.rb @@ -4,7 +4,7 @@ class Projects::GitHttpClientController < Projects::ApplicationController include ActionController::HttpAuthentication::Basic include KerberosSpnegoHelper - attr_reader :user + attr_reader :user, :access_type # Git clients will not know what authenticity token to send along skip_before_action :verify_authenticity_token @@ -34,6 +34,8 @@ class Projects::GitHttpClientController < Projects::ApplicationController @user = auth_result.user end + @access_type = auth_result.access_type + if ci? || user return # Allow access end @@ -118,6 +120,14 @@ class Projects::GitHttpClientController < Projects::ApplicationController @ci.present? end + def full? + @access_type == :full + end + + def restricted? + @access_type == :restricted + end + def verify_workhorse_api! Gitlab::Workhorse.verify_api_request!(request.headers) end diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb index 9805705c4e3..d59a47417f4 100644 --- a/app/controllers/projects/git_http_controller.rb +++ b/app/controllers/projects/git_http_controller.rb @@ -86,7 +86,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController end def access - @access ||= Gitlab::GitAccess.new(user, project, 'http') + @access ||= Gitlab::GitAccess.new(user, project, 'http', access_type: access_type) end def access_check diff --git a/app/helpers/lfs_helper.rb b/app/helpers/lfs_helper.rb index 5d82abfca79..625dfddcf8d 100644 --- a/app/helpers/lfs_helper.rb +++ b/app/helpers/lfs_helper.rb @@ -25,13 +25,25 @@ module LfsHelper def lfs_download_access? return false unless project.lfs_enabled? - project.public? || ci? || (user && user.can?(:download_code, project)) + project.public? || ci? || privileged_user_can_download_code? || restricted_user_can_download_code? + end + + def privileged_user_can_download_code? + full? && user && user.can?(:download_code, project) + end + + def restricted_user_can_download_code? + restricted? && user && user.can?(:restricted_download_code, project) end def lfs_upload_access? return false unless project.lfs_enabled? - user && user.can?(:push_code, project) + privileged_user_can_push_code? + end + + def privileged_user_can_push_code? + full? && user && user.can?(:push_code, project) end def render_lfs_forbidden diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 61052437318..1c2e0f1edea 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -1,5 +1,7 @@ module Ci class Build < CommitStatus + include TokenAuthenticatable + belongs_to :runner, class_name: 'Ci::Runner' belongs_to :trigger_request, class_name: 'Ci::TriggerRequest' belongs_to :erased_by, class_name: 'User' @@ -23,7 +25,10 @@ module Ci acts_as_taggable + add_authentication_token_field :token + before_save :update_artifacts_size, if: :artifacts_file_changed? + before_save :ensure_token before_destroy { project } after_create :execute_hooks @@ -172,7 +177,7 @@ module Ci end def repo_url - auth = "gitlab-ci-token:#{token}@" + auth = "gitlab-ci-token:#{ensure_token}@" project.http_url_to_repo.sub(/^https?:\/\//) do |prefix| prefix + auth end @@ -340,12 +345,8 @@ module Ci ) end - def token - project.runners_token - end - def valid_token?(token) - project.valid_runners_token?(token) + self.token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.token) end def has_tags? diff --git a/app/models/project.rb b/app/models/project.rb index a6de2c48071..d7cdf8775b3 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1138,12 +1138,6 @@ class Project < ActiveRecord::Base self.runners_token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.runners_token) end - # TODO (ayufan): For now we use runners_token (backward compatibility) - # In 8.4 every build will have its own individual token valid for time of build - def valid_build_token?(token) - self.builds_enabled? && self.runners_token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.runners_token) - end - def build_coverage_enabled? build_coverage_regex.present? end diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index acf36d422d1..cda83bcc74a 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -64,6 +64,12 @@ class ProjectPolicy < BasePolicy can! :read_deployment end + # Permissions given when an user is direct member of a group + def restricted_reporter_access! + can! :restricted_download_code + can! :restricted_read_container_image + end + def developer_access! can! :admin_merge_request can! :update_merge_request @@ -130,10 +136,11 @@ class ProjectPolicy < BasePolicy def team_access!(user) access = project.team.max_member_access(user.id) - guest_access! if access >= Gitlab::Access::GUEST - reporter_access! if access >= Gitlab::Access::REPORTER - developer_access! if access >= Gitlab::Access::DEVELOPER - master_access! if access >= Gitlab::Access::MASTER + guest_access! if access >= Gitlab::Access::GUEST + reporter_access! if access >= Gitlab::Access::REPORTER + restricted_reporter_access! if access >= Gitlab::Access::REPORTER + developer_access! if access >= Gitlab::Access::DEVELOPER + master_access! if access >= Gitlab::Access::MASTER end def archived_access! diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb index 6072123b851..270d5a11d9e 100644 --- a/app/services/auth/container_registry_authentication_service.rb +++ b/app/services/auth/container_registry_authentication_service.rb @@ -4,7 +4,9 @@ module Auth AUDIENCE = 'container_registry' - def execute + def execute(access_type: access_type) + @access_type = access_type + return error('not found', 404) unless registry.enabled unless current_user || project @@ -74,9 +76,9 @@ module Auth case requested_action when 'pull' - requested_project == project || can?(current_user, :read_container_image, requested_project) + restricted_user_can_pull?(requested_project) || privileged_user_can_pull?(requested_project) when 'push' - requested_project == project || can?(current_user, :create_container_image, requested_project) + restricted_user_can_push?(requested_project) || privileged_user_can_push?(requested_project) else false end @@ -85,5 +87,37 @@ module Auth def registry Gitlab.config.registry end + + private + + def restricted_user_can_pull?(requested_project) + return false unless restricted? + + # Restricted can: + # 1. pull from it's own project (for ex. a build) + # 2. read images from dependent projects if he is a team member + requested_project == project || can?(current_user, :restricted_read_container_image, requested_project) + end + + def privileged_user_can_pull?(requested_project) + full? && can?(current_user, :read_container_image, requested_project) + end + + def restricted_user_can_push?(requested_project) + # Restricted can push only to project to from which he originates + restricted? && requested_project == project + end + + def privileged_user_can_push?(requested_project) + full? && can?(current_user, :create_container_image, requested_project) + end + + def full? + @access_type == :full + end + + def restricted? + @access_type == :restricted + end end end |