escher 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2c7d0c11568986e6d42c2d60a853da006ce45484
4
- data.tar.gz: 867865591e198f3466bfe1872ab87e17cdb47429
3
+ metadata.gz: ba40c7a7b12bb5aec126c7151b4a8cf81eaa3f51
4
+ data.tar.gz: 3fa09ffdec0d12b2bb7deaaf9aa30cecc23dfe63
5
5
  SHA512:
6
- metadata.gz: 674aadece40c90e9affccc8a23a1ed12ee2c86512bd627134cb266ce8cbf4ace7693201114e5ff451b49fc6ca80eca074b4ca4969481d210284ed3b9eba04cf7
7
- data.tar.gz: 92c61fbad4a295131b23fae67e1429e10e53b807c4e474fcd1357d72fe896782650bcea4865c0f1d690c83d724a175779c836955e1412c44f0e60d1e9e36096c
6
+ metadata.gz: b5060b34740b6300e7f9abef1ee5ef32c4470336dbf956d74047a9e9048e5990b9755738f650221db734493d3a0ad27101905c669111edbda9e9b52f9dbce555
7
+ data.tar.gz: 4fdcfda5426410a5ba9b465099630d626a72ce105bffdd968765ac284bdbfe79057a594f942822cbb2b9c351a72c94a702f86ad4134de81a965cf56f839ec07d
data/lib/escher/base.rb CHANGED
@@ -21,13 +21,26 @@ class Escher
21
21
  @clock_skew = options[:clock_skew] || 900
22
22
  end
23
23
 
24
- def sign!(req, client)
25
- request = EscherRequest.new(req)
26
- auth_header = generate_auth_header(client, request.method, uri_parsed.host, uri_parsed.path, request.body || '', request.to_enum.to_a, [])
24
+ def sign!(request, client, headers_to_sign = [])
25
+ uri = Addressable::URI.parse(request[:uri])
26
+ body = request[:body] || ''
27
+ headers = request[:headers].map {|k, v| {k.downcase => v} }.reduce({}, &:merge)
28
+
29
+ host = headers['host'] || uri.host || request[:host]
30
+
31
+ unless headers.has_key? 'host'
32
+ headers['host'] = host
33
+ end
34
+ unless headers.has_key? @date_header_name
35
+ headers[@date_header_name] = format_date_for_header
36
+ end
37
+
38
+ headers_to_sign |= [@date_header_name.downcase, 'host']
39
+
27
40
 
28
- request.set_header('Host', request.host) # TODO: we shouldn't remove port from Host here
29
- request.set_header(@date_header_name, format_date_for_header)
30
- request.set_header(@auth_header_name, auth_header)
41
+ auth_header = generate_auth_header(client, request[:method], uri.path + (uri.query ? '?' + uri.query : ''), body, headers.map { |k, v| [k, v] }, headers_to_sign)
42
+
43
+ request[:headers] = headers.merge(@auth_header_name => auth_header)
31
44
  request
32
45
  end
33
46
 
@@ -101,10 +114,8 @@ class Escher
101
114
  )
102
115
  end
103
116
 
104
- def generate_auth_header(client, method, host, request_uri, body, headers, headers_to_sign)
117
+ def generate_auth_header(client, method, request_uri, body, headers, headers_to_sign)
105
118
  path, query_parts = parse_uri(request_uri)
106
- headers = add_defaults_to(headers, host)
107
- headers_to_sign |= [@date_header_name.downcase, 'host']
108
119
  signature = generate_signature(client[:api_secret], body, headers, method, headers_to_sign, path, query_parts)
109
120
  "#{get_algorithm_id} Credential=#{client[:api_key_id]}/#{short_date(@current_time)}/#{@credential_scope}, SignedHeaders=#{prepare_headers_to_sign headers_to_sign}, Signature=#{signature}"
110
121
  end
@@ -182,21 +193,10 @@ class Escher
182
193
  Digest::HMAC.hexdigest(string_to_sign, signing_key, create_algo)
183
194
  end
184
195
 
185
- def add_defaults_to(headers, host)
186
- [['host', host], [@date_header_name, format_date_for_header]]
187
- .each { |k, v| headers = add_if_missing headers, k, v }
188
- headers
189
- end
190
-
191
196
  def format_date_for_header
192
197
  @date_header_name.downcase == 'date' ? @current_time.utc.rfc2822.sub('-0000', 'GMT') : long_date(@current_time)
193
198
  end
194
199
 
195
- def add_if_missing(headers, header_to_find, value)
196
- headers += [header_to_find, value] unless headers.find { |header| header[0].downcase == header_to_find.downcase }
197
- headers
198
- end
199
-
200
200
  def canonicalize(method, path, query_parts, body, headers, headers_to_sign) [
201
201
  method,
202
202
  canonicalize_path(path),
@@ -3,7 +3,9 @@ class EscherRequest
3
3
 
4
4
  def initialize(request)
5
5
  @request = request
6
- @request_uri = Addressable::URI.parse(uri)
6
+ request_uri = Addressable::URI.parse(uri)
7
+ raise "Invalid request URI: #{request_uri}" unless request_uri
8
+ @request_uri = request_uri
7
9
  prepare_request_headers
8
10
  end
9
11
 
@@ -66,6 +68,10 @@ class EscherRequest
66
68
  end
67
69
  end
68
70
 
71
+ def host
72
+ @request_uri.host
73
+ end
74
+
69
75
  def path
70
76
  @request_uri.path
71
77
  end
@@ -1,3 +1,3 @@
1
1
  class Escher
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.1'
3
3
  end
data/spec/escher_spec.rb CHANGED
@@ -45,10 +45,12 @@ ESCHER_AWS4_OPTIONS = {
45
45
  algo_prefix: 'AWS4', vendor_key: 'AWS4', hash_algo: 'SHA256', auth_header_name: 'Authorization', date_header_name: 'Date'
46
46
  }
47
47
 
48
- ESCHER_EMARSYS_OPTIONS = {
48
+ ESCHER_MIXED_OPTIONS = {
49
49
  algo_prefix: 'EMS', vendor_key: 'EMS', hash_algo: 'SHA256', auth_header_name: 'Authorization', date_header_name: 'Date', clock_skew: 10
50
50
  }
51
51
 
52
+ ESCHER_EMARSYS_OPTIONS = ESCHER_MIXED_OPTIONS.merge(auth_header_name: 'X-Ems-Auth', date_header_name: 'X-Ems-Date')
53
+
52
54
  GOOD_AUTH_HEADER = 'AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470'
53
55
 
54
56
  # noinspection RubyStringKeysInHashInspection
@@ -98,17 +100,44 @@ describe 'Escher' do
98
100
  test_suites.each do |suite, tests|
99
101
  tests.each do |test|
100
102
  it "should calculate auth header for #{test} in #{suite}" do
101
- method, request_uri, body, headers, date, host = read_request(suite, test)
103
+ method, request_uri, body, headers, date = read_request(suite, test)
102
104
  escher = Escher.new('us-east-1/host/aws4_request', ESCHER_AWS4_OPTIONS.merge(current_time: Time.parse(date)))
103
105
  headers_to_sign = headers.map {|k| k[0].downcase }
104
- auth_header = escher.generate_auth_header(client, method, host, request_uri, body, headers, headers_to_sign)
106
+ auth_header = escher.generate_auth_header(client, method, request_uri, body, headers, headers_to_sign)
105
107
  expect(auth_header).to eq(fixture(suite, test, 'authz'))
106
108
  end
107
109
  end
108
110
  end
109
111
 
112
+ it 'should sign request' do
113
+ escher = Escher.new('us-east-1/iam/aws4_request', ESCHER_EMARSYS_OPTIONS.merge(current_time: Time.parse('20110909T233600Z')))
114
+ client = { :api_key_id => 'AKIDEXAMPLE', :api_secret => 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' }
115
+
116
+ input_headers = {
117
+ 'content-type' => 'application/x-www-form-urlencoded; charset=utf-8'
118
+ }
119
+
120
+ expected_headers = {
121
+ 'content-type' => 'application/x-www-form-urlencoded; charset=utf-8',
122
+ 'host' => 'iam.amazonaws.com',
123
+ 'x-ems-date' => '20110909T233600Z',
124
+ 'x-ems-auth' => 'EMS-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/iam/aws4_request, SignedHeaders=content-type;host;x-ems-date, Signature=f36c21c6e16a71a6e8dc56673ad6354aeef49c577a22fd58a190b5fcf8891dbd',
125
+ }
126
+ headers_to_sign = %w(content-type)
127
+
128
+ request = {
129
+ method: 'POST',
130
+ uri: 'http://iam.amazonaws.com/',
131
+ body: 'Action=ListUsers&Version=2010-05-08',
132
+ headers: input_headers,
133
+ }
134
+
135
+ downcase = escher.sign!(request, client, headers_to_sign)[:headers].map { |k, v| { k.downcase => v } }.reduce({}, &:merge)
136
+ expect(downcase).to eq expected_headers
137
+ end
138
+
110
139
  it 'should generate presigned url' do
111
- escher = Escher.new('us-east-1/host/aws4_request', ESCHER_EMARSYS_OPTIONS.merge(current_time: Time.parse('2011/05/11 12:00:00 UTC')))
140
+ escher = Escher.new('us-east-1/host/aws4_request', ESCHER_MIXED_OPTIONS.merge(current_time: Time.parse('2011/05/11 12:00:00 UTC')))
112
141
  expected_url =
113
142
  'http://example.com/something?foo=bar&' + 'baz=barbaz&' +
114
143
  'X-EMS-Algorithm=EMS-HMAC-SHA256&' +
@@ -123,7 +152,7 @@ describe 'Escher' do
123
152
  end
124
153
 
125
154
  it 'should validate presigned url' do
126
- escher = Escher.new('us-east-1/host/aws4_request', ESCHER_EMARSYS_OPTIONS.merge(current_time: Time.parse('2011/05/12 21:59:00 UTC')))
155
+ escher = Escher.new('us-east-1/host/aws4_request', ESCHER_MIXED_OPTIONS.merge(current_time: Time.parse('2011/05/12 21:59:00 UTC')))
127
156
  presigned_uri =
128
157
  '/something?foo=bar&' + 'baz=barbaz&' +
129
158
  'X-EMS-Algorithm=EMS-HMAC-SHA256&' +
@@ -143,7 +172,7 @@ describe 'Escher' do
143
172
  end
144
173
 
145
174
  it 'should validate expiration' do
146
- escher = Escher.new('us-east-1/host/aws4_request', ESCHER_EMARSYS_OPTIONS.merge(current_time: Time.parse('2011/05/12 22:20:00 UTC')))
175
+ escher = Escher.new('us-east-1/host/aws4_request', ESCHER_MIXED_OPTIONS.merge(current_time: Time.parse('2011/05/12 22:20:00 UTC')))
147
176
  presigned_uri =
148
177
  '/something?foo=bar&' + 'baz=barbaz&' +
149
178
  'X-EMS-Algorithm=EMS-HMAC-SHA256&' +
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: escher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andras Barthazi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-17 00:00:00.000000000 Z
11
+ date: 2014-09-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler