container_registry_authentication_service.rb 2.16 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
9
10
11
12
13
14
15
16
      if params[:offline_token]
        return error('forbidden', 403) unless current_user
      end

      return error('forbidden', 401) if scopes.blank?

      { token: authorized_token(scopes).encoded }
    end

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

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
    private

    def authorized_token(access)
      token = ::JWT::RSAToken.new(registry.key)
      token.issuer = registry.issuer
      token.audience = params[:service]
      token.subject = current_user.try(:username)
      token[:access] = access
      token
    end

    def scopes
      return unless params[:scope]

      @scopes ||= begin
        scope = process_scope(params[:scope])
        [scope].compact
      end
    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)
      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)
      case requested_action
      when 'pull'
        requested_project.public? || requested_project == project || can?(current_user, :read_container_registry, requested_project)
      when 'push'
        requested_project == project || can?(current_user, :create_container_registry, requested_project)
      else
        false
      end
    end

    def registry
      Gitlab.config.registry
    end
  end
end