mixlib-authentication 2.1.1 → 3.0.10

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.
data/Rakefile DELETED
@@ -1,18 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
- task :default => :spec
7
-
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"]
13
- end
14
- rescue LoadError
15
- puts "chefstyle/rubocop is not available."
16
- end
17
-
18
- task :ci => [:style, :spec]
@@ -1,22 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__) + "/lib")
2
- require "mixlib/authentication/version"
3
-
4
- Gem::Specification.new do |s|
5
- s.name = "mixlib-authentication"
6
- s.version = Mixlib::Authentication::VERSION
7
- s.platform = Gem::Platform::RUBY
8
- s.summary = "Mixes in simple per-request authentication"
9
- s.description = s.summary
10
- s.license = "Apache-2.0"
11
- s.author = "Chef Software, Inc."
12
- s.email = "info@chef.io"
13
- s.homepage = "https://www.chef.io"
14
-
15
- s.require_path = "lib"
16
- s.files = %w{LICENSE README.md Gemfile Rakefile NOTICE} + Dir.glob("*.gemspec") +
17
- Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
18
-
19
- %w{rspec-core rspec-expectations rspec-mocks}.each { |gem| s.add_development_dependency gem, "~> 3.2" }
20
- s.add_development_dependency "chefstyle"
21
- s.add_development_dependency "rake", "~> 11"
22
- end
@@ -1,24 +0,0 @@
1
- require "mixlib/authentication/digester"
2
-
3
- describe Mixlib::Authentication::Digester do
4
- context "backcompat" do
5
- # The digester API should really have been private,
6
- # however oc-chef-pedant uses it.
7
- let(:test_string) { "hello" }
8
- let(:test_string_checksum) { "qvTGHdzF6KLavt4PO0gs2a6pQ00=" }
9
-
10
- describe "#hash_file" do
11
- it "should default to use SHA1" do
12
- expect(described_class.hash_file(StringIO.new(test_string))).to(
13
- eq(test_string_checksum))
14
- end
15
- end
16
-
17
- describe "#hash_string" do
18
- it "should default to use SHA1" do
19
- expect(described_class.hash_string(test_string)).to(
20
- eq(test_string_checksum))
21
- end
22
- end
23
- end
24
- end
@@ -1,132 +0,0 @@
1
- # Author:: Daniel DeLeo (<dan@opscode.com>)
2
- # Copyright:: Copyright (c) 2010 Opscode, Inc.
3
- # License:: Apache License, Version 2.0
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
- require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
19
-
20
- require "mixlib/authentication"
21
- require "mixlib/authentication/http_authentication_request"
22
- require "ostruct"
23
- require "pp"
24
-
25
- describe Mixlib::Authentication::HTTPAuthenticationRequest do
26
- before do
27
- request = Struct.new(:env, :method, :path)
28
-
29
- @timestamp_iso8601 = "2009-01-01T12:00:00Z"
30
- @x_ops_content_hash = "DFteJZPVv6WKdQmMqZUQUumUyRs="
31
- @user_id = "spec-user"
32
- @http_x_ops_lines = [
33
- "jVHrNniWzpbez/eGWjFnO6lINRIuKOg40ZTIQudcFe47Z9e/HvrszfVXlKG4",
34
- "NMzYZgyooSvU85qkIUmKuCqgG2AIlvYa2Q/2ctrMhoaHhLOCWWoqYNMaEqPc",
35
- "3tKHE+CfvP+WuPdWk4jv4wpIkAz6ZLxToxcGhXmZbXpk56YTmqgBW2cbbw4O",
36
- "IWPZDHSiPcw//AYNgW1CCDptt+UFuaFYbtqZegcBd2n/jzcWODA7zL4KWEUy",
37
- "9q4rlh/+1tBReg60QdsmDRsw/cdO1GZrKtuCwbuD4+nbRdVBKv72rqHX9cu0",
38
- "utju9jzczCyB+sSAQWrxSsXB/b8vV2qs0l4VD2ML+w=="]
39
- @merb_headers = {
40
- # These are used by signatureverification. An arbitrary sampling of non-HTTP_*
41
- # headers are in here to exercise that code path.
42
- "HTTP_HOST" => "127.0.0.1",
43
- "HTTP_X_OPS_SIGN" => "version=1.0",
44
- "HTTP_X_OPS_REQUESTID" => "127.0.0.1 1258566194.85386",
45
- "HTTP_X_OPS_TIMESTAMP" => @timestamp_iso8601,
46
- "HTTP_X_OPS_CONTENT_HASH" => @x_ops_content_hash,
47
- "HTTP_X_OPS_USERID" => @user_id,
48
- "HTTP_X_OPS_AUTHORIZATION_1" => @http_x_ops_lines[0],
49
- "HTTP_X_OPS_AUTHORIZATION_2" => @http_x_ops_lines[1],
50
- "HTTP_X_OPS_AUTHORIZATION_3" => @http_x_ops_lines[2],
51
- "HTTP_X_OPS_AUTHORIZATION_4" => @http_x_ops_lines[3],
52
- "HTTP_X_OPS_AUTHORIZATION_5" => @http_x_ops_lines[4],
53
- "HTTP_X_OPS_AUTHORIZATION_6" => @http_x_ops_lines[5],
54
-
55
- # Random sampling
56
- "REMOTE_ADDR" => "127.0.0.1",
57
- "PATH_INFO" => "/organizations/local-test-org/cookbooks",
58
- "REQUEST_PATH" => "/organizations/local-test-org/cookbooks",
59
- "CONTENT_TYPE" => "multipart/form-data; boundary=----RubyMultipartClient6792ZZZZZ",
60
- "CONTENT_LENGTH" => "394",
61
- }
62
- @request = request.new(@merb_headers, "POST", "/nodes")
63
- @http_authentication_request = Mixlib::Authentication::HTTPAuthenticationRequest.new(@request)
64
- end
65
-
66
- it "normalizes the headers to lowercase symbols" do
67
- expected = { :host => "127.0.0.1",
68
- :x_ops_sign => "version=1.0",
69
- :x_ops_requestid => "127.0.0.1 1258566194.85386",
70
- :x_ops_timestamp => "2009-01-01T12:00:00Z",
71
- :x_ops_content_hash => "DFteJZPVv6WKdQmMqZUQUumUyRs=",
72
- :x_ops_userid => "spec-user",
73
- :x_ops_authorization_1 => "jVHrNniWzpbez/eGWjFnO6lINRIuKOg40ZTIQudcFe47Z9e/HvrszfVXlKG4",
74
- :x_ops_authorization_2 => "NMzYZgyooSvU85qkIUmKuCqgG2AIlvYa2Q/2ctrMhoaHhLOCWWoqYNMaEqPc",
75
- :x_ops_authorization_3 => "3tKHE+CfvP+WuPdWk4jv4wpIkAz6ZLxToxcGhXmZbXpk56YTmqgBW2cbbw4O",
76
- :x_ops_authorization_4 => "IWPZDHSiPcw//AYNgW1CCDptt+UFuaFYbtqZegcBd2n/jzcWODA7zL4KWEUy",
77
- :x_ops_authorization_5 => "9q4rlh/+1tBReg60QdsmDRsw/cdO1GZrKtuCwbuD4+nbRdVBKv72rqHX9cu0",
78
- :x_ops_authorization_6 => "utju9jzczCyB+sSAQWrxSsXB/b8vV2qs0l4VD2ML+w==" }
79
- expect(@http_authentication_request.headers).to eq(expected)
80
- end
81
-
82
- it "raises an error when not all required headers are given" do
83
- @merb_headers.delete("HTTP_X_OPS_SIGN")
84
- exception = Mixlib::Authentication::MissingAuthenticationHeader
85
- expect { Mixlib::Authentication::HTTPAuthenticationRequest.new(@request) }.to raise_error(exception)
86
- end
87
-
88
- it "extracts the path from the request" do
89
- expect(@http_authentication_request.path).to eq("/nodes")
90
- end
91
-
92
- it "extracts the request method from the request" do
93
- expect(@http_authentication_request.http_method).to eq("POST")
94
- end
95
-
96
- it "extracts the signing description from the request headers" do
97
- expect(@http_authentication_request.signing_description).to eq("version=1.0")
98
- end
99
-
100
- it "extracts the user_id from the request headers" do
101
- expect(@http_authentication_request.user_id).to eq("spec-user")
102
- end
103
-
104
- it "extracts the timestamp from the request headers" do
105
- expect(@http_authentication_request.timestamp).to eq("2009-01-01T12:00:00Z")
106
- end
107
-
108
- it "extracts the host from the request headers" do
109
- expect(@http_authentication_request.host).to eq("127.0.0.1")
110
- end
111
-
112
- it "extracts the content hash from the request headers" do
113
- expect(@http_authentication_request.content_hash).to eq("DFteJZPVv6WKdQmMqZUQUumUyRs=")
114
- end
115
-
116
- it "rebuilds the request signature from the headers" do
117
- expected = <<-SIG
118
- jVHrNniWzpbez/eGWjFnO6lINRIuKOg40ZTIQudcFe47Z9e/HvrszfVXlKG4
119
- NMzYZgyooSvU85qkIUmKuCqgG2AIlvYa2Q/2ctrMhoaHhLOCWWoqYNMaEqPc
120
- 3tKHE+CfvP+WuPdWk4jv4wpIkAz6ZLxToxcGhXmZbXpk56YTmqgBW2cbbw4O
121
- IWPZDHSiPcw//AYNgW1CCDptt+UFuaFYbtqZegcBd2n/jzcWODA7zL4KWEUy
122
- 9q4rlh/+1tBReg60QdsmDRsw/cdO1GZrKtuCwbuD4+nbRdVBKv72rqHX9cu0
123
- utju9jzczCyB+sSAQWrxSsXB/b8vV2qs0l4VD2ML+w==
124
- SIG
125
- expect(@http_authentication_request.request_signature).to eq(expected.chomp)
126
- end
127
-
128
- it "defaults to server api version 0" do
129
- expect(@http_authentication_request.server_api_version).to eq("0")
130
- end
131
-
132
- end
@@ -1,623 +0,0 @@
1
- #
2
- # Author:: Tim Hinderliter (<tim@opscode.com>)
3
- # Author:: Christopher Walters (<cw@opscode.com>)
4
- # Author:: Christopher Brown (<cb@opscode.com>)
5
- # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
6
- # License:: Apache License, Version 2.0
7
- #
8
- # Licensed under the Apache License, Version 2.0 (the "License");
9
- # you may not use this file except in compliance with the License.
10
- # You may obtain a copy of the License at
11
- #
12
- # http://www.apache.org/licenses/LICENSE-2.0
13
- #
14
- # Unless required by applicable law or agreed to in writing, software
15
- # distributed under the License is distributed on an "AS IS" BASIS,
16
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
- # See the License for the specific language governing permissions and
18
- # limitations under the License.
19
- #
20
-
21
- require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
22
- require "rubygems"
23
-
24
- require "ostruct"
25
- require "openssl"
26
- require "mixlib/authentication/signatureverification"
27
- require "time"
28
- require "net/ssh"
29
-
30
- # TODO: should make these regular spec-based mock objects.
31
- class MockRequest
32
- attr_accessor :env, :params, :path, :raw_post
33
-
34
- def initialize(path, params, headers, raw_post)
35
- @path = path
36
- @params = params
37
- @env = headers
38
- @raw_post = raw_post
39
- end
40
-
41
- def method
42
- "POST"
43
- end
44
- end
45
-
46
- class MockFile
47
- def initialize
48
- @have_read = nil
49
- end
50
-
51
- def self.length
52
- BODY.length
53
- end
54
-
55
- def read(len, out_str)
56
- if @have_read.nil?
57
- @have_read = 1
58
- out_str[0..-1] = BODY
59
- BODY
60
- else
61
- nil
62
- end
63
- end
64
- end
65
-
66
- # Uncomment this to get some more info from the methods we're testing.
67
- #Mixlib::Authentication.logger.level = :trace
68
-
69
- describe "Mixlib::Authentication::SignedHeaderAuth" do
70
-
71
- # NOTE: Version 1.0 will be the default until Chef 11 is released.
72
-
73
- it "should generate the correct string to sign and signature, version 1.0 (default)" do
74
-
75
- expect(V1_0_SIGNING_OBJECT.canonicalize_request).to eq(V1_0_CANONICAL_REQUEST)
76
-
77
- # If you need to regenerate the constants in this test spec, print out
78
- # the results of res.inspect and copy them as appropriate into the
79
- # the constants in this file.
80
- expect(V1_0_SIGNING_OBJECT.sign(PRIVATE_KEY)).to eq(EXPECTED_SIGN_RESULT_V1_0)
81
- end
82
-
83
- it "should generate the correct string to sign and signature, version 1.1" do
84
- expect(V1_1_SIGNING_OBJECT.proto_version).to eq("1.1")
85
- expect(V1_1_SIGNING_OBJECT.canonicalize_request).to eq(V1_1_CANONICAL_REQUEST)
86
-
87
- # If you need to regenerate the constants in this test spec, print out
88
- # the results of res.inspect and copy them as appropriate into the
89
- # the constants in this file.
90
- expect(V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY)).to eq(EXPECTED_SIGN_RESULT_V1_1)
91
- end
92
-
93
- it "should generate the correct string to sign and signature for version 1.3 with SHA256" do
94
- expect(V1_3_SHA256_SIGNING_OBJECT.proto_version).to eq("1.3")
95
- expect(V1_3_SHA256_SIGNING_OBJECT.algorithm).to eq("sha256")
96
- expect(V1_3_SHA256_SIGNING_OBJECT.server_api_version).to eq("1")
97
- expect(V1_3_SHA256_SIGNING_OBJECT.canonicalize_request).to eq(V1_3_SHA256_CANONICAL_REQUEST)
98
-
99
- # If you need to regenerate the constants in this test spec, print out
100
- # the results of res.inspect and copy them as appropriate into the
101
- # the constants in this file.
102
- expect(V1_3_SHA256_SIGNING_OBJECT.sign(PRIVATE_KEY)).to eq(EXPECTED_SIGN_RESULT_V1_3_SHA256)
103
- end
104
-
105
- it "should generate the correct string to sign and signature for version 1.3 with SHA256 via ssh-agent" do
106
- agent = double("ssh-agent")
107
- expect(Net::SSH::Authentication::Agent).to receive(:connect).and_return(agent)
108
- expect(agent).to receive(:sign).and_return(SSH_AGENT_RESPONSE)
109
- expect(V1_3_SHA256_SIGNING_OBJECT.sign(PUBLIC_KEY, use_ssh_agent: true)).to eq(EXPECTED_SIGN_RESULT_V1_3_SHA256)
110
- end
111
-
112
- it "should generate the correct string to sign and signature for non-default proto version when used as a mixin" do
113
- algorithm = "sha1"
114
- version = "1.1"
115
-
116
- V1_1_SIGNING_OBJECT.proto_version = "1.0"
117
- expect(V1_1_SIGNING_OBJECT.proto_version).to eq("1.0")
118
- expect(V1_1_SIGNING_OBJECT.canonicalize_request(algorithm, version)).to eq(V1_1_CANONICAL_REQUEST)
119
-
120
- # If you need to regenerate the constants in this test spec, print out
121
- # the results of res.inspect and copy them as appropriate into the
122
- # the constants in this file.
123
- expect(V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, algorithm, version)).to eq(EXPECTED_SIGN_RESULT_V1_1)
124
- expect(V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, sign_algorithm: algorithm, sign_version: version)).to eq(EXPECTED_SIGN_RESULT_V1_1)
125
- end
126
-
127
- it "should not choke when signing a request for a long user id with version 1.1" do
128
- expect { LONG_SIGNING_OBJECT.sign(PRIVATE_KEY, "sha1", "1.1") }.not_to raise_error
129
- expect { LONG_SIGNING_OBJECT.sign(PRIVATE_KEY, sign_algorithm: "sha1", sign_version: "1.1") }.not_to raise_error
130
- end
131
-
132
- it "should choke when signing a request for a long user id with version 1.0" do
133
- expect { LONG_SIGNING_OBJECT.sign(PRIVATE_KEY, "sha1", "1.0") }.to raise_error(OpenSSL::PKey::RSAError)
134
- expect { LONG_SIGNING_OBJECT.sign(PRIVATE_KEY, sign_algorithm: "sha1", sign_version: "1.0") }.to raise_error(OpenSSL::PKey::RSAError)
135
- end
136
-
137
- it "should choke when signing a request with a bad version" do
138
- expect { V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, "sha1", "poo") }.to raise_error(Mixlib::Authentication::AuthenticationError)
139
- end
140
-
141
- it "should choke when signing a request with a bad algorithm" do
142
- expect { V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, "sha_poo", "1.1") }.to raise_error(Mixlib::Authentication::AuthenticationError)
143
- end
144
-
145
- it "should choke when signing a request via ssh-agent and ssh-agent is not reachable with version 1.3" do
146
- expect(Net::SSH::Authentication::Agent).to receive(:connect).and_raise(Net::SSH::Authentication::AgentNotAvailable)
147
- expect { V1_3_SHA256_SIGNING_OBJECT.sign(PUBLIC_KEY, use_ssh_agent: true) }.to raise_error(Mixlib::Authentication::AuthenticationError)
148
- end
149
-
150
- it "should choke when signing a request via ssh-agent and the key is not loaded with version 1.3" do
151
- agent = double("ssh-agent")
152
- expect(Net::SSH::Authentication::Agent).to receive(:connect).and_return(agent)
153
- expect(agent).to receive(:sign).and_raise(Net::SSH::Authentication::AgentError)
154
- expect { V1_3_SHA256_SIGNING_OBJECT.sign(PUBLIC_KEY, use_ssh_agent: true) }.to raise_error(Mixlib::Authentication::AuthenticationError)
155
- end
156
-
157
- end
158
-
159
- describe "Mixlib::Authentication::SignatureVerification" do
160
-
161
- before(:each) do
162
- @user_private_key = PRIVATE_KEY
163
- end
164
-
165
- it "should authenticate a File-containing request V1.1 - Merb" do
166
- request_params = MERB_REQUEST_PARAMS.clone
167
- request_params["file"] =
168
- { "size" => MockFile.length, "content_type" => "application/octet-stream", "filename" => "zsh.tar.gz", "tempfile" => MockFile.new }
169
-
170
- mock_request = MockRequest.new(PATH, request_params, MERB_HEADERS_V1_1, "")
171
- expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
172
-
173
- service = Mixlib::Authentication::SignatureVerification.new
174
- res = service.authenticate_user_request(mock_request, @user_private_key)
175
- expect(res).not_to be_nil
176
- end
177
-
178
- it "should authenticate a File-containing request V1.3 SHA256 - Merb" do
179
- request_params = MERB_REQUEST_PARAMS.clone
180
- request_params["file"] =
181
- { "size" => MockFile.length, "content_type" => "application/octet-stream", "filename" => "zsh.tar.gz", "tempfile" => MockFile.new }
182
-
183
- mock_request = MockRequest.new(PATH, request_params, MERB_HEADERS_V1_3_SHA256, "")
184
- expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
185
-
186
- service = Mixlib::Authentication::SignatureVerification.new
187
- res = service.authenticate_user_request(mock_request, @user_private_key)
188
- expect(res).not_to be_nil
189
- end
190
-
191
- it "should authenticate a File-containing request from a v1.0 client - Passenger" do
192
- request_params = PASSENGER_REQUEST_PARAMS.clone
193
- request_params["tarball"] = MockFile.new
194
-
195
- mock_request = MockRequest.new(PATH, request_params, PASSENGER_HEADERS_V1_0, "")
196
- expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
197
-
198
- auth_req = Mixlib::Authentication::SignatureVerification.new
199
- res = auth_req.authenticate_user_request(mock_request, @user_private_key)
200
- expect(res).not_to be_nil
201
- end
202
-
203
- it "should authenticate a normal (post body) request v1.3 SHA256 - Merb" do
204
- mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, MERB_HEADERS_V1_3_SHA256, BODY)
205
- expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
206
-
207
- service = Mixlib::Authentication::SignatureVerification.new
208
- res = service.authenticate_user_request(mock_request, @user_private_key)
209
- expect(res).not_to be_nil
210
- end
211
-
212
- it "should authenticate a normal (post body) request v1.1 - Merb" do
213
- mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, MERB_HEADERS_V1_1, BODY)
214
- expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
215
-
216
- service = Mixlib::Authentication::SignatureVerification.new
217
- res = service.authenticate_user_request(mock_request, @user_private_key)
218
- expect(res).not_to be_nil
219
- end
220
-
221
- it "should authenticate a normal (post body) request from a v1.0 client - Merb" do
222
- mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, MERB_HEADERS_V1_0, BODY)
223
- expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
224
-
225
- service = Mixlib::Authentication::SignatureVerification.new
226
- res = service.authenticate_user_request(mock_request, @user_private_key)
227
- expect(res).not_to be_nil
228
- end
229
-
230
- it "shouldn't authenticate if an Authorization header is missing" do
231
- headers = MERB_HEADERS_V1_1.clone
232
- headers.delete("HTTP_X_OPS_SIGN")
233
-
234
- mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, headers, BODY)
235
- allow(Time).to receive(:now).and_return(TIMESTAMP_OBJ)
236
- #Time.stub!(:now).and_return(TIMESTAMP_OBJ)
237
-
238
- auth_req = Mixlib::Authentication::SignatureVerification.new
239
- expect { auth_req.authenticate_user_request(mock_request, @user_private_key) }.to raise_error(Mixlib::Authentication::AuthenticationError)
240
-
241
- expect(auth_req).not_to be_a_valid_request
242
- expect(auth_req).not_to be_a_valid_timestamp
243
- expect(auth_req).not_to be_a_valid_signature
244
- expect(auth_req).not_to be_a_valid_content_hash
245
- end
246
-
247
- it "shouldn't authenticate if Authorization header is wrong" do
248
- headers = MERB_HEADERS_V1_1.clone
249
- headers["HTTP_X_OPS_CONTENT_HASH"] += "_"
250
-
251
- mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, headers, BODY)
252
- expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
253
-
254
- auth_req = Mixlib::Authentication::SignatureVerification.new
255
- res = auth_req.authenticate_user_request(mock_request, @user_private_key)
256
- expect(res).to be_nil
257
-
258
- expect(auth_req).not_to be_a_valid_request
259
- expect(auth_req).to be_a_valid_timestamp
260
- expect(auth_req).to be_a_valid_signature
261
- expect(auth_req).not_to be_a_valid_content_hash
262
- end
263
-
264
- it "shouldn't authenticate if the timestamp is not within bounds" do
265
- mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, MERB_HEADERS_V1_1, BODY)
266
- expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ - 1000)
267
-
268
- auth_req = Mixlib::Authentication::SignatureVerification.new
269
- res = auth_req.authenticate_user_request(mock_request, @user_private_key)
270
- expect(res).to be_nil
271
- expect(auth_req).not_to be_a_valid_request
272
- expect(auth_req).not_to be_a_valid_timestamp
273
- expect(auth_req).to be_a_valid_signature
274
- expect(auth_req).to be_a_valid_content_hash
275
- end
276
-
277
- it "shouldn't authenticate if the signature is wrong" do
278
- headers = MERB_HEADERS_V1_1.dup
279
- headers["HTTP_X_OPS_AUTHORIZATION_1"] = "epicfail"
280
- mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, headers, BODY)
281
- expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
282
-
283
- auth_req = Mixlib::Authentication::SignatureVerification.new
284
- res = auth_req.authenticate_user_request(mock_request, @user_private_key)
285
- expect(res).to be_nil
286
- expect(auth_req).not_to be_a_valid_request
287
- expect(auth_req).not_to be_a_valid_signature
288
- expect(auth_req).to be_a_valid_timestamp
289
- expect(auth_req).to be_a_valid_content_hash
290
- end
291
-
292
- it "shouldn't authenticate if the signature is wrong for v1.3 SHA256" do
293
- headers = MERB_HEADERS_V1_3_SHA256.dup
294
- headers["HTTP_X_OPS_AUTHORIZATION_1"] = "epicfail"
295
- mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, headers, BODY)
296
- expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
297
-
298
- auth_req = Mixlib::Authentication::SignatureVerification.new
299
- res = auth_req.authenticate_user_request(mock_request, @user_private_key)
300
- expect(res).to be_nil
301
- expect(auth_req).not_to be_a_valid_request
302
- expect(auth_req).not_to be_a_valid_signature
303
- expect(auth_req).to be_a_valid_timestamp
304
- expect(auth_req).to be_a_valid_content_hash
305
- end
306
- end
307
-
308
- USER_ID = "spec-user"
309
- DIGESTED_USER_ID = Base64.encode64(Digest::SHA1.new.digest(USER_ID)).chomp
310
- BODY = "Spec Body"
311
- HASHED_BODY = "DFteJZPVv6WKdQmMqZUQUumUyRs=" # Base64.encode64(Digest::SHA1.digest("Spec Body")).chomp
312
- HASHED_BODY_SHA256 = "hDlKNZhIhgso3Fs0S0pZwJ0xyBWtR1RBaeHs1DrzOho="
313
- TIMESTAMP_ISO8601 = "2009-01-01T12:00:00Z"
314
- TIMESTAMP_OBJ = Time.parse("Thu Jan 01 12:00:00 -0000 2009")
315
- PATH = "/organizations/clownco"
316
- HASHED_CANONICAL_PATH = "YtBWDn1blGGuFIuKksdwXzHU9oE=" # Base64.encode64(Digest::SHA1.digest("/organizations/clownco")).chomp
317
-
318
- V1_0_ARGS = {
319
- :body => BODY,
320
- :user_id => USER_ID,
321
- :http_method => :post,
322
- :timestamp => TIMESTAMP_ISO8601, # fixed timestamp so we get back the same answer each time.
323
- :file => MockFile.new,
324
- :path => PATH,
325
- }
326
-
327
- V1_1_ARGS = {
328
- :body => BODY,
329
- :user_id => USER_ID,
330
- :http_method => :post,
331
- :timestamp => TIMESTAMP_ISO8601, # fixed timestamp so we get back the same answer each time.
332
- :file => MockFile.new,
333
- :path => PATH,
334
- :proto_version => 1.1,
335
- }
336
-
337
- V1_3_ARGS_SHA256 = {
338
- :body => BODY,
339
- :user_id => USER_ID,
340
- :http_method => :post,
341
- :timestamp => TIMESTAMP_ISO8601, # fixed timestamp so we get back the same answer each time.
342
- :file => MockFile.new,
343
- :path => PATH,
344
- :proto_version => "1.3",
345
- :headers => {
346
- "X-OpS-SeRvEr-ApI-VerSiOn" => "1",
347
- }
348
- # This defaults to sha256
349
- }
350
-
351
- LONG_PATH_LONG_USER_ARGS = {
352
- :body => BODY,
353
- :user_id => "A" * 200,
354
- :http_method => :put,
355
- :timestamp => TIMESTAMP_ISO8601, # fixed timestamp so we get back the same answer each time.
356
- :file => MockFile.new,
357
- :path => PATH + "/nodes/#{"A" * 250}",
358
- }
359
-
360
- REQUESTING_ACTOR_ID = "c0f8a68c52bffa1020222a56b23cccfa"
361
-
362
- # Content hash is ???TODO
363
- X_OPS_CONTENT_HASH = "DFteJZPVv6WKdQmMqZUQUumUyRs="
364
- X_OPS_CONTENT_HASH_SHA256 = "hDlKNZhIhgso3Fs0S0pZwJ0xyBWtR1RBaeHs1DrzOho="
365
-
366
- X_OPS_AUTHORIZATION_LINES_V1_0 = [
367
- "jVHrNniWzpbez/eGWjFnO6lINRIuKOg40ZTIQudcFe47Z9e/HvrszfVXlKG4",
368
- "NMzYZgyooSvU85qkIUmKuCqgG2AIlvYa2Q/2ctrMhoaHhLOCWWoqYNMaEqPc",
369
- "3tKHE+CfvP+WuPdWk4jv4wpIkAz6ZLxToxcGhXmZbXpk56YTmqgBW2cbbw4O",
370
- "IWPZDHSiPcw//AYNgW1CCDptt+UFuaFYbtqZegcBd2n/jzcWODA7zL4KWEUy",
371
- "9q4rlh/+1tBReg60QdsmDRsw/cdO1GZrKtuCwbuD4+nbRdVBKv72rqHX9cu0",
372
- "utju9jzczCyB+sSAQWrxSsXB/b8vV2qs0l4VD2ML+w==",
373
- ]
374
-
375
- X_OPS_AUTHORIZATION_LINES = [
376
- "UfZD9dRz6rFu6LbP5Mo1oNHcWYxpNIcUfFCffJS1FQa0GtfU/vkt3/O5HuCM",
377
- "1wIFl/U0f5faH9EWpXWY5NwKR031Myxcabw4t4ZLO69CIh/3qx1XnjcZvt2w",
378
- "c2R9bx/43IWA/r8w8Q6decuu0f6ZlNheJeJhaYPI8piX/aH+uHBH8zTACZu8",
379
- "vMnl5MF3/OIlsZc8cemq6eKYstp8a8KYq9OmkB5IXIX6qVMJHA6fRvQEB/7j",
380
- "281Q7oI/O+lE8AmVyBbwruPb7Mp6s4839eYiOdjbDwFjYtbS3XgAjrHlaD7W",
381
- "FDlbAG7H8Dmvo+wBxmtNkszhzbBnEYtuwQqT8nM/8A==",
382
- ]
383
-
384
- X_OPS_AUTHORIZATION_LINES_V1_3_SHA256 = [
385
- "FZOmXAyOBAZQV/uw188iBljBJXOm+m8xQ/8KTGLkgGwZNcRFxk1m953XjE3W",
386
- "VGy1dFT76KeaNWmPCNtDmprfH2na5UZFtfLIKrPv7xm80V+lzEzTd9WBwsfP",
387
- "42dZ9N+V9I5SVfcL/lWrrlpdybfceJC5jOcP5tzfJXWUITwb6Z3Erg3DU3Uh",
388
- "H9h9E0qWlYGqmiNCVrBnpe6Si1gU/Jl+rXlRSNbLJ4GlArAPuL976iTYJTzE",
389
- "MmbLUIm3JRYi00Yb01IUCCKdI90vUq1HHNtlTEu93YZfQaJwRxXlGkCNwIJe",
390
- "fy49QzaCIEu1XiOx5Jn+4GmkrZch/RrK9VzQWXgs+w==",
391
- ]
392
-
393
- SSH_AGENT_RESPONSE = "\x00\x00\x00\frsa-sha2-256\x00\x00\x01\x00\x15\x93\xA6\\\f\x8E\x04\x06PW\xFB\xB0\xD7\xCF\"\x06X\xC1%s\xA6\xFAo1C\xFF\nLb\xE4\x80l\x195\xC4E\xC6Mf\xF7\x9D\xD7\x8CM\xD6Tl\xB5tT\xFB\xE8\xA7\x9A5i\x8F\b\xDBC\x9A\x9A\xDF\x1Fi\xDA\xE5FE\xB5\xF2\xC8*\xB3\xEF\xEF\x19\xBC\xD1_\xA5\xCCL\xD3w\xD5\x81\xC2\xC7\xCF\xE3gY\xF4\xDF\x95\xF4\x8ERU\xF7\v\xFEU\xAB\xAEZ]\xC9\xB7\xDCx\x90\xB9\x8C\xE7\x0F\xE6\xDC\xDF%u\x94!<\e\xE9\x9D\xC4\xAE\r\xC3Su!\x1F\xD8}\x13J\x96\x95\x81\xAA\x9A#BV\xB0g\xA5\xEE\x92\x8BX\x14\xFC\x99~\xADyQH\xD6\xCB'\x81\xA5\x02\xB0\x0F\xB8\xBF{\xEA$\xD8%<\xC42f\xCBP\x89\xB7%\x16\"\xD3F\e\xD3R\x14\b\"\x9D#\xDD/R\xADG\x1C\xDBeLK\xBD\xDD\x86_A\xA2pG\x15\xE5\x1A@\x8D\xC0\x82^\x7F.=C6\x82 K\xB5^#\xB1\xE4\x99\xFE\xE0i\xA4\xAD\x97!\xFD\x1A\xCA\xF5\\\xD0Yx,\xFB"
394
- # We expect Mixlib::Authentication::SignedHeaderAuth#sign to return this
395
- # if passed the BODY above, based on version
396
-
397
- EXPECTED_SIGN_RESULT_V1_0 = {
398
- "X-Ops-Content-Hash" => X_OPS_CONTENT_HASH,
399
- "X-Ops-Userid" => USER_ID,
400
- "X-Ops-Sign" => "algorithm=sha1;version=1.0;",
401
- "X-Ops-Authorization-1" => X_OPS_AUTHORIZATION_LINES_V1_0[0],
402
- "X-Ops-Authorization-2" => X_OPS_AUTHORIZATION_LINES_V1_0[1],
403
- "X-Ops-Authorization-3" => X_OPS_AUTHORIZATION_LINES_V1_0[2],
404
- "X-Ops-Authorization-4" => X_OPS_AUTHORIZATION_LINES_V1_0[3],
405
- "X-Ops-Authorization-5" => X_OPS_AUTHORIZATION_LINES_V1_0[4],
406
- "X-Ops-Authorization-6" => X_OPS_AUTHORIZATION_LINES_V1_0[5],
407
- "X-Ops-Timestamp" => TIMESTAMP_ISO8601,
408
- }
409
-
410
- EXPECTED_SIGN_RESULT_V1_1 = {
411
- "X-Ops-Content-Hash" => X_OPS_CONTENT_HASH,
412
- "X-Ops-Userid" => USER_ID,
413
- "X-Ops-Sign" => "algorithm=sha1;version=1.1;",
414
- "X-Ops-Authorization-1" => X_OPS_AUTHORIZATION_LINES[0],
415
- "X-Ops-Authorization-2" => X_OPS_AUTHORIZATION_LINES[1],
416
- "X-Ops-Authorization-3" => X_OPS_AUTHORIZATION_LINES[2],
417
- "X-Ops-Authorization-4" => X_OPS_AUTHORIZATION_LINES[3],
418
- "X-Ops-Authorization-5" => X_OPS_AUTHORIZATION_LINES[4],
419
- "X-Ops-Authorization-6" => X_OPS_AUTHORIZATION_LINES[5],
420
- "X-Ops-Timestamp" => TIMESTAMP_ISO8601,
421
- }
422
-
423
- EXPECTED_SIGN_RESULT_V1_3_SHA256 = {
424
- "X-Ops-Content-Hash" => X_OPS_CONTENT_HASH_SHA256,
425
- "X-Ops-Userid" => USER_ID,
426
- "X-Ops-Sign" => "algorithm=sha256;version=1.3;",
427
- "X-Ops-Authorization-1" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[0],
428
- "X-Ops-Authorization-2" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[1],
429
- "X-Ops-Authorization-3" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[2],
430
- "X-Ops-Authorization-4" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[3],
431
- "X-Ops-Authorization-5" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[4],
432
- "X-Ops-Authorization-6" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[5],
433
- "X-Ops-Timestamp" => TIMESTAMP_ISO8601,
434
- }
435
-
436
- OTHER_HEADERS = {
437
- # An arbitrary sampling of non-HTTP_* headers are in here to
438
- # exercise that code path.
439
- "REMOTE_ADDR" => "127.0.0.1",
440
- "PATH_INFO" => "/organizations/local-test-org/cookbooks",
441
- "REQUEST_PATH" => "/organizations/local-test-org/cookbooks",
442
- "CONTENT_TYPE" => "multipart/form-data; boundary=----RubyMultipartClient6792ZZZZZ",
443
- "CONTENT_LENGTH" => "394",
444
- }
445
-
446
- # This is what will be in request.params for the Merb case.
447
- MERB_REQUEST_PARAMS = {
448
- "name" => "zsh", "action" => "create", "controller" => "chef_server_api/cookbooks",
449
- "organization_id" => "local-test-org", "requesting_actor_id" => REQUESTING_ACTOR_ID
450
- }
451
-
452
- MERB_HEADERS_V1_3_SHA256 = {
453
- # These are used by signatureverification.
454
- "HTTP_HOST" => "127.0.0.1",
455
- "HTTP_X_OPS_SIGN" => "algorithm=sha256;version=1.3;",
456
- "HTTP_X_OPS_REQUESTID" => "127.0.0.1 1258566194.85386",
457
- "HTTP_X_OPS_TIMESTAMP" => TIMESTAMP_ISO8601,
458
- "HTTP_X_OPS_CONTENT_HASH" => X_OPS_CONTENT_HASH_SHA256,
459
- "HTTP_X_OPS_USERID" => USER_ID,
460
- "HTTP_X_OPS_SERVER_API_VERSION" => "1",
461
- "HTTP_X_OPS_AUTHORIZATION_1" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[0],
462
- "HTTP_X_OPS_AUTHORIZATION_2" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[1],
463
- "HTTP_X_OPS_AUTHORIZATION_3" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[2],
464
- "HTTP_X_OPS_AUTHORIZATION_4" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[3],
465
- "HTTP_X_OPS_AUTHORIZATION_5" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[4],
466
- "HTTP_X_OPS_AUTHORIZATION_6" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[5],
467
- }.merge(OTHER_HEADERS)
468
-
469
- # Tis is what will be in request.env for the Merb case.
470
- MERB_HEADERS_V1_1 = {
471
- # These are used by signatureverification.
472
- "HTTP_HOST" => "127.0.0.1",
473
- "HTTP_X_OPS_SIGN" => "algorithm=sha1;version=1.1;",
474
- "HTTP_X_OPS_REQUESTID" => "127.0.0.1 1258566194.85386",
475
- "HTTP_X_OPS_TIMESTAMP" => TIMESTAMP_ISO8601,
476
- "HTTP_X_OPS_CONTENT_HASH" => X_OPS_CONTENT_HASH,
477
- "HTTP_X_OPS_USERID" => USER_ID,
478
- "HTTP_X_OPS_AUTHORIZATION_1" => X_OPS_AUTHORIZATION_LINES[0],
479
- "HTTP_X_OPS_AUTHORIZATION_2" => X_OPS_AUTHORIZATION_LINES[1],
480
- "HTTP_X_OPS_AUTHORIZATION_3" => X_OPS_AUTHORIZATION_LINES[2],
481
- "HTTP_X_OPS_AUTHORIZATION_4" => X_OPS_AUTHORIZATION_LINES[3],
482
- "HTTP_X_OPS_AUTHORIZATION_5" => X_OPS_AUTHORIZATION_LINES[4],
483
- "HTTP_X_OPS_AUTHORIZATION_6" => X_OPS_AUTHORIZATION_LINES[5],
484
- }.merge(OTHER_HEADERS)
485
-
486
- # Tis is what will be in request.env for the Merb case.
487
- MERB_HEADERS_V1_0 = {
488
- # These are used by signatureverification.
489
- "HTTP_HOST" => "127.0.0.1",
490
- "HTTP_X_OPS_SIGN" => "version=1.0",
491
- "HTTP_X_OPS_REQUESTID" => "127.0.0.1 1258566194.85386",
492
- "HTTP_X_OPS_TIMESTAMP" => TIMESTAMP_ISO8601,
493
- "HTTP_X_OPS_CONTENT_HASH" => X_OPS_CONTENT_HASH,
494
- "HTTP_X_OPS_USERID" => USER_ID,
495
- "HTTP_X_OPS_AUTHORIZATION_1" => X_OPS_AUTHORIZATION_LINES_V1_0[0],
496
- "HTTP_X_OPS_AUTHORIZATION_2" => X_OPS_AUTHORIZATION_LINES_V1_0[1],
497
- "HTTP_X_OPS_AUTHORIZATION_3" => X_OPS_AUTHORIZATION_LINES_V1_0[2],
498
- "HTTP_X_OPS_AUTHORIZATION_4" => X_OPS_AUTHORIZATION_LINES_V1_0[3],
499
- "HTTP_X_OPS_AUTHORIZATION_5" => X_OPS_AUTHORIZATION_LINES_V1_0[4],
500
- "HTTP_X_OPS_AUTHORIZATION_6" => X_OPS_AUTHORIZATION_LINES_V1_0[5],
501
- }.merge(OTHER_HEADERS)
502
-
503
- PASSENGER_REQUEST_PARAMS = {
504
- "action" => "create",
505
- #"tarball"=>#<File:/tmp/RackMultipart20091120-25570-mgq2sa-0>,
506
- "controller" => "api/v1/cookbooks",
507
- "cookbook" => "{\"category\":\"databases\"}",
508
- }
509
-
510
- PASSENGER_HEADERS_V1_1 = {
511
- # These are used by signatureverification.
512
- "HTTP_HOST" => "127.0.0.1",
513
- "HTTP_X_OPS_SIGN" => "algorithm=sha1;version=1.1;",
514
- "HTTP_X_OPS_REQUESTID" => "127.0.0.1 1258566194.85386",
515
- "HTTP_X_OPS_TIMESTAMP" => TIMESTAMP_ISO8601,
516
- "HTTP_X_OPS_CONTENT_HASH" => X_OPS_CONTENT_HASH,
517
- "HTTP_X_OPS_USERID" => USER_ID,
518
- "HTTP_X_OPS_AUTHORIZATION_1" => X_OPS_AUTHORIZATION_LINES[0],
519
- "HTTP_X_OPS_AUTHORIZATION_2" => X_OPS_AUTHORIZATION_LINES[1],
520
- "HTTP_X_OPS_AUTHORIZATION_3" => X_OPS_AUTHORIZATION_LINES[2],
521
- "HTTP_X_OPS_AUTHORIZATION_4" => X_OPS_AUTHORIZATION_LINES[3],
522
- "HTTP_X_OPS_AUTHORIZATION_5" => X_OPS_AUTHORIZATION_LINES[4],
523
- "HTTP_X_OPS_AUTHORIZATION_6" => X_OPS_AUTHORIZATION_LINES[5],
524
- }.merge(OTHER_HEADERS)
525
-
526
- PASSENGER_HEADERS_V1_0 = {
527
- # These are used by signatureverification.
528
- "HTTP_HOST" => "127.0.0.1",
529
- "HTTP_X_OPS_SIGN" => "version=1.0",
530
- "HTTP_X_OPS_REQUESTID" => "127.0.0.1 1258566194.85386",
531
- "HTTP_X_OPS_TIMESTAMP" => TIMESTAMP_ISO8601,
532
- "HTTP_X_OPS_CONTENT_HASH" => X_OPS_CONTENT_HASH,
533
- "HTTP_X_OPS_USERID" => USER_ID,
534
- "HTTP_X_OPS_AUTHORIZATION_1" => X_OPS_AUTHORIZATION_LINES_V1_0[0],
535
- "HTTP_X_OPS_AUTHORIZATION_2" => X_OPS_AUTHORIZATION_LINES_V1_0[1],
536
- "HTTP_X_OPS_AUTHORIZATION_3" => X_OPS_AUTHORIZATION_LINES_V1_0[2],
537
- "HTTP_X_OPS_AUTHORIZATION_4" => X_OPS_AUTHORIZATION_LINES_V1_0[3],
538
- "HTTP_X_OPS_AUTHORIZATION_5" => X_OPS_AUTHORIZATION_LINES_V1_0[4],
539
- "HTTP_X_OPS_AUTHORIZATION_6" => X_OPS_AUTHORIZATION_LINES_V1_0[5],
540
- }.merge(OTHER_HEADERS)
541
-
542
- # generated with
543
- # openssl genrsa -out private.pem 2048
544
- # openssl rsa -in private.pem -out public.pem -pubout
545
- PUBLIC_KEY_DATA = <<EOS
546
- -----BEGIN PUBLIC KEY-----
547
- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ueqo76MXuP6XqZBILFz
548
- iH/9AI7C6PaN5W0dSvkr9yInyGHSz/IR1+4tqvP2qlfKVKI4CP6BFH251Ft9qMUB
549
- uAsnlAVQ1z0exDtIFFOyQCdR7iXmjBIWMSS4buBwRQXwDK7id1OxtU23qVJv+xwE
550
- V0IzaaSJmaGLIbvRBD+qatfUuQJBMU/04DdJIwvLtZBYdC2219m5dUBQaa4bimL+
551
- YN9EcsDzD9h9UxQo5ReK7b3cNMzJBKJWLzFBcJuePMzAnLFktr/RufX4wpXe6XJx
552
- oVPaHo72GorLkwnQ0HYMTY8rehT4mDi1FI969LHCFFaFHSAaRnwdXaQkJmSfcxzC
553
- YQIDAQAB
554
- -----END PUBLIC KEY-----
555
- EOS
556
-
557
- PUBLIC_KEY = OpenSSL::PKey::RSA.new(PUBLIC_KEY_DATA)
558
-
559
- PRIVATE_KEY_DATA = <<EOS
560
- -----BEGIN RSA PRIVATE KEY-----
561
- MIIEpAIBAAKCAQEA0ueqo76MXuP6XqZBILFziH/9AI7C6PaN5W0dSvkr9yInyGHS
562
- z/IR1+4tqvP2qlfKVKI4CP6BFH251Ft9qMUBuAsnlAVQ1z0exDtIFFOyQCdR7iXm
563
- jBIWMSS4buBwRQXwDK7id1OxtU23qVJv+xwEV0IzaaSJmaGLIbvRBD+qatfUuQJB
564
- MU/04DdJIwvLtZBYdC2219m5dUBQaa4bimL+YN9EcsDzD9h9UxQo5ReK7b3cNMzJ
565
- BKJWLzFBcJuePMzAnLFktr/RufX4wpXe6XJxoVPaHo72GorLkwnQ0HYMTY8rehT4
566
- mDi1FI969LHCFFaFHSAaRnwdXaQkJmSfcxzCYQIDAQABAoIBAQCW3I4sKN5B9jOe
567
- xq/pkeWBq4OvhW8Ys1yW0zFT8t6nHbB1XrwscQygd8gE9BPqj3e0iIEqtdphbPmj
568
- VHqTYbC0FI6QDClifV7noTwTBjeIOlgZ0NSUN0/WgVzIOxUz2mZ2vBZUovKILPqG
569
- TOi7J7RXMoySMdcXpP1f+PgvYNcnKsT72UcWaSXEV8/zo+Zm/qdGPVWwJonri5Mp
570
- DVm5EQSENBiRyt028rU6ElXORNmoQpVjDVqZ1gipzXkifdjGyENw2rt4V/iKYD7V
571
- 5iqXOsvP6Cemf4gbrjunAgDG08S00kiUgvVWcdXW+dlsR2nCvH4DOEe3AYYh/aH8
572
- DxEE7FbtAoGBAPcNO8fJ56mNw0ow4Qg38C+Zss/afhBOCfX4O/SZKv/roRn5+gRM
573
- KRJYSVXNnsjPI1plzqR4OCyOrjAhtuvL4a0DinDzf1+fiztyNohwYsW1vYmqn3ti
574
- EN0GhSgE7ppZjqvLQ3f3LUTxynhA0U+k9wflb4irIlViTUlCsOPkrNJDAoGBANqL
575
- Q+vvuGSsmRLU/Cenjy+Mjj6+QENg51dz34o8JKuVKIPKU8pNnyeLa5fat0qD2MHm
576
- OB9opeQOcw0dStodxr6DB3wi83bpjeU6BWUGITNiWEaZEBrQ0aiqNJJKrrHm8fAZ
577
- 9o4l4oHc4hI0kYVYYDuxtKuVJrzZiEapTwoOcYiLAoGBAI/EWbeIHZIj9zOjgjEA
578
- LHvm25HtulLOtyk2jd1njQhlHNk7CW2azIPqcLLH99EwCYi/miNH+pijZ2aHGCXb
579
- /bZrSxM0ADmrZKDxdB6uGCyp+GS2sBxjEyEsfCyvwhJ8b3Q100tqwiNO+d5FCglp
580
- HICx2dgUjuRVUliBwOK93nx1AoGAUI8RhIEjOYkeDAESyhNMBr0LGjnLOosX+/as
581
- qiotYkpjWuFULbibOFp+WMW41vDvD9qrSXir3fstkeIAW5KqVkO6mJnRoT3Knnra
582
- zjiKOITCAZQeiaP8BO5o3pxE9TMqb9VCO3ffnPstIoTaN4syPg7tiGo8k1SklVeH
583
- 2S8lzq0CgYAKG2fljIYWQvGH628rp4ZcXS4hWmYohOxsnl1YrszbJ+hzR+IQOhGl
584
- YlkUQYXhy9JixmUUKtH+NXkKX7Lyc8XYw5ETr7JBT3ifs+G7HruDjVG78EJVojbd
585
- 8uLA+DdQm5mg4vd1GTiSK65q/3EeoBlUaVor3HhLFki+i9qpT8CBsg==
586
- -----END RSA PRIVATE KEY-----
587
- EOS
588
-
589
- PRIVATE_KEY = OpenSSL::PKey::RSA.new(PRIVATE_KEY_DATA)
590
-
591
- V1_0_CANONICAL_REQUEST_DATA = <<EOS
592
- Method:POST
593
- Hashed Path:#{HASHED_CANONICAL_PATH}
594
- X-Ops-Content-Hash:#{HASHED_BODY}
595
- X-Ops-Timestamp:#{TIMESTAMP_ISO8601}
596
- X-Ops-UserId:#{USER_ID}
597
- EOS
598
- V1_0_CANONICAL_REQUEST = V1_0_CANONICAL_REQUEST_DATA.chomp
599
-
600
- V1_1_CANONICAL_REQUEST_DATA = <<EOS
601
- Method:POST
602
- Hashed Path:#{HASHED_CANONICAL_PATH}
603
- X-Ops-Content-Hash:#{HASHED_BODY}
604
- X-Ops-Timestamp:#{TIMESTAMP_ISO8601}
605
- X-Ops-UserId:#{DIGESTED_USER_ID}
606
- EOS
607
- V1_1_CANONICAL_REQUEST = V1_1_CANONICAL_REQUEST_DATA.chomp
608
-
609
- V1_3_SHA256_CANONICAL_REQUEST_DATA = <<EOS
610
- Method:POST
611
- Path:#{PATH}
612
- X-Ops-Content-Hash:#{HASHED_BODY_SHA256}
613
- X-Ops-Sign:version=1.3
614
- X-Ops-Timestamp:#{TIMESTAMP_ISO8601}
615
- X-Ops-UserId:#{USER_ID}
616
- X-Ops-Server-API-Version:1
617
- EOS
618
- V1_3_SHA256_CANONICAL_REQUEST = V1_3_SHA256_CANONICAL_REQUEST_DATA.chomp
619
-
620
- V1_3_SHA256_SIGNING_OBJECT = Mixlib::Authentication::SignedHeaderAuth.signing_object(V1_3_ARGS_SHA256)
621
- V1_1_SIGNING_OBJECT = Mixlib::Authentication::SignedHeaderAuth.signing_object(V1_1_ARGS)
622
- V1_0_SIGNING_OBJECT = Mixlib::Authentication::SignedHeaderAuth.signing_object(V1_0_ARGS)
623
- LONG_SIGNING_OBJECT = Mixlib::Authentication::SignedHeaderAuth.signing_object(LONG_PATH_LONG_USER_ARGS)