container_registry_authentication_service.rb 2.1 KB
Newer Older
1 2
module Auth
  class ContainerRegistryAuthenticationService < BaseService
3 4
    AUDIENCE = 'container_registry'

5
    def execute
6 7
      return error('not found', 404) unless registry.enabled

8
      unless current_user || project
9
        return error('forbidden', 403) unless scope
10 11
      end

K
Kamil Trzcinski 已提交
12
      { token: authorized_token(scope).encoded }
13 14
    end

15 16
    def self.full_access_token(*names)
      registry = Gitlab.config.registry
17
      token = JSONWebToken::RSAToken.new(registry.key)
18 19 20
      token.issuer = registry.issuer
      token.audience = AUDIENCE
      token[:access] = names.map do |name|
21
        { type: 'repository', name: name, actions: %w(*) }
22 23 24 25
      end
      token.encoded
    end

26 27
    private

K
Kamil Trzcinski 已提交
28 29
    def authorized_token(*accesses)
      token = JSONWebToken::RSAToken.new(registry.key)
30 31 32
      token.issuer = registry.issuer
      token.audience = params[:service]
      token.subject = current_user.try(:username)
33
      token[:access] = accesses.compact
34 35 36
      token
    end

K
Kamil Trzcinski 已提交
37
    def scope
38 39
      return unless params[:scope]

K
Kamil Trzcinski 已提交
40
      @scope ||= process_scope(params[:scope])
41 42 43 44 45
    end

    def process_scope(scope)
      type, name, actions = scope.split(':', 3)
      actions = actions.split(',')
K
Kamil Trzcinski 已提交
46
      return unless type == 'repository'
47

K
Kamil Trzcinski 已提交
48
      process_repository_access(type, name, actions)
49 50 51 52 53 54 55 56 57 58 59 60 61 62
    end

    def process_repository_access(type, name, actions)
      requested_project = Project.find_with_namespace(name)
      return unless requested_project

      actions = actions.select do |action|
        can_access?(requested_project, action)
      end

      { type: type, name: name, actions: actions } if actions.present?
    end

    def can_access?(requested_project, requested_action)
K
Kamil Trzcinski 已提交
63 64
      return false unless requested_project.container_registry_enabled?

65 66
      case requested_action
      when 'pull'
K
Kamil Trzcinski 已提交
67
        requested_project == project || can?(current_user, :read_container_image, requested_project)
68
      when 'push'
K
Kamil Trzcinski 已提交
69
        requested_project == project || can?(current_user, :create_container_image, requested_project)
70 71 72 73 74 75 76 77 78 79
      else
        false
      end
    end

    def registry
      Gitlab.config.registry
    end
  end
end