api-auth 2.0.1 → 2.1.0
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/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
|