api-auth 2.0.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +1 -0
- data/VERSION +1 -1
- data/api_auth.gemspec +2 -1
- data/lib/api_auth/base.rb +16 -6
- data/lib/api_auth/request_drivers/net_http.rb +1 -0
- data/spec/api_auth_spec.rb +19 -12
- data/spec/railtie_spec.rb +13 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ee2a233ac1efcbf1af8b4028fde060ab2de42d5
|
4
|
+
data.tar.gz: 32dc7e2f7fb53759ff4d043e03f53914e4944345
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5264828dfb7ec5743f4f74bb2b13ac6e8e002f1addfb448bb2e6ded240fe7ef13e0d1d2bc4646c3f568a33d25a32ff32ea4b070ce59c30d6431a8a451350cb2c
|
7
|
+
data.tar.gz: ffed44efe3245f7c74e9a6b76057ec1de088c16805d7f96fd10061d9babb940680e3b4927bc9aa480cd9aa8d03955c60c8fce1c6f596528f2bc4aaa9d2289c13
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# 2.1.0 (2016-12-22)
|
2
|
+
- Fixed a NoMethodError that might occur when using the NetHttp Driver (#130 grahamkenville)
|
3
|
+
- More securely compare signatures in a way that prevents timing attacks (#56 leishman, #133 will0)
|
4
|
+
- Remove support for MD2 and MD4 hashing algorithms since they are insecure (#134 will0)
|
5
|
+
- Disallow requests that are too far in the future to limit the time available for a brute force signature guess (#119 fwininger)
|
6
|
+
|
1
7
|
# 2.0.1 (2016-07-25)
|
2
8
|
- Support of `api_auth_options` in ActiveResource integration (#102 fwininger)
|
3
9
|
- Replace use of `#blank?` with `#nil?` to not depend on ActiveSupport (#114 packrat386)
|
data/README.md
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.0
|
1
|
+
2.1.0
|
data/api_auth.gemspec
CHANGED
@@ -20,7 +20,8 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.add_development_dependency 'rest-client', '~> 1.6.0'
|
21
21
|
s.add_development_dependency 'curb', '~> 0.8.1'
|
22
22
|
s.add_development_dependency 'httpi'
|
23
|
-
|
23
|
+
faraday_version = RUBY_VERSION == '1.8.7' ? '< 0.10' : '>= 0.10'
|
24
|
+
s.add_development_dependency 'faraday', faraday_version
|
24
25
|
s.add_development_dependency 'multipart-post', '~> 2.0'
|
25
26
|
|
26
27
|
s.files = `git ls-files`.split("\n")
|
data/lib/api_auth/base.rb
CHANGED
@@ -41,7 +41,7 @@ module ApiAuth
|
|
41
41
|
false
|
42
42
|
elsif !signatures_match?(headers, secret_key, options)
|
43
43
|
false
|
44
|
-
elsif
|
44
|
+
elsif !request_within_time_window?(headers)
|
45
45
|
false
|
46
46
|
else
|
47
47
|
true
|
@@ -69,14 +69,15 @@ module ApiAuth
|
|
69
69
|
|
70
70
|
private
|
71
71
|
|
72
|
-
AUTH_HEADER_PATTERN = /APIAuth(?:-HMAC-(
|
72
|
+
AUTH_HEADER_PATTERN = /APIAuth(?:-HMAC-(MD5|SHA(?:1|224|256|384|512)?))? ([^:]+):(.+)$/
|
73
73
|
|
74
|
-
def
|
74
|
+
def request_within_time_window?(headers)
|
75
75
|
# 900 seconds is 15 minutes
|
76
76
|
|
77
|
-
Time.httpdate(headers.timestamp).utc
|
77
|
+
Time.httpdate(headers.timestamp).utc > (Time.now.utc - 900) &&
|
78
|
+
Time.httpdate(headers.timestamp).utc < (Time.now.utc + 900)
|
78
79
|
rescue ArgumentError
|
79
|
-
|
80
|
+
false
|
80
81
|
end
|
81
82
|
|
82
83
|
def signatures_match?(headers, secret_key, options)
|
@@ -91,7 +92,16 @@ module ApiAuth
|
|
91
92
|
header_sig = match_data[3]
|
92
93
|
calculated_sig = hmac_signature(headers, secret_key, options)
|
93
94
|
|
94
|
-
header_sig
|
95
|
+
secure_equals?(header_sig, calculated_sig, secret_key)
|
96
|
+
end
|
97
|
+
|
98
|
+
def secure_equals?(m1, m2, key)
|
99
|
+
sha1_hmac(key, m1) == sha1_hmac(key, m2)
|
100
|
+
end
|
101
|
+
|
102
|
+
def sha1_hmac(key, message)
|
103
|
+
digest = OpenSSL::Digest.new('sha1')
|
104
|
+
OpenSSL::HMAC.digest(digest, key, message)
|
95
105
|
end
|
96
106
|
|
97
107
|
def hmac_signature(headers, secret_key, options)
|
data/spec/api_auth_spec.rb
CHANGED
@@ -75,37 +75,44 @@ describe 'ApiAuth' do
|
|
75
75
|
|
76
76
|
describe '.authentic?' do
|
77
77
|
let(:request) do
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
78
|
+
Net::HTTP::Put.new('/resource.xml?foo=bar&bar=foo',
|
79
|
+
'content-type' => 'text/plain',
|
80
|
+
'content-md5' => '1B2M2Y8AsgTpgAmY7PhCfg==',
|
81
|
+
'date' => Time.now.utc.httpdate)
|
82
|
+
end
|
82
83
|
|
83
|
-
|
84
|
-
|
85
|
-
|
84
|
+
let(:signed_request) do
|
85
|
+
signature = hmac('123', request)
|
86
|
+
request['Authorization'] = "APIAuth 1044:#{signature}"
|
87
|
+
request
|
86
88
|
end
|
87
89
|
|
88
90
|
it 'validates that the signature in the request header matches the way we sign it' do
|
89
|
-
expect(ApiAuth.authentic?(
|
91
|
+
expect(ApiAuth.authentic?(signed_request, '123')).to eq true
|
90
92
|
end
|
91
93
|
|
92
94
|
it 'fails to validate a non matching signature' do
|
93
|
-
expect(ApiAuth.authentic?(
|
95
|
+
expect(ApiAuth.authentic?(signed_request, '456')).to eq false
|
94
96
|
end
|
95
97
|
|
96
98
|
it 'fails to validate non matching md5' do
|
97
99
|
request['content-md5'] = '12345'
|
98
|
-
expect(ApiAuth.authentic?(
|
100
|
+
expect(ApiAuth.authentic?(signed_request, '123')).to eq false
|
99
101
|
end
|
100
102
|
|
101
103
|
it 'fails to validate expired requests' do
|
102
104
|
request['date'] = 16.minutes.ago.utc.httpdate
|
103
|
-
expect(ApiAuth.authentic?(
|
105
|
+
expect(ApiAuth.authentic?(signed_request, '123')).to eq false
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'fails to validate far future requests' do
|
109
|
+
request['date'] = 16.minutes.from_now.utc.httpdate
|
110
|
+
expect(ApiAuth.authentic?(signed_request, '123')).to eq false
|
104
111
|
end
|
105
112
|
|
106
113
|
it 'fails to validate if the date is invalid' do
|
107
114
|
request['date'] = '٢٠١٤-٠٩-٠٨ ١٦:٣١:١٤ +٠٣٠٠'
|
108
|
-
expect(ApiAuth.authentic?(
|
115
|
+
expect(ApiAuth.authentic?(signed_request, '123')).to eq false
|
109
116
|
end
|
110
117
|
|
111
118
|
it 'fails to validate if the request method differs' do
|
data/spec/railtie_spec.rb
CHANGED
@@ -73,7 +73,7 @@ describe 'Rails integration' do
|
|
73
73
|
expect(response.code).to eq('200')
|
74
74
|
end
|
75
75
|
|
76
|
-
it 'should forbid a request with properly signed headers but timestamp > 15 minutes' do
|
76
|
+
it 'should forbid a request with properly signed headers but timestamp > 15 minutes ago' do
|
77
77
|
request = if ActionController::TestRequest.respond_to?(:create)
|
78
78
|
ActionController::TestRequest.create
|
79
79
|
else
|
@@ -85,6 +85,18 @@ describe 'Rails integration' do
|
|
85
85
|
expect(response.code).to eq('401')
|
86
86
|
end
|
87
87
|
|
88
|
+
it 'should forbid a request with properly signed headers but timestamp > 15 minutes in the future' do
|
89
|
+
request = if ActionController::TestRequest.respond_to?(:create)
|
90
|
+
ActionController::TestRequest.create
|
91
|
+
else
|
92
|
+
ActionController::TestRequest.new
|
93
|
+
end
|
94
|
+
request.env['DATE'] = 'Mon, 23 Jan 2100 03:29:56 GMT'
|
95
|
+
ApiAuth.sign!(request, '1044', API_KEY_STORE['1044'])
|
96
|
+
response = generated_response(request, :index)
|
97
|
+
expect(response.code).to eq('401')
|
98
|
+
end
|
99
|
+
|
88
100
|
it "should insert a DATE header in the request when one hasn't been specified" do
|
89
101
|
request = if ActionController::TestRequest.respond_to?(:create)
|
90
102
|
ActionController::TestRequest.create
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: api-auth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mauricio Gomes
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: appraisal
|
@@ -168,14 +168,14 @@ dependencies:
|
|
168
168
|
requirements:
|
169
169
|
- - ">="
|
170
170
|
- !ruby/object:Gem::Version
|
171
|
-
version: '0'
|
171
|
+
version: '0.10'
|
172
172
|
type: :development
|
173
173
|
prerelease: false
|
174
174
|
version_requirements: !ruby/object:Gem::Requirement
|
175
175
|
requirements:
|
176
176
|
- - ">="
|
177
177
|
- !ruby/object:Gem::Version
|
178
|
-
version: '0'
|
178
|
+
version: '0.10'
|
179
179
|
- !ruby/object:Gem::Dependency
|
180
180
|
name: multipart-post
|
181
181
|
requirement: !ruby/object:Gem::Requirement
|
@@ -265,7 +265,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
265
265
|
version: '0'
|
266
266
|
requirements: []
|
267
267
|
rubyforge_project:
|
268
|
-
rubygems_version: 2.5.
|
268
|
+
rubygems_version: 2.5.2
|
269
269
|
signing_key:
|
270
270
|
specification_version: 4
|
271
271
|
summary: Simple HMAC authentication for your APIs
|