From f1bc7b6eb5cb9beab55e4edac87cc5e0b7ceb069 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Mon, 12 Nov 2018 10:52:48 +0000 Subject: SSH public-key authentication for push mirroring --- app/models/remote_mirror.rb | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'app/models/remote_mirror.rb') diff --git a/app/models/remote_mirror.rb b/app/models/remote_mirror.rb index c1f53b5da4f..a3415a4a14c 100644 --- a/app/models/remote_mirror.rb +++ b/app/models/remote_mirror.rb @@ -2,6 +2,7 @@ class RemoteMirror < ActiveRecord::Base include AfterCommitQueue + include MirrorAuthentication PROTECTED_BACKOFF_DELAY = 1.minute UNPROTECTED_BACKOFF_DELAY = 5.minutes @@ -28,6 +29,8 @@ class RemoteMirror < ActiveRecord::Base after_commit :remove_remote, on: :destroy + before_validation :store_credentials + scope :enabled, -> { where(enabled: true) } scope :started, -> { with_update_status(:started) } scope :stuck, -> { started.where('last_update_at < ? OR (last_update_at IS NULL AND updated_at < ?)', 1.day.ago, 1.day.ago) } @@ -84,7 +87,21 @@ class RemoteMirror < ActiveRecord::Base end def update_repository(options) - raw.update(options) + if ssh_mirror_url? + if ssh_key_auth? && ssh_private_key.present? + options[:ssh_key] = ssh_private_key + end + + if ssh_known_hosts.present? + options[:known_hosts] = ssh_known_hosts + end + end + + Gitlab::Git::RemoteMirror.new( + project.repository.raw, + remote_name, + **options + ).update end def sync? @@ -128,7 +145,8 @@ class RemoteMirror < ActiveRecord::Base super(value) && return unless Gitlab::UrlSanitizer.valid?(value) mirror_url = Gitlab::UrlSanitizer.new(value) - self.credentials = mirror_url.credentials + self.credentials ||= {} + self.credentials = self.credentials.merge(mirror_url.credentials) super(mirror_url.sanitized_url) end @@ -152,17 +170,28 @@ class RemoteMirror < ActiveRecord::Base def ensure_remote! return unless project - return unless remote_name && url + return unless remote_name && remote_url # If this fails or the remote already exists, we won't know due to # https://gitlab.com/gitlab-org/gitaly/issues/1317 - project.repository.add_remote(remote_name, url) + project.repository.add_remote(remote_name, remote_url) end private - def raw - @raw ||= Gitlab::Git::RemoteMirror.new(project.repository.raw, remote_name) + def store_credentials + # This is a necessary workaround for attr_encrypted, which doesn't otherwise + # notice that the credentials have changed + self.credentials = self.credentials + end + + # The remote URL omits any password if SSH public-key authentication is in use + def remote_url + return url unless ssh_key_auth? && password.present? + + Gitlab::UrlSanitizer.new(read_attribute(:url), credentials: { user: user }).full_url + rescue + super end def fallback_remote_name @@ -214,7 +243,7 @@ class RemoteMirror < ActiveRecord::Base project.repository.async_remove_remote(prev_remote_name) end - project.repository.add_remote(remote_name, url) + project.repository.add_remote(remote_name, remote_url) end def remove_remote @@ -224,6 +253,6 @@ class RemoteMirror < ActiveRecord::Base end def mirror_url_changed? - url_changed? || encrypted_credentials_changed? + url_changed? || credentials_changed? end end -- cgit v1.2.1