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 +4 -4
- data/lib/escher/base.rb +20 -20
- data/lib/escher/request.rb +7 -1
- data/lib/escher/version.rb +1 -1
- data/spec/escher_spec.rb +35 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba40c7a7b12bb5aec126c7151b4a8cf81eaa3f51
|
4
|
+
data.tar.gz: 3fa09ffdec0d12b2bb7deaaf9aa30cecc23dfe63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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!(
|
25
|
-
|
26
|
-
|
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.
|
29
|
-
|
30
|
-
request.
|
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,
|
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),
|
data/lib/escher/request.rb
CHANGED
@@ -3,7 +3,9 @@ class EscherRequest
|
|
3
3
|
|
4
4
|
def initialize(request)
|
5
5
|
@request = request
|
6
|
-
|
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
|
data/lib/escher/version.rb
CHANGED
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
|
-
|
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
|
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,
|
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',
|
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',
|
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',
|
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.
|
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-
|
11
|
+
date: 2014-09-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|