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

5 6 7 8 9
    def execute
      if params[:offline_token]
        return error('forbidden', 403) unless current_user
      end

10 11 12
      return error('forbidden', 401) if scopes.empty?

      { token: authorized_token(scopes).encoded }
13 14
    end

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

26 27
    private

28
    def authorized_token(access)
29 30
      token = ::Jwt::RSAToken.new(registry.key)
      token.issuer = registry.issuer
31
      token.audience = AUDIENCE
32 33 34 35 36
      token.subject = current_user.try(:username)
      token[:access] = access
      token
    end

37
    def scopes
38 39
      return unless params[:scope]

40 41 42 43
      @scopes ||= begin
        scope = process_scope(params[:scope])
        [scope].compact
      end
44 45 46 47 48 49 50 51 52 53 54 55 56
    end

    def process_scope(scope)
      type, name, actions = scope.split(':', 3)
      actions = actions.split(',')

      case type
      when 'repository'
        process_repository_access(type, name, actions)
      end
    end

    def process_repository_access(type, name, actions)
57 58
      requested_project = Project.find_with_namespace(name)
      return unless requested_project
59 60

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

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

67 68
    def can_access?(requested_project, requested_action)
      case requested_action
69
      when 'pull'
70
        requested_project.public? || requested_project == project || can?(current_user, :read_container_registry, requested_project)
71
      when 'push'
72
        requested_project == project || can?(current_user, :create_container_registry, requested_project)
73 74 75 76 77 78 79 80 81 82
      else
        false
      end
    end

    def registry
      Gitlab.config.registry
    end
  end
end