mixlib-authentication 1.4.0.rc.1 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,9 +13,8 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
-
17
16
  module Mixlib
18
17
  module Authentication
19
- VERSION = '1.4.0.rc.1'
18
+ VERSION = "1.4.1"
20
19
  end
21
20
  end
@@ -1,25 +1,25 @@
1
- $:.unshift(File.dirname(__FILE__) + '/lib')
2
- require 'mixlib/authentication/version'
1
+ $:.unshift(File.dirname(__FILE__) + "/lib")
2
+ require "mixlib/authentication/version"
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "mixlib-authentication"
6
6
  s.version = Mixlib::Authentication::VERSION
7
7
  s.platform = Gem::Platform::RUBY
8
- s.has_rdoc = true
9
- s.extra_rdoc_files = ["README.rdoc", "LICENSE", 'NOTICE']
10
8
  s.summary = "Mixes in simple per-request authentication"
11
9
  s.description = s.summary
12
- s.author = "Opscode, Inc."
13
- s.email = "info@opscode.com"
14
- s.homepage = "http://www.opscode.com"
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"
15
14
 
16
15
  # Uncomment this to add a dependency
17
16
  s.add_dependency "mixlib-log"
18
17
 
19
- s.require_path = 'lib'
20
- s.files = %w(LICENSE README.rdoc Gemfile Rakefile NOTICE) + Dir.glob("*.gemspec") +
21
- Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject {|f| File.directory?(f) }
18
+ s.require_path = "lib"
19
+ s.files = %w{LICENSE README.md Gemfile Rakefile NOTICE} + Dir.glob("*.gemspec") +
20
+ Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
22
21
 
23
- %w(rspec-core rspec-expectations rspec-mocks).each { |gem| s.add_dependency gem, "~> 3.2" }
22
+ %w{rspec-core rspec-expectations rspec-mocks}.each { |gem| s.add_development_dependency gem, "~> 3.2" }
23
+ s.add_development_dependency "chefstyle"
24
24
  s.add_development_dependency "rake", "~> 10.4"
25
25
  end
@@ -1,21 +1,21 @@
1
- require 'mixlib/authentication/digester'
1
+ require "mixlib/authentication/digester"
2
2
 
3
3
  describe Mixlib::Authentication::Digester do
4
- context 'backcompat' do
4
+ context "backcompat" do
5
5
  # The digester API should really have been private,
6
6
  # however oc-chef-pedant uses it.
7
- let(:test_string) { 'hello' }
8
- let(:test_string_checksum) { 'qvTGHdzF6KLavt4PO0gs2a6pQ00=' }
7
+ let(:test_string) { "hello" }
8
+ let(:test_string_checksum) { "qvTGHdzF6KLavt4PO0gs2a6pQ00=" }
9
9
 
10
10
  describe '#hash_file' do
11
- it 'should default to use SHA1' do
11
+ it "should default to use SHA1" do
12
12
  expect(described_class.hash_file(StringIO.new(test_string))).to(
13
13
  eq(test_string_checksum))
14
14
  end
15
15
  end
16
16
 
17
17
  describe '#hash_string' do
18
- it 'should default to use SHA1' do
18
+ it "should default to use SHA1" do
19
19
  expect(described_class.hash_string(test_string)).to(
20
20
  eq(test_string_checksum))
21
21
  end
@@ -5,9 +5,9 @@
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
7
7
  # You may obtain a copy of the License at
8
- #
8
+ #
9
9
  # http://www.apache.org/licenses/LICENSE-2.0
10
- #
10
+ #
11
11
  # Unless required by applicable law or agreed to in writing, software
12
12
  # distributed under the License is distributed on an "AS IS" BASIS,
13
13
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,12 +15,12 @@
15
15
  # limitations under the License.
16
16
  #
17
17
 
18
- require File.expand_path(File.join(File.dirname(__FILE__), '..','..','spec_helper'))
18
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
19
19
 
20
- require 'mixlib/authentication'
21
- require 'mixlib/authentication/http_authentication_request'
22
- require 'ostruct'
23
- require 'pp'
20
+ require "mixlib/authentication"
21
+ require "mixlib/authentication/http_authentication_request"
22
+ require "ostruct"
23
+ require "pp"
24
24
 
25
25
  describe Mixlib::Authentication::HTTPAuthenticationRequest do
26
26
  before do
@@ -39,66 +39,66 @@ describe Mixlib::Authentication::HTTPAuthenticationRequest do
39
39
  @merb_headers = {
40
40
  # These are used by signatureverification. An arbitrary sampling of non-HTTP_*
41
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],
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
54
 
55
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",
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
61
  }
62
- @request = request.new(@merb_headers, "POST", '/nodes')
62
+ @request = request.new(@merb_headers, "POST", "/nodes")
63
63
  @http_authentication_request = Mixlib::Authentication::HTTPAuthenticationRequest.new(@request)
64
64
  end
65
65
 
66
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=="}
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
79
  expect(@http_authentication_request.headers).to eq(expected)
80
80
  end
81
81
 
82
82
  it "raises an error when not all required headers are given" do
83
83
  @merb_headers.delete("HTTP_X_OPS_SIGN")
84
84
  exception = Mixlib::Authentication::MissingAuthenticationHeader
85
- expect{ Mixlib::Authentication::HTTPAuthenticationRequest.new(@request) }.to raise_error(exception)
85
+ expect { Mixlib::Authentication::HTTPAuthenticationRequest.new(@request) }.to raise_error(exception)
86
86
  end
87
87
 
88
88
  it "extracts the path from the request" do
89
- expect(@http_authentication_request.path).to eq('/nodes')
89
+ expect(@http_authentication_request.path).to eq("/nodes")
90
90
  end
91
91
 
92
92
  it "extracts the request method from the request" do
93
- expect(@http_authentication_request.http_method).to eq('POST')
93
+ expect(@http_authentication_request.http_method).to eq("POST")
94
94
  end
95
95
 
96
96
  it "extracts the signing description from the request headers" do
97
- expect(@http_authentication_request.signing_description).to eq('version=1.0')
97
+ expect(@http_authentication_request.signing_description).to eq("version=1.0")
98
98
  end
99
99
 
100
100
  it "extracts the user_id from the request headers" do
101
- expect(@http_authentication_request.user_id).to eq('spec-user')
101
+ expect(@http_authentication_request.user_id).to eq("spec-user")
102
102
  end
103
103
 
104
104
  it "extracts the timestamp from the request headers" do
@@ -114,7 +114,7 @@ describe Mixlib::Authentication::HTTPAuthenticationRequest do
114
114
  end
115
115
 
116
116
  it "rebuilds the request signature from the headers" do
117
- expected=<<-SIG
117
+ expected = <<-SIG
118
118
  jVHrNniWzpbez/eGWjFnO6lINRIuKOg40ZTIQudcFe47Z9e/HvrszfVXlKG4
119
119
  NMzYZgyooSvU85qkIUmKuCqgG2AIlvYa2Q/2ctrMhoaHhLOCWWoqYNMaEqPc
120
120
  3tKHE+CfvP+WuPdWk4jv4wpIkAz6ZLxToxcGhXmZbXpk56YTmqgBW2cbbw4O
@@ -126,7 +126,7 @@ SIG
126
126
  end
127
127
 
128
128
  it "defaults to server api version 0" do
129
- expect(@http_authentication_request.server_api_version).to eq('0')
129
+ expect(@http_authentication_request.server_api_version).to eq("0")
130
130
  end
131
131
 
132
132
  end
@@ -18,13 +18,13 @@
18
18
  # limitations under the License.
19
19
  #
20
20
 
21
- require File.expand_path(File.join(File.dirname(__FILE__), '..','..','spec_helper'))
22
- require 'rubygems'
21
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
22
+ require "rubygems"
23
23
 
24
- require 'ostruct'
25
- require 'openssl'
26
- require 'mixlib/authentication/signatureverification'
27
- require 'time'
24
+ require "ostruct"
25
+ require "openssl"
26
+ require "mixlib/authentication/signatureverification"
27
+ require "time"
28
28
 
29
29
  # TODO: should make these regular spec-based mock objects.
30
30
  class MockRequest
@@ -102,10 +102,9 @@ describe "Mixlib::Authentication::SignedHeaderAuth" do
102
102
  expect(V1_3_SHA256_SIGNING_OBJECT.sign(PRIVATE_KEY)).to eq(EXPECTED_SIGN_RESULT_V1_3_SHA256)
103
103
  end
104
104
 
105
-
106
105
  it "should generate the correct string to sign and signature for non-default proto version when used as a mixin" do
107
- algorithm = 'sha1'
108
- version = '1.1'
106
+ algorithm = "sha1"
107
+ version = "1.1"
109
108
 
110
109
  V1_1_SIGNING_OBJECT.proto_version = "1.0"
111
110
  expect(V1_1_SIGNING_OBJECT.proto_version).to eq("1.0")
@@ -118,19 +117,19 @@ describe "Mixlib::Authentication::SignedHeaderAuth" do
118
117
  end
119
118
 
120
119
  it "should not choke when signing a request for a long user id with version 1.1" do
121
- expect { LONG_SIGNING_OBJECT.sign(PRIVATE_KEY, 'sha1', '1.1') }.not_to raise_error
120
+ expect { LONG_SIGNING_OBJECT.sign(PRIVATE_KEY, "sha1", "1.1") }.not_to raise_error
122
121
  end
123
122
 
124
123
  it "should choke when signing a request for a long user id with version 1.0" do
125
- expect { LONG_SIGNING_OBJECT.sign(PRIVATE_KEY, 'sha1', '1.0') }.to raise_error(OpenSSL::PKey::RSAError)
124
+ expect { LONG_SIGNING_OBJECT.sign(PRIVATE_KEY, "sha1", "1.0") }.to raise_error(OpenSSL::PKey::RSAError)
126
125
  end
127
126
 
128
127
  it "should choke when signing a request with a bad version" do
129
- expect { V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, 'sha1', 'poo') }.to raise_error(Mixlib::Authentication::AuthenticationError)
128
+ expect { V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, "sha1", "poo") }.to raise_error(Mixlib::Authentication::AuthenticationError)
130
129
  end
131
130
 
132
131
  it "should choke when signing a request with a bad algorithm" do
133
- expect { V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, 'sha_poo', '1.1') }.to raise_error(Mixlib::Authentication::AuthenticationError)
132
+ expect { V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, "sha_poo", "1.1") }.to raise_error(Mixlib::Authentication::AuthenticationError)
134
133
  end
135
134
 
136
135
  end
@@ -144,7 +143,7 @@ describe "Mixlib::Authentication::SignatureVerification" do
144
143
  it "should authenticate a File-containing request V1.1 - Merb" do
145
144
  request_params = MERB_REQUEST_PARAMS.clone
146
145
  request_params["file"] =
147
- { "size"=>MockFile.length, "content_type"=>"application/octet-stream", "filename"=>"zsh.tar.gz", "tempfile"=>MockFile.new }
146
+ { "size" => MockFile.length, "content_type" => "application/octet-stream", "filename" => "zsh.tar.gz", "tempfile" => MockFile.new }
148
147
 
149
148
  mock_request = MockRequest.new(PATH, request_params, MERB_HEADERS_V1_1, "")
150
149
  expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
@@ -157,7 +156,7 @@ describe "Mixlib::Authentication::SignatureVerification" do
157
156
  it "should authenticate a File-containing request V1.3 SHA256 - Merb" do
158
157
  request_params = MERB_REQUEST_PARAMS.clone
159
158
  request_params["file"] =
160
- { "size"=>MockFile.length, "content_type"=>"application/octet-stream", "filename"=>"zsh.tar.gz", "tempfile"=>MockFile.new }
159
+ { "size" => MockFile.length, "content_type" => "application/octet-stream", "filename" => "zsh.tar.gz", "tempfile" => MockFile.new }
161
160
 
162
161
  mock_request = MockRequest.new(PATH, request_params, MERB_HEADERS_V1_3_SHA256, "")
163
162
  expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
@@ -215,7 +214,7 @@ describe "Mixlib::Authentication::SignatureVerification" do
215
214
  #Time.stub!(:now).and_return(TIMESTAMP_OBJ)
216
215
 
217
216
  auth_req = Mixlib::Authentication::SignatureVerification.new
218
- expect {auth_req.authenticate_user_request(mock_request, @user_private_key)}.to raise_error(Mixlib::Authentication::AuthenticationError)
217
+ expect { auth_req.authenticate_user_request(mock_request, @user_private_key) }.to raise_error(Mixlib::Authentication::AuthenticationError)
219
218
 
220
219
  expect(auth_req).not_to be_a_valid_request
221
220
  expect(auth_req).not_to be_a_valid_timestamp
@@ -223,7 +222,6 @@ describe "Mixlib::Authentication::SignatureVerification" do
223
222
  expect(auth_req).not_to be_a_valid_content_hash
224
223
  end
225
224
 
226
-
227
225
  it "shouldn't authenticate if Authorization header is wrong" do
228
226
  headers = MERB_HEADERS_V1_1.clone
229
227
  headers["HTTP_X_OPS_CONTENT_HASH"] += "_"
@@ -255,7 +253,7 @@ describe "Mixlib::Authentication::SignatureVerification" do
255
253
  end
256
254
 
257
255
  it "shouldn't authenticate if the signature is wrong" do
258
- headers = MERB_HEADERS_V1_1.dup
256
+ headers = MERB_HEADERS_V1_1.dup
259
257
  headers["HTTP_X_OPS_AUTHORIZATION_1"] = "epicfail"
260
258
  mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, headers, BODY)
261
259
  expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
@@ -270,7 +268,7 @@ describe "Mixlib::Authentication::SignatureVerification" do
270
268
  end
271
269
 
272
270
  it "shouldn't authenticate if the signature is wrong for v1.3 SHA256" do
273
- headers = MERB_HEADERS_V1_3_SHA256.dup
271
+ headers = MERB_HEADERS_V1_3_SHA256.dup
274
272
  headers["HTTP_X_OPS_AUTHORIZATION_1"] = "epicfail"
275
273
  mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, headers, BODY)
276
274
  expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
@@ -301,7 +299,7 @@ V1_0_ARGS = {
301
299
  :http_method => :post,
302
300
  :timestamp => TIMESTAMP_ISO8601, # fixed timestamp so we get back the same answer each time.
303
301
  :file => MockFile.new,
304
- :path => PATH
302
+ :path => PATH,
305
303
  }
306
304
 
307
305
  V1_1_ARGS = {
@@ -311,7 +309,7 @@ V1_1_ARGS = {
311
309
  :timestamp => TIMESTAMP_ISO8601, # fixed timestamp so we get back the same answer each time.
312
310
  :file => MockFile.new,
313
311
  :path => PATH,
314
- :proto_version => 1.1
312
+ :proto_version => 1.1,
315
313
  }
316
314
 
317
315
  V1_3_ARGS_SHA256 = {
@@ -321,9 +319,9 @@ V1_3_ARGS_SHA256 = {
321
319
  :timestamp => TIMESTAMP_ISO8601, # fixed timestamp so we get back the same answer each time.
322
320
  :file => MockFile.new,
323
321
  :path => PATH,
324
- :proto_version => '1.3',
322
+ :proto_version => "1.3",
325
323
  :headers => {
326
- 'X-OpS-SeRvEr-ApI-VerSiOn' => '1'
324
+ "X-OpS-SeRvEr-ApI-VerSiOn" => "1",
327
325
  }
328
326
  # This defaults to sha256
329
327
  }
@@ -332,9 +330,9 @@ LONG_PATH_LONG_USER_ARGS = {
332
330
  :body => BODY,
333
331
  :user_id => "A" * 200,
334
332
  :http_method => :put,
335
- :timestamp => TIMESTAMP_ISO8601, # fixed timestamp so we get back the same answer each time.
333
+ :timestamp => TIMESTAMP_ISO8601, # fixed timestamp so we get back the same answer each time.
336
334
  :file => MockFile.new,
337
- :path => PATH + "/nodes/#{"A" * 250}"
335
+ :path => PATH + "/nodes/#{"A" * 250}",
338
336
  }
339
337
 
340
338
  REQUESTING_ACTOR_ID = "c0f8a68c52bffa1020222a56b23cccfa"
@@ -349,7 +347,7 @@ X_OPS_AUTHORIZATION_LINES_V1_0 = [
349
347
  "3tKHE+CfvP+WuPdWk4jv4wpIkAz6ZLxToxcGhXmZbXpk56YTmqgBW2cbbw4O",
350
348
  "IWPZDHSiPcw//AYNgW1CCDptt+UFuaFYbtqZegcBd2n/jzcWODA7zL4KWEUy",
351
349
  "9q4rlh/+1tBReg60QdsmDRsw/cdO1GZrKtuCwbuD4+nbRdVBKv72rqHX9cu0",
352
- "utju9jzczCyB+sSAQWrxSsXB/b8vV2qs0l4VD2ML+w=="
350
+ "utju9jzczCyB+sSAQWrxSsXB/b8vV2qs0l4VD2ML+w==",
353
351
  ]
354
352
 
355
353
  X_OPS_AUTHORIZATION_LINES = [
@@ -358,7 +356,7 @@ X_OPS_AUTHORIZATION_LINES = [
358
356
  "c2R9bx/43IWA/r8w8Q6decuu0f6ZlNheJeJhaYPI8piX/aH+uHBH8zTACZu8",
359
357
  "vMnl5MF3/OIlsZc8cemq6eKYstp8a8KYq9OmkB5IXIX6qVMJHA6fRvQEB/7j",
360
358
  "281Q7oI/O+lE8AmVyBbwruPb7Mp6s4839eYiOdjbDwFjYtbS3XgAjrHlaD7W",
361
- "FDlbAG7H8Dmvo+wBxmtNkszhzbBnEYtuwQqT8nM/8A=="
359
+ "FDlbAG7H8Dmvo+wBxmtNkszhzbBnEYtuwQqT8nM/8A==",
362
360
  ]
363
361
 
364
362
  X_OPS_AUTHORIZATION_LINES_V1_3_SHA256 = [
@@ -367,154 +365,154 @@ X_OPS_AUTHORIZATION_LINES_V1_3_SHA256 = [
367
365
  "42dZ9N+V9I5SVfcL/lWrrlpdybfceJC5jOcP5tzfJXWUITwb6Z3Erg3DU3Uh",
368
366
  "H9h9E0qWlYGqmiNCVrBnpe6Si1gU/Jl+rXlRSNbLJ4GlArAPuL976iTYJTzE",
369
367
  "MmbLUIm3JRYi00Yb01IUCCKdI90vUq1HHNtlTEu93YZfQaJwRxXlGkCNwIJe",
370
- "fy49QzaCIEu1XiOx5Jn+4GmkrZch/RrK9VzQWXgs+w=="
368
+ "fy49QzaCIEu1XiOx5Jn+4GmkrZch/RrK9VzQWXgs+w==",
371
369
  ]
372
370
  # We expect Mixlib::Authentication::SignedHeaderAuth#sign to return this
373
371
  # if passed the BODY above, based on version
374
372
 
375
373
  EXPECTED_SIGN_RESULT_V1_0 = {
376
- "X-Ops-Content-Hash"=>X_OPS_CONTENT_HASH,
377
- "X-Ops-Userid"=>USER_ID,
378
- "X-Ops-Sign"=>"algorithm=sha1;version=1.0;",
379
- "X-Ops-Authorization-1"=>X_OPS_AUTHORIZATION_LINES_V1_0[0],
380
- "X-Ops-Authorization-2"=>X_OPS_AUTHORIZATION_LINES_V1_0[1],
381
- "X-Ops-Authorization-3"=>X_OPS_AUTHORIZATION_LINES_V1_0[2],
382
- "X-Ops-Authorization-4"=>X_OPS_AUTHORIZATION_LINES_V1_0[3],
383
- "X-Ops-Authorization-5"=>X_OPS_AUTHORIZATION_LINES_V1_0[4],
384
- "X-Ops-Authorization-6"=>X_OPS_AUTHORIZATION_LINES_V1_0[5],
385
- "X-Ops-Timestamp"=>TIMESTAMP_ISO8601
374
+ "X-Ops-Content-Hash" => X_OPS_CONTENT_HASH,
375
+ "X-Ops-Userid" => USER_ID,
376
+ "X-Ops-Sign" => "algorithm=sha1;version=1.0;",
377
+ "X-Ops-Authorization-1" => X_OPS_AUTHORIZATION_LINES_V1_0[0],
378
+ "X-Ops-Authorization-2" => X_OPS_AUTHORIZATION_LINES_V1_0[1],
379
+ "X-Ops-Authorization-3" => X_OPS_AUTHORIZATION_LINES_V1_0[2],
380
+ "X-Ops-Authorization-4" => X_OPS_AUTHORIZATION_LINES_V1_0[3],
381
+ "X-Ops-Authorization-5" => X_OPS_AUTHORIZATION_LINES_V1_0[4],
382
+ "X-Ops-Authorization-6" => X_OPS_AUTHORIZATION_LINES_V1_0[5],
383
+ "X-Ops-Timestamp" => TIMESTAMP_ISO8601,
386
384
  }
387
385
 
388
386
  EXPECTED_SIGN_RESULT_V1_1 = {
389
- "X-Ops-Content-Hash"=>X_OPS_CONTENT_HASH,
390
- "X-Ops-Userid"=>USER_ID,
391
- "X-Ops-Sign"=>"algorithm=sha1;version=1.1;",
392
- "X-Ops-Authorization-1"=>X_OPS_AUTHORIZATION_LINES[0],
393
- "X-Ops-Authorization-2"=>X_OPS_AUTHORIZATION_LINES[1],
394
- "X-Ops-Authorization-3"=>X_OPS_AUTHORIZATION_LINES[2],
395
- "X-Ops-Authorization-4"=>X_OPS_AUTHORIZATION_LINES[3],
396
- "X-Ops-Authorization-5"=>X_OPS_AUTHORIZATION_LINES[4],
397
- "X-Ops-Authorization-6"=>X_OPS_AUTHORIZATION_LINES[5],
398
- "X-Ops-Timestamp"=>TIMESTAMP_ISO8601
387
+ "X-Ops-Content-Hash" => X_OPS_CONTENT_HASH,
388
+ "X-Ops-Userid" => USER_ID,
389
+ "X-Ops-Sign" => "algorithm=sha1;version=1.1;",
390
+ "X-Ops-Authorization-1" => X_OPS_AUTHORIZATION_LINES[0],
391
+ "X-Ops-Authorization-2" => X_OPS_AUTHORIZATION_LINES[1],
392
+ "X-Ops-Authorization-3" => X_OPS_AUTHORIZATION_LINES[2],
393
+ "X-Ops-Authorization-4" => X_OPS_AUTHORIZATION_LINES[3],
394
+ "X-Ops-Authorization-5" => X_OPS_AUTHORIZATION_LINES[4],
395
+ "X-Ops-Authorization-6" => X_OPS_AUTHORIZATION_LINES[5],
396
+ "X-Ops-Timestamp" => TIMESTAMP_ISO8601,
399
397
  }
400
398
 
401
399
  EXPECTED_SIGN_RESULT_V1_3_SHA256 = {
402
- "X-Ops-Content-Hash"=>X_OPS_CONTENT_HASH_SHA256,
403
- "X-Ops-Userid"=>USER_ID,
404
- "X-Ops-Sign"=>"algorithm=sha256;version=1.3;",
405
- "X-Ops-Authorization-1"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[0],
406
- "X-Ops-Authorization-2"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[1],
407
- "X-Ops-Authorization-3"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[2],
408
- "X-Ops-Authorization-4"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[3],
409
- "X-Ops-Authorization-5"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[4],
410
- "X-Ops-Authorization-6"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[5],
411
- "X-Ops-Timestamp"=>TIMESTAMP_ISO8601
400
+ "X-Ops-Content-Hash" => X_OPS_CONTENT_HASH_SHA256,
401
+ "X-Ops-Userid" => USER_ID,
402
+ "X-Ops-Sign" => "algorithm=sha256;version=1.3;",
403
+ "X-Ops-Authorization-1" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[0],
404
+ "X-Ops-Authorization-2" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[1],
405
+ "X-Ops-Authorization-3" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[2],
406
+ "X-Ops-Authorization-4" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[3],
407
+ "X-Ops-Authorization-5" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[4],
408
+ "X-Ops-Authorization-6" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[5],
409
+ "X-Ops-Timestamp" => TIMESTAMP_ISO8601,
412
410
  }
413
411
 
414
412
  OTHER_HEADERS = {
415
413
  # An arbitrary sampling of non-HTTP_* headers are in here to
416
414
  # exercise that code path.
417
- "REMOTE_ADDR"=>"127.0.0.1",
418
- "PATH_INFO"=>"/organizations/local-test-org/cookbooks",
419
- "REQUEST_PATH"=>"/organizations/local-test-org/cookbooks",
420
- "CONTENT_TYPE"=>"multipart/form-data; boundary=----RubyMultipartClient6792ZZZZZ",
421
- "CONTENT_LENGTH"=>"394",
415
+ "REMOTE_ADDR" => "127.0.0.1",
416
+ "PATH_INFO" => "/organizations/local-test-org/cookbooks",
417
+ "REQUEST_PATH" => "/organizations/local-test-org/cookbooks",
418
+ "CONTENT_TYPE" => "multipart/form-data; boundary=----RubyMultipartClient6792ZZZZZ",
419
+ "CONTENT_LENGTH" => "394",
422
420
  }
423
421
 
424
422
  # This is what will be in request.params for the Merb case.
425
423
  MERB_REQUEST_PARAMS = {
426
- "name"=>"zsh", "action"=>"create", "controller"=>"chef_server_api/cookbooks",
427
- "organization_id"=>"local-test-org", "requesting_actor_id"=>REQUESTING_ACTOR_ID,
424
+ "name" => "zsh", "action" => "create", "controller" => "chef_server_api/cookbooks",
425
+ "organization_id" => "local-test-org", "requesting_actor_id" => REQUESTING_ACTOR_ID
428
426
  }
429
427
 
430
428
  MERB_HEADERS_V1_3_SHA256 = {
431
429
  # These are used by signatureverification.
432
- "HTTP_HOST"=>"127.0.0.1",
433
- "HTTP_X_OPS_SIGN"=>"algorithm=sha256;version=1.3;",
434
- "HTTP_X_OPS_REQUESTID"=>"127.0.0.1 1258566194.85386",
435
- "HTTP_X_OPS_TIMESTAMP"=>TIMESTAMP_ISO8601,
436
- "HTTP_X_OPS_CONTENT_HASH"=>X_OPS_CONTENT_HASH_SHA256,
437
- "HTTP_X_OPS_USERID"=>USER_ID,
438
- "HTTP_X_OPS_SERVER_API_VERSION"=>"1",
439
- "HTTP_X_OPS_AUTHORIZATION_1"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[0],
440
- "HTTP_X_OPS_AUTHORIZATION_2"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[1],
441
- "HTTP_X_OPS_AUTHORIZATION_3"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[2],
442
- "HTTP_X_OPS_AUTHORIZATION_4"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[3],
443
- "HTTP_X_OPS_AUTHORIZATION_5"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[4],
444
- "HTTP_X_OPS_AUTHORIZATION_6"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[5],
430
+ "HTTP_HOST" => "127.0.0.1",
431
+ "HTTP_X_OPS_SIGN" => "algorithm=sha256;version=1.3;",
432
+ "HTTP_X_OPS_REQUESTID" => "127.0.0.1 1258566194.85386",
433
+ "HTTP_X_OPS_TIMESTAMP" => TIMESTAMP_ISO8601,
434
+ "HTTP_X_OPS_CONTENT_HASH" => X_OPS_CONTENT_HASH_SHA256,
435
+ "HTTP_X_OPS_USERID" => USER_ID,
436
+ "HTTP_X_OPS_SERVER_API_VERSION" => "1",
437
+ "HTTP_X_OPS_AUTHORIZATION_1" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[0],
438
+ "HTTP_X_OPS_AUTHORIZATION_2" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[1],
439
+ "HTTP_X_OPS_AUTHORIZATION_3" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[2],
440
+ "HTTP_X_OPS_AUTHORIZATION_4" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[3],
441
+ "HTTP_X_OPS_AUTHORIZATION_5" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[4],
442
+ "HTTP_X_OPS_AUTHORIZATION_6" => X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[5],
445
443
  }.merge(OTHER_HEADERS)
446
444
 
447
445
  # Tis is what will be in request.env for the Merb case.
448
446
  MERB_HEADERS_V1_1 = {
449
447
  # These are used by signatureverification.
450
- "HTTP_HOST"=>"127.0.0.1",
451
- "HTTP_X_OPS_SIGN"=>"algorithm=sha1;version=1.1;",
452
- "HTTP_X_OPS_REQUESTID"=>"127.0.0.1 1258566194.85386",
453
- "HTTP_X_OPS_TIMESTAMP"=>TIMESTAMP_ISO8601,
454
- "HTTP_X_OPS_CONTENT_HASH"=>X_OPS_CONTENT_HASH,
455
- "HTTP_X_OPS_USERID"=>USER_ID,
456
- "HTTP_X_OPS_AUTHORIZATION_1"=>X_OPS_AUTHORIZATION_LINES[0],
457
- "HTTP_X_OPS_AUTHORIZATION_2"=>X_OPS_AUTHORIZATION_LINES[1],
458
- "HTTP_X_OPS_AUTHORIZATION_3"=>X_OPS_AUTHORIZATION_LINES[2],
459
- "HTTP_X_OPS_AUTHORIZATION_4"=>X_OPS_AUTHORIZATION_LINES[3],
460
- "HTTP_X_OPS_AUTHORIZATION_5"=>X_OPS_AUTHORIZATION_LINES[4],
461
- "HTTP_X_OPS_AUTHORIZATION_6"=>X_OPS_AUTHORIZATION_LINES[5],
448
+ "HTTP_HOST" => "127.0.0.1",
449
+ "HTTP_X_OPS_SIGN" => "algorithm=sha1;version=1.1;",
450
+ "HTTP_X_OPS_REQUESTID" => "127.0.0.1 1258566194.85386",
451
+ "HTTP_X_OPS_TIMESTAMP" => TIMESTAMP_ISO8601,
452
+ "HTTP_X_OPS_CONTENT_HASH" => X_OPS_CONTENT_HASH,
453
+ "HTTP_X_OPS_USERID" => USER_ID,
454
+ "HTTP_X_OPS_AUTHORIZATION_1" => X_OPS_AUTHORIZATION_LINES[0],
455
+ "HTTP_X_OPS_AUTHORIZATION_2" => X_OPS_AUTHORIZATION_LINES[1],
456
+ "HTTP_X_OPS_AUTHORIZATION_3" => X_OPS_AUTHORIZATION_LINES[2],
457
+ "HTTP_X_OPS_AUTHORIZATION_4" => X_OPS_AUTHORIZATION_LINES[3],
458
+ "HTTP_X_OPS_AUTHORIZATION_5" => X_OPS_AUTHORIZATION_LINES[4],
459
+ "HTTP_X_OPS_AUTHORIZATION_6" => X_OPS_AUTHORIZATION_LINES[5],
462
460
  }.merge(OTHER_HEADERS)
463
461
 
464
462
  # Tis is what will be in request.env for the Merb case.
465
463
  MERB_HEADERS_V1_0 = {
466
464
  # These are used by signatureverification.
467
- "HTTP_HOST"=>"127.0.0.1",
468
- "HTTP_X_OPS_SIGN"=>"version=1.0",
469
- "HTTP_X_OPS_REQUESTID"=>"127.0.0.1 1258566194.85386",
470
- "HTTP_X_OPS_TIMESTAMP"=>TIMESTAMP_ISO8601,
471
- "HTTP_X_OPS_CONTENT_HASH"=>X_OPS_CONTENT_HASH,
472
- "HTTP_X_OPS_USERID"=>USER_ID,
473
- "HTTP_X_OPS_AUTHORIZATION_1"=>X_OPS_AUTHORIZATION_LINES_V1_0[0],
474
- "HTTP_X_OPS_AUTHORIZATION_2"=>X_OPS_AUTHORIZATION_LINES_V1_0[1],
475
- "HTTP_X_OPS_AUTHORIZATION_3"=>X_OPS_AUTHORIZATION_LINES_V1_0[2],
476
- "HTTP_X_OPS_AUTHORIZATION_4"=>X_OPS_AUTHORIZATION_LINES_V1_0[3],
477
- "HTTP_X_OPS_AUTHORIZATION_5"=>X_OPS_AUTHORIZATION_LINES_V1_0[4],
478
- "HTTP_X_OPS_AUTHORIZATION_6"=>X_OPS_AUTHORIZATION_LINES_V1_0[5],
465
+ "HTTP_HOST" => "127.0.0.1",
466
+ "HTTP_X_OPS_SIGN" => "version=1.0",
467
+ "HTTP_X_OPS_REQUESTID" => "127.0.0.1 1258566194.85386",
468
+ "HTTP_X_OPS_TIMESTAMP" => TIMESTAMP_ISO8601,
469
+ "HTTP_X_OPS_CONTENT_HASH" => X_OPS_CONTENT_HASH,
470
+ "HTTP_X_OPS_USERID" => USER_ID,
471
+ "HTTP_X_OPS_AUTHORIZATION_1" => X_OPS_AUTHORIZATION_LINES_V1_0[0],
472
+ "HTTP_X_OPS_AUTHORIZATION_2" => X_OPS_AUTHORIZATION_LINES_V1_0[1],
473
+ "HTTP_X_OPS_AUTHORIZATION_3" => X_OPS_AUTHORIZATION_LINES_V1_0[2],
474
+ "HTTP_X_OPS_AUTHORIZATION_4" => X_OPS_AUTHORIZATION_LINES_V1_0[3],
475
+ "HTTP_X_OPS_AUTHORIZATION_5" => X_OPS_AUTHORIZATION_LINES_V1_0[4],
476
+ "HTTP_X_OPS_AUTHORIZATION_6" => X_OPS_AUTHORIZATION_LINES_V1_0[5],
479
477
  }.merge(OTHER_HEADERS)
480
478
 
481
479
  PASSENGER_REQUEST_PARAMS = {
482
- "action"=>"create",
480
+ "action" => "create",
483
481
  #"tarball"=>#<File:/tmp/RackMultipart20091120-25570-mgq2sa-0>,
484
- "controller"=>"api/v1/cookbooks",
485
- "cookbook"=>"{\"category\":\"databases\"}",
482
+ "controller" => "api/v1/cookbooks",
483
+ "cookbook" => "{\"category\":\"databases\"}",
486
484
  }
487
485
 
488
486
  PASSENGER_HEADERS_V1_1 = {
489
487
  # These are used by signatureverification.
490
- "HTTP_HOST"=>"127.0.0.1",
491
- "HTTP_X_OPS_SIGN"=>"algorithm=sha1;version=1.1;",
492
- "HTTP_X_OPS_REQUESTID"=>"127.0.0.1 1258566194.85386",
493
- "HTTP_X_OPS_TIMESTAMP"=>TIMESTAMP_ISO8601,
494
- "HTTP_X_OPS_CONTENT_HASH"=>X_OPS_CONTENT_HASH,
495
- "HTTP_X_OPS_USERID"=>USER_ID,
496
- "HTTP_X_OPS_AUTHORIZATION_1"=>X_OPS_AUTHORIZATION_LINES[0],
497
- "HTTP_X_OPS_AUTHORIZATION_2"=>X_OPS_AUTHORIZATION_LINES[1],
498
- "HTTP_X_OPS_AUTHORIZATION_3"=>X_OPS_AUTHORIZATION_LINES[2],
499
- "HTTP_X_OPS_AUTHORIZATION_4"=>X_OPS_AUTHORIZATION_LINES[3],
500
- "HTTP_X_OPS_AUTHORIZATION_5"=>X_OPS_AUTHORIZATION_LINES[4],
501
- "HTTP_X_OPS_AUTHORIZATION_6"=>X_OPS_AUTHORIZATION_LINES[5],
488
+ "HTTP_HOST" => "127.0.0.1",
489
+ "HTTP_X_OPS_SIGN" => "algorithm=sha1;version=1.1;",
490
+ "HTTP_X_OPS_REQUESTID" => "127.0.0.1 1258566194.85386",
491
+ "HTTP_X_OPS_TIMESTAMP" => TIMESTAMP_ISO8601,
492
+ "HTTP_X_OPS_CONTENT_HASH" => X_OPS_CONTENT_HASH,
493
+ "HTTP_X_OPS_USERID" => USER_ID,
494
+ "HTTP_X_OPS_AUTHORIZATION_1" => X_OPS_AUTHORIZATION_LINES[0],
495
+ "HTTP_X_OPS_AUTHORIZATION_2" => X_OPS_AUTHORIZATION_LINES[1],
496
+ "HTTP_X_OPS_AUTHORIZATION_3" => X_OPS_AUTHORIZATION_LINES[2],
497
+ "HTTP_X_OPS_AUTHORIZATION_4" => X_OPS_AUTHORIZATION_LINES[3],
498
+ "HTTP_X_OPS_AUTHORIZATION_5" => X_OPS_AUTHORIZATION_LINES[4],
499
+ "HTTP_X_OPS_AUTHORIZATION_6" => X_OPS_AUTHORIZATION_LINES[5],
502
500
  }.merge(OTHER_HEADERS)
503
501
 
504
502
  PASSENGER_HEADERS_V1_0 = {
505
503
  # These are used by signatureverification.
506
- "HTTP_HOST"=>"127.0.0.1",
507
- "HTTP_X_OPS_SIGN"=>"version=1.0",
508
- "HTTP_X_OPS_REQUESTID"=>"127.0.0.1 1258566194.85386",
509
- "HTTP_X_OPS_TIMESTAMP"=>TIMESTAMP_ISO8601,
510
- "HTTP_X_OPS_CONTENT_HASH"=>X_OPS_CONTENT_HASH,
511
- "HTTP_X_OPS_USERID"=>USER_ID,
512
- "HTTP_X_OPS_AUTHORIZATION_1"=>X_OPS_AUTHORIZATION_LINES_V1_0[0],
513
- "HTTP_X_OPS_AUTHORIZATION_2"=>X_OPS_AUTHORIZATION_LINES_V1_0[1],
514
- "HTTP_X_OPS_AUTHORIZATION_3"=>X_OPS_AUTHORIZATION_LINES_V1_0[2],
515
- "HTTP_X_OPS_AUTHORIZATION_4"=>X_OPS_AUTHORIZATION_LINES_V1_0[3],
516
- "HTTP_X_OPS_AUTHORIZATION_5"=>X_OPS_AUTHORIZATION_LINES_V1_0[4],
517
- "HTTP_X_OPS_AUTHORIZATION_6"=>X_OPS_AUTHORIZATION_LINES_V1_0[5],
504
+ "HTTP_HOST" => "127.0.0.1",
505
+ "HTTP_X_OPS_SIGN" => "version=1.0",
506
+ "HTTP_X_OPS_REQUESTID" => "127.0.0.1 1258566194.85386",
507
+ "HTTP_X_OPS_TIMESTAMP" => TIMESTAMP_ISO8601,
508
+ "HTTP_X_OPS_CONTENT_HASH" => X_OPS_CONTENT_HASH,
509
+ "HTTP_X_OPS_USERID" => USER_ID,
510
+ "HTTP_X_OPS_AUTHORIZATION_1" => X_OPS_AUTHORIZATION_LINES_V1_0[0],
511
+ "HTTP_X_OPS_AUTHORIZATION_2" => X_OPS_AUTHORIZATION_LINES_V1_0[1],
512
+ "HTTP_X_OPS_AUTHORIZATION_3" => X_OPS_AUTHORIZATION_LINES_V1_0[2],
513
+ "HTTP_X_OPS_AUTHORIZATION_4" => X_OPS_AUTHORIZATION_LINES_V1_0[3],
514
+ "HTTP_X_OPS_AUTHORIZATION_5" => X_OPS_AUTHORIZATION_LINES_V1_0[4],
515
+ "HTTP_X_OPS_AUTHORIZATION_6" => X_OPS_AUTHORIZATION_LINES_V1_0[5],
518
516
  }.merge(OTHER_HEADERS)
519
517
 
520
518
  # generated with