mixlib-authentication 1.4.0.rc.1 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/NOTICE +2 -2
- data/{README.rdoc → README.md} +9 -11
- data/Rakefile +11 -39
- data/lib/mixlib/authentication.rb +7 -9
- data/lib/mixlib/authentication/digester.rb +6 -6
- data/lib/mixlib/authentication/http_authentication_request.rb +5 -6
- data/lib/mixlib/authentication/signatureverification.rb +30 -35
- data/lib/mixlib/authentication/signedheaderauth.rb +26 -26
- data/lib/mixlib/authentication/version.rb +1 -2
- data/mixlib-authentication.gemspec +11 -11
- data/spec/mixlib/authentication/digester_spec.rb +6 -6
- data/spec/mixlib/authentication/http_authentication_request_spec.rb +44 -44
- data/spec/mixlib/authentication/mixlib_authentication_spec.rb +127 -129
- data/spec/spec_helper.rb +3 -3
- metadata +29 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9909dd06ad5a2444688f93330b5c9128238d14e0
|
4
|
+
data.tar.gz: d9c72f4ae75782b00398ce12bc6823778e8aef45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 606bfed6570c5fbc8c02bcf827985a07003cb191a60dada99496bf073427b91d7fb6e7db966a2c357d082f1d6306f9a8f67cb97708a119d05390db5a77fd3b2f
|
7
|
+
data.tar.gz: 6305dcaae186d7a39054164a7061226b11713b9e35a5f5ca91d6f2025f42d838f174e9e699e616b2786fa776ef001929d33ff53858ed3a4e534193b206aed211
|
data/Gemfile
CHANGED
data/NOTICE
CHANGED
data/{README.rdoc → README.md}
RENAMED
@@ -1,13 +1,14 @@
|
|
1
|
-
|
1
|
+
# Mixlib::Authentication
|
2
|
+
[](https://travis-ci.org/chef/mixlib-authentication) [](https://badge.fury.io/rb/mixlib-authentication)
|
2
3
|
|
3
|
-
Mixlib::Authentication provides a class-based header signing authentication object, like the one used in Chef.
|
4
|
+
Mixlib::Authentication provides a class-based header signing authentication object, like the one used in Chef.
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
License:: Apache License, Version 2.0
|
6
|
+
## License
|
7
|
+
- Author:: Christopher Brown ([cb@chef.io](mailto:cb@chef.io))
|
8
|
+
- Copyright:: Copyright (c) 2009-2016 Chef Software, Inc.
|
9
|
+
- License:: Apache License, Version 2.0
|
10
10
|
|
11
|
+
```text
|
11
12
|
Licensed under the Apache License, Version 2.0 (the "License");
|
12
13
|
you may not use this file except in compliance with the License.
|
13
14
|
You may obtain a copy of the License at
|
@@ -19,7 +20,4 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
20
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
20
21
|
See the License for the specific language governing permissions and
|
21
22
|
limitations under the License.
|
22
|
-
|
23
|
-
== Issue Tracker
|
24
|
-
|
25
|
-
Report any issues via Opscode Jira instance at http://tickets.opscode.com against Chef project.
|
23
|
+
```
|
data/Rakefile
CHANGED
@@ -1,46 +1,18 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require 'rubygems/specification'
|
4
|
-
require 'date'
|
5
|
-
require 'rspec/core/rake_task'
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
6
3
|
|
7
|
-
|
8
|
-
GEM_VERSION = "1.2.1"
|
9
|
-
AUTHOR = "Opscode, Inc."
|
10
|
-
EMAIL = "info@opscode.com"
|
11
|
-
HOMEPAGE = "http://www.opscode.com"
|
12
|
-
SUMMARY = "Mixes in simple per-request authentication"
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
13
5
|
|
14
6
|
task :default => :spec
|
15
7
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
gem_spec = eval(File.read("mixlib-authentication.gemspec"))
|
23
|
-
|
24
|
-
Gem::PackageTask.new(gem_spec) do |pkg|
|
25
|
-
pkg.gem_spec = gem_spec
|
26
|
-
end
|
27
|
-
|
28
|
-
desc "install the gem locally"
|
29
|
-
task :install => [:package] do
|
30
|
-
sh %{gem install pkg/#{GEM}-#{GEM_VERSION}}
|
31
|
-
end
|
32
|
-
|
33
|
-
desc "create a gemspec file"
|
34
|
-
task :make_spec do
|
35
|
-
File.open("#{GEM}.gemspec", "w") do |file|
|
36
|
-
file.puts spec.to_ruby
|
8
|
+
begin
|
9
|
+
require "chefstyle"
|
10
|
+
require "rubocop/rake_task"
|
11
|
+
RuboCop::RakeTask.new(:style) do |task|
|
12
|
+
task.options += ["--display-cop-names", "--no-color"]
|
37
13
|
end
|
14
|
+
rescue
|
15
|
+
puts "chefstyle/rubocop is not available."
|
38
16
|
end
|
39
17
|
|
40
|
-
|
41
|
-
task :clean do
|
42
|
-
sh %Q{ rm -f pkg/*.gem }
|
43
|
-
end
|
44
|
-
|
45
|
-
desc "Run the spec and features"
|
46
|
-
task :test => [ :features, :spec ]
|
18
|
+
task :ci => [:style, :spec]
|
@@ -6,9 +6,9 @@
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
8
8
|
# You may obtain a copy of the License at
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# Unless required by applicable law or agreed to in writing, software
|
13
13
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
14
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -16,11 +16,11 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
-
require
|
19
|
+
require "mixlib/log"
|
20
20
|
|
21
21
|
module Mixlib
|
22
22
|
module Authentication
|
23
|
-
DEFAULT_SERVER_API_VERSION =
|
23
|
+
DEFAULT_SERVER_API_VERSION = "0"
|
24
24
|
|
25
25
|
class AuthenticationError < StandardError
|
26
26
|
end
|
@@ -29,12 +29,10 @@ module Mixlib
|
|
29
29
|
end
|
30
30
|
|
31
31
|
class Log
|
32
|
-
extend
|
32
|
+
extend Mixlib::Log
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
Log.level = :error
|
36
|
-
|
36
|
+
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
40
|
-
|
@@ -6,9 +6,9 @@
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
8
8
|
# You may obtain a copy of the License at
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# Unless required by applicable law or agreed to in writing, software
|
13
13
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
14
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -16,15 +16,15 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
-
require
|
20
|
-
require
|
19
|
+
require "mixlib/authentication"
|
20
|
+
require "openssl"
|
21
21
|
|
22
22
|
module Mixlib
|
23
23
|
module Authentication
|
24
24
|
class Digester
|
25
25
|
class << self
|
26
26
|
|
27
|
-
def hash_file(f, digest=OpenSSL::Digest::SHA1)
|
27
|
+
def hash_file(f, digest = OpenSSL::Digest::SHA1)
|
28
28
|
digester = digest.new
|
29
29
|
buf = ""
|
30
30
|
while f.read(16384, buf)
|
@@ -37,7 +37,7 @@ module Mixlib
|
|
37
37
|
#
|
38
38
|
# ====Parameters
|
39
39
|
#
|
40
|
-
def hash_string(str, digest=OpenSSL::Digest::SHA1)
|
40
|
+
def hash_string(str, digest = OpenSSL::Digest::SHA1)
|
41
41
|
::Base64.encode64(digest.digest(str)).chomp
|
42
42
|
end
|
43
43
|
|
@@ -6,9 +6,9 @@
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
8
8
|
# You may obtain a copy of the License at
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# Unless required by applicable law or agreed to in writing, software
|
13
13
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
14
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -16,7 +16,7 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
-
require
|
19
|
+
require "mixlib/authentication"
|
20
20
|
|
21
21
|
module Mixlib
|
22
22
|
module Authentication
|
@@ -33,7 +33,7 @@ module Mixlib
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def headers
|
36
|
-
@headers ||= @request.env.inject({
|
36
|
+
@headers ||= @request.env.inject({}) { |memo, kv| memo[$2.tr("-", "_").downcase.to_sym] = kv[1] if kv[0] =~ /^(HTTP_)(.*)/; memo }
|
37
37
|
end
|
38
38
|
|
39
39
|
def http_method
|
@@ -70,13 +70,12 @@ module Mixlib
|
|
70
70
|
|
71
71
|
def request_signature
|
72
72
|
unless @request_signature
|
73
|
-
@request_signature = headers.find_all { |h| h[0].to_s =~ /^x_ops_authorization_/ }.sort { |x,y| x.to_s <=> y.to_s}.map { |i| i[1] }.join("\n")
|
73
|
+
@request_signature = headers.find_all { |h| h[0].to_s =~ /^x_ops_authorization_/ }.sort { |x, y| x.to_s <=> y.to_s }.map { |i| i[1] }.join("\n")
|
74
74
|
Mixlib::Authentication::Log.debug "Reconstituted (user-supplied) request signature: #{@request_signature}"
|
75
75
|
end
|
76
76
|
@request_signature
|
77
77
|
end
|
78
78
|
|
79
|
-
|
80
79
|
def validate_headers!
|
81
80
|
missing_headers = MANDATORY_HEADERS - headers.keys
|
82
81
|
unless missing_headers.empty?
|
@@ -7,9 +7,9 @@
|
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
8
|
# you may not use this file except in compliance with the License.
|
9
9
|
# You may obtain a copy of the License at
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# Unless required by applicable law or agreed to in writing, software
|
14
14
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
15
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -17,11 +17,11 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
24
|
-
require
|
20
|
+
require "net/http"
|
21
|
+
require "forwardable"
|
22
|
+
require "mixlib/authentication"
|
23
|
+
require "mixlib/authentication/http_authentication_request"
|
24
|
+
require "mixlib/authentication/signedheaderauth"
|
25
25
|
|
26
26
|
module Mixlib
|
27
27
|
module Authentication
|
@@ -52,7 +52,7 @@ module Mixlib
|
|
52
52
|
|
53
53
|
include Mixlib::Authentication::SignedHeaderAuth
|
54
54
|
|
55
|
-
def initialize(request=nil)
|
55
|
+
def initialize(request = nil)
|
56
56
|
@auth_request = HTTPAuthenticationRequest.new(request) if request
|
57
57
|
|
58
58
|
@valid_signature, @valid_timestamp, @valid_content_hash = false, false, false
|
@@ -60,8 +60,7 @@ module Mixlib
|
|
60
60
|
@hashed_body = nil
|
61
61
|
end
|
62
62
|
|
63
|
-
|
64
|
-
def authenticate_user_request(request, user_lookup, time_skew=(15*60))
|
63
|
+
def authenticate_user_request(request, user_lookup, time_skew = (15 * 60))
|
65
64
|
@auth_request = HTTPAuthenticationRequest.new(request)
|
66
65
|
authenticate_request(user_lookup, time_skew)
|
67
66
|
end
|
@@ -74,9 +73,9 @@ module Mixlib
|
|
74
73
|
# X-Ops-Sign: algorithm=sha1;version=1.0;
|
75
74
|
# X-Ops-UserId: <user_id>
|
76
75
|
# X-Ops-Timestamp:
|
77
|
-
# X-Ops-Content-Hash:
|
76
|
+
# X-Ops-Content-Hash:
|
78
77
|
# X-Ops-Authorization-#{line_number}
|
79
|
-
def authenticate_request(user_secret, time_skew=(15*60))
|
78
|
+
def authenticate_request(user_secret, time_skew = (15 * 60))
|
80
79
|
Mixlib::Authentication::Log.debug "Initializing header auth : #{request.inspect}"
|
81
80
|
|
82
81
|
@user_secret = user_secret
|
@@ -87,14 +86,14 @@ module Mixlib
|
|
87
86
|
|
88
87
|
# version 1.0 clients don't include their algorithm in the
|
89
88
|
# signing description, so default to sha1
|
90
|
-
parts[:algorithm] ||=
|
89
|
+
parts[:algorithm] ||= "sha1"
|
91
90
|
|
92
91
|
verify_signature(parts[:algorithm], parts[:version])
|
93
92
|
verify_timestamp
|
94
93
|
verify_content_hash
|
95
94
|
|
96
|
-
rescue StandardError=>se
|
97
|
-
raise AuthenticationError,"Failed to authenticate user request. Check your client key and clock: #{se.message}", se.backtrace
|
95
|
+
rescue StandardError => se
|
96
|
+
raise AuthenticationError, "Failed to authenticate user request. Check your client key and clock: #{se.message}", se.backtrace
|
98
97
|
end
|
99
98
|
|
100
99
|
if valid_request?
|
@@ -121,11 +120,11 @@ module Mixlib
|
|
121
120
|
end
|
122
121
|
|
123
122
|
# The authorization header is a Base64-encoded version of an RSA signature.
|
124
|
-
# The client sent it on multiple header lines, starting at index 1 -
|
123
|
+
# The client sent it on multiple header lines, starting at index 1 -
|
125
124
|
# X-Ops-Authorization-1, X-Ops-Authorization-2, etc. Pull them out and
|
126
125
|
# concatenate.
|
127
126
|
def headers
|
128
|
-
@headers ||= request.env.inject({
|
127
|
+
@headers ||= request.env.inject({}) { |memo, kv| memo[$2.tr("-", "_").downcase.to_sym] = kv[1] if kv[0] =~ /^(HTTP_)(.*)/; memo }
|
129
128
|
end
|
130
129
|
|
131
130
|
private
|
@@ -142,7 +141,7 @@ module Mixlib
|
|
142
141
|
candidate_block = canonicalize_request(algorithm, version)
|
143
142
|
signature = Base64.decode64(request_signature)
|
144
143
|
@valid_signature = case version
|
145
|
-
when
|
144
|
+
when "1.3"
|
146
145
|
digest = validate_sign_version_digest!(algorithm, version)
|
147
146
|
@user_secret.verify(digest.new, signature, candidate_block)
|
148
147
|
else
|
@@ -177,10 +176,9 @@ module Mixlib
|
|
177
176
|
@valid_content_hash
|
178
177
|
end
|
179
178
|
|
180
|
-
|
181
179
|
# The request signature is based on any file attached, if any. Otherwise
|
182
180
|
# it's based on the body of the request.
|
183
|
-
def hashed_body(digest=Digest::SHA1)
|
181
|
+
def hashed_body(digest = Digest::SHA1)
|
184
182
|
unless @hashed_body
|
185
183
|
# TODO: tim: 2009-112-28: It'd be nice to remove this special case, and
|
186
184
|
# always hash the entire request body. In the file case it would just be
|
@@ -189,22 +187,22 @@ module Mixlib
|
|
189
187
|
# Pull out any file that was attached to this request, using multipart
|
190
188
|
# form uploads.
|
191
189
|
# Depending on the server we're running in, multipart form uploads are
|
192
|
-
# handed to us differently.
|
193
|
-
# - In Passenger (Cookbooks Community Site), the File is handed to us
|
194
|
-
# directly in the params hash. The name is whatever the client used,
|
195
|
-
# its value is therefore a File or Tempfile.
|
190
|
+
# handed to us differently.
|
191
|
+
# - In Passenger (Cookbooks Community Site), the File is handed to us
|
192
|
+
# directly in the params hash. The name is whatever the client used,
|
193
|
+
# its value is therefore a File or Tempfile.
|
196
194
|
# e.g. request['file_param'] = File
|
197
|
-
#
|
198
|
-
# - In Merb (Chef server), the File is wrapped. The original parameter
|
195
|
+
#
|
196
|
+
# - In Merb (Chef server), the File is wrapped. The original parameter
|
199
197
|
# name used for the file is used, but its value is a Hash. Within
|
200
|
-
# the hash is a name/value pair named 'file' which actually
|
198
|
+
# the hash is a name/value pair named 'file' which actually
|
201
199
|
# contains the Tempfile instance.
|
202
200
|
# e.g. request['file_param'] = { :file => Tempfile }
|
203
201
|
file_param = request.params.values.find { |value| value.respond_to?(:read) }
|
204
202
|
|
205
203
|
# No file_param; we're running in Merb, or it's just not there..
|
206
204
|
if file_param.nil?
|
207
|
-
hash_param = request.params.values.find { |value| value.respond_to?(:has_key?) }
|
205
|
+
hash_param = request.params.values.find { |value| value.respond_to?(:has_key?) } # Hash responds to :has_key? .
|
208
206
|
if !hash_param.nil?
|
209
207
|
file_param = hash_param.values.find { |value| value.respond_to?(:read) } # File/Tempfile responds to :read.
|
210
208
|
end
|
@@ -225,22 +223,19 @@ module Mixlib
|
|
225
223
|
end
|
226
224
|
|
227
225
|
# Compare the request timestamp with boundary time
|
228
|
-
#
|
229
|
-
#
|
226
|
+
#
|
227
|
+
#
|
230
228
|
# ====Parameters
|
231
229
|
# time1<Time>:: minuend
|
232
230
|
# time2<Time>:: subtrahend
|
233
231
|
#
|
234
232
|
def timestamp_within_bounds?(time1, time2)
|
235
|
-
time_diff = (time2-time1).abs
|
233
|
+
time_diff = (time2 - time1).abs
|
236
234
|
is_allowed = (time_diff < @allowed_time_skew)
|
237
235
|
Mixlib::Authentication::Log.debug "Request time difference: #{time_diff}, within #{@allowed_time_skew} seconds? : #{!!is_allowed}"
|
238
|
-
is_allowed
|
236
|
+
is_allowed
|
239
237
|
end
|
240
238
|
end
|
241
239
|
|
242
|
-
|
243
240
|
end
|
244
241
|
end
|
245
|
-
|
246
|
-
|
@@ -17,11 +17,11 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
24
|
-
require
|
20
|
+
require "time"
|
21
|
+
require "base64"
|
22
|
+
require "openssl/digest"
|
23
|
+
require "mixlib/authentication"
|
24
|
+
require "mixlib/authentication/digester"
|
25
25
|
|
26
26
|
module Mixlib
|
27
27
|
module Authentication
|
@@ -31,18 +31,18 @@ module Mixlib
|
|
31
31
|
NULL_ARG = Object.new
|
32
32
|
|
33
33
|
ALGORITHM_FOR_VERSION = {
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
"1.0" => "sha1",
|
35
|
+
"1.1" => "sha1",
|
36
|
+
"1.3" => "sha256",
|
37
37
|
}.freeze()
|
38
38
|
|
39
39
|
# Use of SUPPORTED_ALGORITHMS and SUPPORTED_VERSIONS is deprecated. Use
|
40
40
|
# ALGORITHM_FOR_VERSION instead
|
41
|
-
SUPPORTED_ALGORITHMS = [
|
42
|
-
SUPPORTED_VERSIONS = [
|
41
|
+
SUPPORTED_ALGORITHMS = ["sha1"].freeze
|
42
|
+
SUPPORTED_VERSIONS = ["1.0", "1.1"].freeze
|
43
43
|
|
44
|
-
DEFAULT_SIGN_ALGORITHM =
|
45
|
-
DEFAULT_PROTO_VERSION =
|
44
|
+
DEFAULT_SIGN_ALGORITHM = "sha1".freeze
|
45
|
+
DEFAULT_PROTO_VERSION = "1.0".freeze
|
46
46
|
|
47
47
|
# === signing_object
|
48
48
|
# This is the intended interface for signing requests with the
|
@@ -72,7 +72,7 @@ module Mixlib
|
|
72
72
|
# ==== Other Parameters:
|
73
73
|
# These parameters are accepted but not used in the computation of the signature.
|
74
74
|
# * `:host`: The host part of the URI
|
75
|
-
def self.signing_object(args={
|
75
|
+
def self.signing_object(args = {})
|
76
76
|
SigningObject.new(args[:http_method],
|
77
77
|
args[:path],
|
78
78
|
args[:body],
|
@@ -97,7 +97,7 @@ module Mixlib
|
|
97
97
|
# compute the signature from the request, using the looked-up user secret
|
98
98
|
# ====Parameters
|
99
99
|
# private_key<OpenSSL::PKey::RSA>:: user's RSA private key.
|
100
|
-
def sign(private_key, sign_algorithm=algorithm, sign_version=proto_version)
|
100
|
+
def sign(private_key, sign_algorithm = algorithm, sign_version = proto_version)
|
101
101
|
digest = validate_sign_version_digest!(sign_algorithm, sign_version)
|
102
102
|
# Our multiline hash for authorization will be encoded in multiple header
|
103
103
|
# lines - X-Ops-Authorization-1, ... (starts at 1, not 0!)
|
@@ -132,9 +132,9 @@ module Mixlib
|
|
132
132
|
end
|
133
133
|
|
134
134
|
case sign_algorithm
|
135
|
-
when
|
135
|
+
when "sha1"
|
136
136
|
OpenSSL::Digest::SHA1
|
137
|
-
when
|
137
|
+
when "sha256"
|
138
138
|
OpenSSL::Digest::SHA256
|
139
139
|
else
|
140
140
|
# This case should never happen
|
@@ -156,11 +156,11 @@ module Mixlib
|
|
156
156
|
# ====Parameters
|
157
157
|
#
|
158
158
|
def canonical_path
|
159
|
-
p = path.gsub(/\/+/,
|
160
|
-
p.length > 1 ? p.chomp(
|
159
|
+
p = path.gsub(/\/+/, "/")
|
160
|
+
p.length > 1 ? p.chomp("/") : p
|
161
161
|
end
|
162
162
|
|
163
|
-
def hashed_body(digest=OpenSSL::Digest::SHA1)
|
163
|
+
def hashed_body(digest = OpenSSL::Digest::SHA1)
|
164
164
|
# This is weird. sign() is called with the digest type and signing
|
165
165
|
# version. These are also expected to be properties of the object.
|
166
166
|
# Hence, we're going to assume the one that is passed to sign is
|
@@ -189,7 +189,7 @@ module Mixlib
|
|
189
189
|
# ====Parameters
|
190
190
|
#
|
191
191
|
#
|
192
|
-
def canonicalize_request(sign_algorithm=algorithm, sign_version=proto_version)
|
192
|
+
def canonicalize_request(sign_algorithm = algorithm, sign_version = proto_version)
|
193
193
|
digest = validate_sign_version_digest!(sign_algorithm, sign_version)
|
194
194
|
canonical_x_ops_user_id = canonicalize_user_id(user_id, sign_version, digest)
|
195
195
|
case sign_version
|
@@ -209,12 +209,12 @@ module Mixlib
|
|
209
209
|
"Hashed Path:#{digester.hash_string(canonical_path, digest)}",
|
210
210
|
"X-Ops-Content-Hash:#{hashed_body(digest)}",
|
211
211
|
"X-Ops-Timestamp:#{canonical_time}",
|
212
|
-
"X-Ops-UserId:#{canonical_x_ops_user_id}"
|
212
|
+
"X-Ops-UserId:#{canonical_x_ops_user_id}",
|
213
213
|
].join("\n")
|
214
214
|
end
|
215
215
|
end
|
216
216
|
|
217
|
-
def canonicalize_user_id(user_id, proto_version, digest=OpenSSL::Digest::SHA1)
|
217
|
+
def canonicalize_user_id(user_id, proto_version, digest = OpenSSL::Digest::SHA1)
|
218
218
|
case proto_version
|
219
219
|
when "1.1"
|
220
220
|
# and 1.2 if that ever gets implemented
|
@@ -230,7 +230,7 @@ module Mixlib
|
|
230
230
|
# ====Parameters
|
231
231
|
#
|
232
232
|
def parse_signing_description
|
233
|
-
parts = signing_description.strip.split(";").inject({
|
233
|
+
parts = signing_description.strip.split(";").inject({}) do |memo, part|
|
234
234
|
field_name, field_value = part.split("=")
|
235
235
|
memo[field_name.to_sym] = field_value.strip
|
236
236
|
memo
|
@@ -248,7 +248,7 @@ module Mixlib
|
|
248
248
|
string_to_sign = canonicalize_request(sign_algorithm, sign_version)
|
249
249
|
Mixlib::Authentication::Log.debug "String to sign: '#{string_to_sign}'"
|
250
250
|
case sign_version
|
251
|
-
when
|
251
|
+
when "1.3"
|
252
252
|
private_key.sign(digest.new, string_to_sign)
|
253
253
|
else
|
254
254
|
private_key.private_encrypt(string_to_sign)
|
@@ -269,12 +269,12 @@ module Mixlib
|
|
269
269
|
include SignedHeaderAuth
|
270
270
|
|
271
271
|
def proto_version
|
272
|
-
(self[:proto_version]
|
272
|
+
(self[:proto_version] || DEFAULT_PROTO_VERSION).to_s
|
273
273
|
end
|
274
274
|
|
275
275
|
def server_api_version
|
276
276
|
key = (self[:headers] || {}).keys.select do |k|
|
277
|
-
k.downcase ==
|
277
|
+
k.downcase == "x-ops-server-api-version"
|
278
278
|
end.first
|
279
279
|
if key
|
280
280
|
self[:headers][key]
|