diff options
Diffstat (limited to 'app/services/auth/container_registry_authentication_service.rb')
-rw-r--r-- | app/services/auth/container_registry_authentication_service.rb | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb new file mode 100644 index 00000000000..e7aa7faeb96 --- /dev/null +++ b/app/services/auth/container_registry_authentication_service.rb @@ -0,0 +1,84 @@ +module Auth + class ContainerRegistryAuthenticationService < BaseService + AUDIENCE = 'container_registry' + + def execute + return error('not found', 404) unless registry.enabled + + 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 + + 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 + + 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 |