mixlib-authentication 1.4.0 → 1.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 +27 -15
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
|
+
[![Build Status Master](https://travis-ci.org/chef/mixlib-authentication.svg?branch=master)](https://travis-ci.org/chef/mixlib-authentication) [![Gem Version](https://badge.fury.io/rb/mixlib-authentication.svg)](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]
|