mixlib-authentication 2.0.0 → 3.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30042f8e3ac0f6ca2d793fa73556e19d41146554c6673788e2c0d7225e9f3584
4
- data.tar.gz: bed096ad15f32dca36dddfe79deb4f7b9f54a8656849b68393ce900944f3cc5b
3
+ metadata.gz: ffd7c02d4d9d20fdf32da899c6409fc59caffea1183d4c0806b0c02a20054538
4
+ data.tar.gz: 5f30cd2c44cc6b8375d9a950f596e2b89031654d315a822088baca00c1300b49
5
5
  SHA512:
6
- metadata.gz: f2bc4eff96e238290c9d3ec9cfc490b62372b9f4b0668dae56055f88844c8b8b971183000e4189d5ecfd8a4cc8b902aee753f103fecb839ad1bf9b33716d1840
7
- data.tar.gz: 0a03fd4b0a2016b93b681ba5a174dcc49089bd2aab2c2601bad114970a0680fe091bd562a6de4a0918f24e52b3eb512159287a239fb0cf1654ca91c452e34a4f
6
+ metadata.gz: 288e2b5de5735c93ebfe885ec24ae267dc056bbdff205b8ff0a4ad94f7691598965db5051ffd853811574ada1aeb10775685b4a4a864a870aa08377def77a801
7
+ data.tar.gz: 1c49b5589da86a7fe73d0d0c9914a148f0c95a0ff4762a711224bfc7d1a47fb20f98c7a9c6ad2a3a0d45bb6c42a90e295f7d6b98a5a8af80a99c96aafe9ecdf5
@@ -1,6 +1,6 @@
1
1
  #
2
- # Author:: Christopher Brown (<cb@opscode.com>)
3
- # Copyright:: Copyright (c) 2009 Opscode, Inc.
2
+ # Author:: Christopher Brown (<cb@chef.io>)
3
+ # Copyright:: Copyright (c) 2009-2018 Chef Software, Inc.
4
4
  # License:: Apache License, Version 2.0
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@
18
18
 
19
19
  module Mixlib
20
20
  module Authentication
21
- DEFAULT_SERVER_API_VERSION = "0"
21
+ DEFAULT_SERVER_API_VERSION = "0".freeze
22
22
 
23
23
  attr_accessor :logger
24
24
  module_function :logger, :logger=
@@ -36,7 +36,7 @@ module Mixlib
36
36
  require "mixlib/log"
37
37
  Mixlib::Authentication::Log.extend(Mixlib::Log)
38
38
  rescue LoadError
39
- require "mixlib/authentication/null_logger"
39
+ require_relative "authentication/null_logger"
40
40
  Mixlib::Authentication::Log.extend(Mixlib::Authentication::NullLogger)
41
41
  end
42
42
 
@@ -1,6 +1,6 @@
1
1
  #
2
- # Author:: Christopher Brown (<cb@opscode.com>)
3
- # Copyright:: Copyright (c) 2009 Opscode, Inc.
2
+ # Author:: Christopher Brown (<cb@chef.io>)
3
+ # Copyright:: Copyright (c) 2009-2018 Chef Software, Inc.
4
4
  # License:: Apache License, Version 2.0
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- require "mixlib/authentication"
19
+ require_relative "../authentication"
20
20
  require "openssl"
21
21
 
22
22
  module Mixlib
@@ -1,6 +1,6 @@
1
1
  #
2
- # Author:: Daniel DeLeo (<dan@opscode.com>)
3
- # Copyright:: Copyright (c) 2010 Opscode, Inc.
2
+ # Author:: Daniel DeLeo (<dan@chef.io>)
3
+ # Copyright:: Copyright (c) 2010-2018 Chef Software, Inc.
4
4
  # License:: Apache License, Version 2.0
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- require "mixlib/authentication"
19
+ require_relative "../authentication"
20
20
 
21
21
  module Mixlib
22
22
  module Authentication
23
23
  class HTTPAuthenticationRequest
24
24
 
25
- MANDATORY_HEADERS = [:x_ops_sign, :x_ops_userid, :x_ops_timestamp, :host, :x_ops_content_hash]
25
+ MANDATORY_HEADERS = %i{x_ops_sign x_ops_userid x_ops_timestamp host x_ops_content_hash}.freeze
26
26
 
27
27
  attr_reader :request
28
28
 
@@ -1,7 +1,7 @@
1
1
  #
2
- # Author:: Christopher Brown (<cb@opscode.com>)
3
- # Author:: Christopher Walters (<cw@opscode.com>)
4
- # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
2
+ # Author:: Christopher Brown (<cb@chef.io>)
3
+ # Author:: Christopher Walters (<cw@chef.io>)
4
+ # Copyright:: Copyright (c) 2009-2018 Chef Software, Inc.
5
5
  # License:: Apache License, Version 2.0
6
6
  #
7
7
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,9 +19,9 @@
19
19
 
20
20
  require "net/http"
21
21
  require "forwardable"
22
- require "mixlib/authentication"
23
- require "mixlib/authentication/http_authentication_request"
24
- require "mixlib/authentication/signedheaderauth"
22
+ require_relative "../authentication"
23
+ require_relative "http_authentication_request"
24
+ require_relative "signedheaderauth"
25
25
 
26
26
  module Mixlib
27
27
  module Authentication
@@ -203,7 +203,7 @@ module Mixlib
203
203
  # No file_param; we're running in Merb, or it's just not there..
204
204
  if file_param.nil?
205
205
  hash_param = request.params.values.find { |value| value.respond_to?(:has_key?) } # Hash responds to :has_key? .
206
- if !hash_param.nil?
206
+ unless hash_param.nil?
207
207
  file_param = hash_param.values.find { |value| value.respond_to?(:read) } # File/Tempfile responds to :read.
208
208
  end
209
209
  end
@@ -1,7 +1,7 @@
1
1
  #
2
- # Author:: Christopher Brown (<cb@opscode.com>)
3
- # Author:: Christopher Walters (<cw@opscode.com>)
4
- # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
2
+ # Author:: Christopher Brown (<cb@chef.io>)
3
+ # Author:: Christopher Walters (<cw@chef.io>)
4
+ # Copyright:: Copyright (c) 2009-2018 Chef Software, Inc.
5
5
  # License:: Apache License, Version 2.0
6
6
  #
7
7
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,8 +20,8 @@
20
20
  require "time"
21
21
  require "base64"
22
22
  require "openssl/digest"
23
- require "mixlib/authentication"
24
- require "mixlib/authentication/digester"
23
+ require_relative "../authentication"
24
+ require_relative "digester"
25
25
 
26
26
  module Mixlib
27
27
  module Authentication
@@ -34,7 +34,7 @@ module Mixlib
34
34
  "1.0" => "sha1",
35
35
  "1.1" => "sha1",
36
36
  "1.3" => "sha256",
37
- }.freeze()
37
+ }.freeze
38
38
 
39
39
  # Use of SUPPORTED_ALGORITHMS and SUPPORTED_VERSIONS is deprecated. Use
40
40
  # ALGORITHM_FOR_VERSION instead
@@ -74,15 +74,14 @@ module Mixlib
74
74
  # * `:host`: The host part of the URI
75
75
  def self.signing_object(args = {})
76
76
  SigningObject.new(args[:http_method],
77
- args[:path],
78
- args[:body],
79
- args[:host],
80
- args[:timestamp],
81
- args[:user_id],
82
- args[:file],
83
- args[:proto_version],
84
- args[:headers]
85
- )
77
+ args[:path],
78
+ args[:body],
79
+ args[:host],
80
+ args[:timestamp],
81
+ args[:user_id],
82
+ args[:file],
83
+ args[:proto_version],
84
+ args[:headers])
86
85
  end
87
86
 
88
87
  def algorithm
@@ -95,9 +94,28 @@ module Mixlib
95
94
 
96
95
  # Build the canonicalized request based on the method, other headers, etc.
97
96
  # compute the signature from the request, using the looked-up user secret
98
- # ====Parameters
99
- # private_key<OpenSSL::PKey::RSA>:: user's RSA private key.
100
- def sign(private_key, sign_algorithm = algorithm, sign_version = proto_version)
97
+ #
98
+ # @param rsa_key [OpenSSL::PKey::RSA] User's RSA key. If `use_ssh_agent` is
99
+ # true, this must have the public key portion populated. If `use_ssh_agent`
100
+ # is false, this must have the private key portion populated.
101
+ # @param use_ssh_agent [Boolean] If true, use ssh-agent for request signing.
102
+ def sign(rsa_key, sign_algorithm = algorithm, sign_version = proto_version, **opts)
103
+ # Backwards compat stuff.
104
+ if sign_algorithm.is_a?(Hash)
105
+ # Was called like sign(key, sign_algorithm: 'foo', other: 'bar')
106
+ opts.update(sign_algorithm)
107
+ opts[:sign_algorithm] ||= algorithm
108
+ opts[:sign_version] ||= sign_version
109
+ else
110
+ # Was called like sign(key, 'foo', '1.3', other: 'bar')
111
+ Mixlib::Authentication.logger.warn("Using deprecated positional arguments for sign(), please update to keyword arguments (from #{caller[1][/^(.*:\d+):in /, 1]})") unless sign_algorithm == algorithm
112
+ opts[:sign_algorithm] ||= sign_algorithm
113
+ opts[:sign_version] ||= sign_version
114
+ end
115
+ sign_algorithm = opts[:sign_algorithm]
116
+ sign_version = opts[:sign_version]
117
+ use_ssh_agent = opts[:use_ssh_agent]
118
+
101
119
  digest = validate_sign_version_digest!(sign_algorithm, sign_version)
102
120
  # Our multiline hash for authorization will be encoded in multiple header
103
121
  # lines - X-Ops-Authorization-1, ... (starts at 1, not 0!)
@@ -108,7 +126,7 @@ module Mixlib
108
126
  "X-Ops-Content-Hash" => hashed_body(digest),
109
127
  }
110
128
 
111
- signature = Base64.encode64(do_sign(private_key, digest, sign_algorithm, sign_version)).chomp
129
+ signature = Base64.encode64(do_sign(rsa_key, digest, sign_algorithm, sign_version, use_ssh_agent)).chomp
112
130
  signature_lines = signature.split(/\n/)
113
131
  signature_lines.each_index do |idx|
114
132
  key = "X-Ops-Authorization-#{idx + 1}"
@@ -156,7 +174,7 @@ module Mixlib
156
174
  # ====Parameters
157
175
  #
158
176
  def canonical_path
159
- p = path.gsub(/\/+/, "/")
177
+ p = path.gsub(%r{/+}, "/")
160
178
  p.length > 1 ? p.chomp("/") : p
161
179
  end
162
180
 
@@ -172,6 +190,7 @@ module Mixlib
172
190
  else
173
191
  @hashed_body_digest = digest
174
192
  end
193
+
175
194
  # Hash the file object if it was passed in, otherwise hash based on
176
195
  # the body.
177
196
  # TODO: tim 2009-12-28: It'd be nice to just remove this special case,
@@ -244,18 +263,75 @@ module Mixlib
244
263
  Mixlib::Authentication::Digester
245
264
  end
246
265
 
247
- # private
248
- def do_sign(private_key, digest, sign_algorithm, sign_version)
266
+ # Low-level RSA signature implementation used in {#sign}.
267
+ #
268
+ # @api private
269
+ # @param rsa_key [OpenSSL::PKey::RSA] User's RSA key. If `use_ssh_agent` is
270
+ # true, this must have the public key portion populated. If `use_ssh_agent`
271
+ # is false, this must have the private key portion populated.
272
+ # @param digest [Class] Sublcass of OpenSSL::Digest to use while signing.
273
+ # @param sign_algorithm [String] Hash algorithm to use while signing.
274
+ # @param sign_version [String] Version number of the signing protocol to use.
275
+ # @param use_ssh_agent [Boolean] If true, use ssh-agent for request signing.
276
+ # @return [String]
277
+ def do_sign(rsa_key, digest, sign_algorithm, sign_version, use_ssh_agent)
249
278
  string_to_sign = canonicalize_request(sign_algorithm, sign_version)
250
279
  Mixlib::Authentication.logger.trace "String to sign: '#{string_to_sign}'"
251
280
  case sign_version
252
281
  when "1.3"
253
- private_key.sign(digest.new, string_to_sign)
282
+ if use_ssh_agent
283
+ do_sign_ssh_agent(rsa_key, string_to_sign)
284
+ else
285
+ raise AuthenticationError, "RSA private key is required to sign requests, but a public key was provided" unless rsa_key.private?
286
+
287
+ rsa_key.sign(digest.new, string_to_sign)
288
+ end
254
289
  else
255
- private_key.private_encrypt(string_to_sign)
290
+ raise AuthenticationError, "Agent signing mode requires signing protocol version 1.3 or newer" if use_ssh_agent
291
+ raise AuthenticationError, "RSA private key is required to sign requests, but a public key was provided" unless rsa_key.private?
292
+
293
+ rsa_key.private_encrypt(string_to_sign)
256
294
  end
257
295
  end
258
296
 
297
+ # Low-level signing logic for using ssh-agent. This requires the user has
298
+ # already set up ssh-agent and used ssh-add to load in a (possibly encrypted)
299
+ # RSA private key. ssh-agent supports keys other than RSA, however they
300
+ # are not supported as Chef's protocol explicitly requires RSA keys/sigs.
301
+ #
302
+ # @api private
303
+ # @param rsa_key [OpenSSL::PKey::RSA] User's RSA public key.
304
+ # @param string_to_sign [String] String data to sign with the requested key.
305
+ # @return [String]
306
+ def do_sign_ssh_agent(rsa_key, string_to_sign)
307
+ # First try loading net-ssh as it is an optional dependency.
308
+ begin
309
+ require "net/ssh"
310
+ rescue LoadError => e
311
+ # ???: Since agent mode is explicitly enabled, should we even catch
312
+ # this in the first place? Might be cleaner to let the LoadError bubble.
313
+ raise AuthenticationError, "net-ssh gem is not available, unable to use ssh-agent signing: #{e.message}"
314
+ end
315
+
316
+ # Try to connect to ssh-agent.
317
+ begin
318
+ agent = Net::SSH::Authentication::Agent.connect
319
+ rescue Net::SSH::Authentication::AgentNotAvailable => e
320
+ raise AuthenticationError, "Could not connect to ssh-agent. Make sure the SSH_AUTH_SOCK environment variable is set and ssh-agent is running: #{e.message}"
321
+ end
322
+
323
+ begin
324
+ ssh2_signature = agent.sign(rsa_key.public_key, string_to_sign, Net::SSH::Authentication::Agent::SSH_AGENT_RSA_SHA2_256)
325
+ rescue Net::SSH::Authentication::AgentError => e
326
+ raise AuthenticationError, "Unable to sign request with ssh-agent. Make sure your key is loaded with ssh-add: #{e.class.name} #{e.message})"
327
+ end
328
+
329
+ # extract signature from SSH Agent response => skip first 20 bytes for RSA keys
330
+ # "\x00\x00\x00\frsa-sha2-256\x00\x00\x01\x00"
331
+ # (see http://api.libssh.org/rfc/PROTOCOL.agent for details)
332
+ ssh2_signature[20..-1]
333
+ end
334
+
259
335
  private :canonical_time, :canonical_path, :parse_signing_description, :digester, :canonicalize_user_id
260
336
 
261
337
  end
@@ -265,25 +341,25 @@ module Mixlib
265
341
  # generate a request signature. `SignedHeaderAuth.signing_object()`
266
342
  # provides a more convenient interface to the constructor.
267
343
  SigningObject = Struct.new(:http_method, :path, :body, :host,
268
- :timestamp, :user_id, :file, :proto_version,
269
- :headers) do
344
+ :timestamp, :user_id, :file, :proto_version,
345
+ :headers) do
270
346
 
271
- include SignedHeaderAuth
347
+ include SignedHeaderAuth
272
348
 
273
- def proto_version
274
- (self[:proto_version] || SignedHeaderAuth::DEFAULT_PROTO_VERSION).to_s
275
- end
349
+ def proto_version
350
+ (self[:proto_version] || SignedHeaderAuth::DEFAULT_PROTO_VERSION).to_s
351
+ end
276
352
 
277
- def server_api_version
278
- key = (self[:headers] || {}).keys.select do |k|
279
- k.casecmp("x-ops-server-api-version") == 0
280
- end.first
281
- if key
282
- self[:headers][key]
283
- else
284
- DEFAULT_SERVER_API_VERSION
353
+ def server_api_version
354
+ key = (self[:headers] || {}).keys.select do |k|
355
+ k.casecmp("x-ops-server-api-version") == 0
356
+ end.first
357
+ if key
358
+ self[:headers][key]
359
+ else
360
+ DEFAULT_SERVER_API_VERSION
361
+ end
285
362
  end
286
363
  end
287
- end
288
364
  end
289
365
  end
@@ -1,4 +1,5 @@
1
- # Copyright:: Copyright (c) 2010-2015 Chef Software, Inc.
1
+ #
2
+ # Copyright:: Copyright (c) 2010-2019, Chef Software Inc.
2
3
  # License:: Apache License, Version 2.0
3
4
  #
4
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,6 +16,6 @@
15
16
 
16
17
  module Mixlib
17
18
  module Authentication
18
- VERSION = "2.0.0"
19
+ VERSION = "3.0.6".freeze
19
20
  end
20
21
  end
metadata CHANGED
@@ -1,96 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mixlib-authentication
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 3.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chef Software, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-12 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: rspec-core
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '3.2'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '3.2'
27
- - !ruby/object:Gem::Dependency
28
- name: rspec-expectations
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '3.2'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '3.2'
41
- - !ruby/object:Gem::Dependency
42
- name: rspec-mocks
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '3.2'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '3.2'
55
- - !ruby/object:Gem::Dependency
56
- name: chefstyle
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: rake
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '11'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '11'
11
+ date: 2019-12-30 00:00:00.000000000 Z
12
+ dependencies: []
83
13
  description: Mixes in simple per-request authentication
84
14
  email: info@chef.io
85
15
  executables: []
86
16
  extensions: []
87
17
  extra_rdoc_files: []
88
18
  files:
89
- - Gemfile
90
19
  - LICENSE
91
- - NOTICE
92
- - README.md
93
- - Rakefile
94
20
  - lib/mixlib/authentication.rb
95
21
  - lib/mixlib/authentication/digester.rb
96
22
  - lib/mixlib/authentication/http_authentication_request.rb
@@ -98,13 +24,7 @@ files:
98
24
  - lib/mixlib/authentication/signatureverification.rb
99
25
  - lib/mixlib/authentication/signedheaderauth.rb
100
26
  - lib/mixlib/authentication/version.rb
101
- - mixlib-authentication.gemspec
102
- - spec/mixlib/authentication/digester_spec.rb
103
- - spec/mixlib/authentication/http_authentication_request_spec.rb
104
- - spec/mixlib/authentication/mixlib_authentication_spec.rb
105
- - spec/mixlib/authentication/mixlib_log_missing_spec.rb
106
- - spec/spec_helper.rb
107
- homepage: https://www.chef.io
27
+ homepage: https://github.com/chef/mixlib-authentication
108
28
  licenses:
109
29
  - Apache-2.0
110
30
  metadata: {}
@@ -116,15 +36,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
116
36
  requirements:
117
37
  - - ">="
118
38
  - !ruby/object:Gem::Version
119
- version: '0'
39
+ version: '2.4'
120
40
  required_rubygems_version: !ruby/object:Gem::Requirement
121
41
  requirements:
122
42
  - - ">="
123
43
  - !ruby/object:Gem::Version
124
44
  version: '0'
125
45
  requirements: []
126
- rubyforge_project:
127
- rubygems_version: 2.7.3
46
+ rubygems_version: 3.0.3
128
47
  signing_key:
129
48
  specification_version: 4
130
49
  summary: Mixes in simple per-request authentication