Class: R10K::Git::Rugged::Credentials Private
- Inherits:
-
Object
- Object
- R10K::Git::Rugged::Credentials
- Includes:
- Logging
- Defined in:
- lib/r10k/git/rugged/credentials.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
Generate credentials for secured remote connections.
Constant Summary
Constants included from Logging
Logging::LOG_LEVELS, Logging::SYSLOG_LEVELS_MAP
Instance Method Summary collapse
- #call(url, username_from_url, allowed_types) ⇒ Object private
- #extract_token(token_path, url) ⇒ Object private
- #get_default_credentials(url, username_from_url) ⇒ Object private
- #get_git_username(url, username_from_url) ⇒ Object private
- #get_plaintext_credentials(url, username_from_url) ⇒ Object private
- #get_ssh_key_credentials(url, username_from_url) ⇒ Object private
- #github_app_token(app_id, private_key, ttl) ⇒ Object private
-
#initialize(repository) ⇒ Credentials
constructor
private
A new instance of Credentials.
-
#valid_token?(token) ⇒ Boolean
private
This regex is the only real requirement for OAuth token format, per www.oauth.com/oauth2-servers/access-tokens/access-token-response/ Bitbucket’s tokens also can include an underscore, so that is added here.
Methods included from Logging
add_outputters, debug_formatter, default_formatter, default_outputter, #logger, #logger_name, parse_level
Constructor Details
#initialize(repository) ⇒ Credentials
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of Credentials.
17 18 19 20 |
# File 'lib/r10k/git/rugged/credentials.rb', line 17 def initialize(repository) @repository = repository @called = 0 end |
Instance Method Details
#call(url, username_from_url, allowed_types) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/r10k/git/rugged/credentials.rb', line 22 def call(url, username_from_url, allowed_types) @called += 1 # Break out of infinite HTTP auth retry loop introduced in libgit2/rugged 0.24.0, libssh # auth seems to already abort after ~50 attempts. if @called > 50 raise R10K::Git::GitError.new(_("Authentication failed for Git remote %{url}.") % {url: url.inspect} ) end if allowed_types.include?(:ssh_key) get_ssh_key_credentials(url, username_from_url) elsif allowed_types.include?(:plaintext) get_plaintext_credentials(url, username_from_url) else get_default_credentials(url, username_from_url) end end |
#extract_token(token_path, url) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/r10k/git/rugged/credentials.rb', line 99 def extract_token(token_path, url) if token_path == '-' token = $stdin.read.strip logger.debug2 _("Using OAuth token from stdin for URL %{url}") % { url: url } elsif File.readable?(token_path) token = File.read(token_path).strip logger.debug2 _("Using OAuth token from %{token_path} for URL %{url}") % { token_path: token_path, url: url } else raise R10K::Git::GitError, _("%{path} is missing or unreadable, cannot load OAuth token") % { path: token_path } end unless valid_token?(token) raise R10K::Git::GitError, _("Supplied OAuth token contains invalid characters.") end token end |
#get_default_credentials(url, username_from_url) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
124 125 126 |
# File 'lib/r10k/git/rugged/credentials.rb', line 124 def get_default_credentials(url, username_from_url) Rugged::Credentials::Default.new end |
#get_git_username(url, username_from_url) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/r10k/git/rugged/credentials.rb', line 128 def get_git_username(url, username_from_url) git_user = R10K::Git.settings[:username] user = nil if !username_from_url.nil? && !username_from_url.empty? user = username_from_url logger.debug2 _("URL %{url} includes the username %{username}, using that user for authentication.") % {url: url.inspect, username: username_from_url} elsif git_user user = git_user logger.debug2 _("URL %{url} did not specify a user, using %{user} from configuration") % {url: url.inspect, user: user.inspect} else user = Etc.getlogin logger.debug2 _("URL %{url} did not specify a user, using current user %{user}") % {url: url.inspect, user: user.inspect} end user end |
#get_plaintext_credentials(url, username_from_url) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/r10k/git/rugged/credentials.rb', line 67 def get_plaintext_credentials(url, username_from_url) per_repo_oauth_token = nil per_repo_github_app_id = nil per_repo_github_app_key = nil per_repo_github_app_ttl = nil if per_repo_settings = R10K::Git.get_repo_settings(url) per_repo_oauth_token = per_repo_settings[:oauth_token] per_repo_github_app_id = per_repo_settings[:github_app_id] per_repo_github_app_key = per_repo_settings[:github_app_key] per_repo_github_app_ttl = per_repo_settings[:github_app_ttl] end app_id = per_repo_github_app_id || R10K::Git.settings[:github_app_id] app_key = per_repo_github_app_key || R10K::Git.settings[:github_app_key] app_ttl = per_repo_github_app_ttl || R10K::Git.settings[:github_app_ttl] if token_path = per_repo_oauth_token || R10K::Git.settings[:oauth_token] @oauth_token ||= extract_token(token_path, url) user = 'x-oauth-token' password = @oauth_token elsif app_id && app_key && app_ttl user = 'x-access-token' password = github_app_token(app_id, app_key, app_ttl) else user = get_git_username(url, username_from_url) password = URI.parse(url).password || '' end Rugged::Credentials::UserPassword.new(username: user, password: password) end |
#get_ssh_key_credentials(url, username_from_url) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
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 |
# File 'lib/r10k/git/rugged/credentials.rb', line 40 def get_ssh_key_credentials(url, username_from_url) user = get_git_username(url, username_from_url) per_repo_private_key = nil if per_repo_settings = R10K::Git.get_repo_settings(url) per_repo_private_key = per_repo_settings[:private_key] end global_private_key = R10K::Git.settings[:private_key] if per_repo_private_key private_key = per_repo_private_key logger.debug2 _("Using per-repository private key %{key} for URL %{url}") % {key: private_key, url: url.inspect} elsif global_private_key private_key = global_private_key logger.debug2 _("URL %{url} has no per-repository private key using '%{key}'." ) % {key: private_key, url: url.inspect} else raise R10K::Git::GitError.new(_("Git remote %{url} uses the SSH protocol but no private key was given") % {url: url.inspect}, :git_dir => @repository.path.to_s) end if !File.readable?(private_key) raise R10K::Git::GitError.new(_("Unable to use SSH key auth for %{url}: private key %{private_key} is missing or unreadable") % {url: url.inspect, private_key: private_key.inspect}, :git_dir => @repository.path.to_s) end Rugged::Credentials::SshKey.new(:username => user, :privatekey => private_key) end |
#github_app_token(app_id, private_key, ttl) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/r10k/git/rugged/credentials.rb', line 147 def github_app_token(app_id, private_key, ttl) raise R10K::Git::GitError, _('Github App id contains invalid characters.') unless app_id =~ /^\d+$/ raise R10K::Git::GitError, _('Github App token ttl contains invalid characters.') unless ttl =~ /^\d+$/ raise R10K::Git::GitError, _('Github App key is missing or unreadable') unless File.readable?(private_key) begin ssl_key = OpenSSL::PKey::RSA.new(File.read(private_key).strip) unless ssl_key.private? raise R10K::Git::GitError, _('Github App key is not a valid SSL private key') end rescue OpenSSL::PKey::RSAError raise R10K::Git::GitError, _('Github App key is not a valid SSL key') end logger.debug2 _("Using Github App id %{app_id} with SSL key from %{key_path}") % { key_path: private_key, app_id: app_id } jwt_issue_time = Time.now.to_i - 60 jwt_exp_time = (jwt_issue_time + 60) + ttl.to_i payload = { iat: jwt_issue_time, exp: jwt_exp_time, iss: app_id } jwt = JWT.encode(payload, ssl_key, "RS256") get = URI.parse("https://api.github.com/app/installations") get_request = Net::HTTP::Get.new(get) get_request["Authorization"] = "Bearer #{jwt}" get_request["Accept"] = "application/vnd.github.v3+json" = { use_ssl: get.scheme == "https", } get_response = Net::HTTP.start(get.hostname, get.port, ) do |http| http.request(get_request) end unless (get_response.class < Net::HTTPSuccess) logger.debug2 _("Unexpected response code: #{get_response.code}\nResponse body: #{get_response.body}") raise R10K::Git::GitError, _("Error using private key to get Github App access token from url") end access_tokens_url = JSON.parse(get_response.body)[0]['access_tokens_url'] post = URI.parse(access_tokens_url) post_request = Net::HTTP::Post.new(post) post_request["Authorization"] = "Bearer #{jwt}" post_request["Accept"] = "application/vnd.github.v3+json" = { use_ssl: post.scheme == "https", } post_response = Net::HTTP.start(post.hostname, post.port, ) do |http| http.request(post_request) end unless (post_response.class < Net::HTTPSuccess) logger.debug2 _("Unexpected response code: #{post_response.code}\nResponse body: #{post_response.body}") raise R10K::Git::GitError, _("Error using private key to generate access token from #{access_token_url}") end token = JSON.parse(post_response.body)['token'] raise R10K::Git::GitError, _("Github App token contains invalid characters.") unless valid_token?(token) logger.debug2 _("Github App token generated, expires at: %{expire}") % {expire: JSON.parse(post_response.body)['expires_at']} token end |
#valid_token?(token) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This regex is the only real requirement for OAuth token format, per www.oauth.com/oauth2-servers/access-tokens/access-token-response/ Bitbucket’s tokens also can include an underscore, so that is added here.
120 121 122 |
# File 'lib/r10k/git/rugged/credentials.rb', line 120 def valid_token?(token) return token =~ /^[\w\-\.~_\+\/]+$/ end |