api-auth 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9ee2a233ac1efcbf1af8b4028fde060ab2de42d5
4
- data.tar.gz: 32dc7e2f7fb53759ff4d043e03f53914e4944345
2
+ SHA256:
3
+ metadata.gz: 51fee150bf8e85fbaa3195608e96a25ad4ef7cb19bcc026137c1831c94f652c1
4
+ data.tar.gz: 7c0aeeefdf36f93e53cef4ac76f0015efa587c5a7b572dafe6670276d786e92a
5
5
  SHA512:
6
- metadata.gz: 5264828dfb7ec5743f4f74bb2b13ac6e8e002f1addfb448bb2e6ded240fe7ef13e0d1d2bc4646c3f568a33d25a32ff32ea4b070ce59c30d6431a8a451350cb2c
7
- data.tar.gz: ffed44efe3245f7c74e9a6b76057ec1de088c16805d7f96fd10061d9babb940680e3b4927bc9aa480cd9aa8d03955c60c8fce1c6f596528f2bc4aaa9d2289c13
6
+ metadata.gz: 4cf7349cdbed677337b82e3c0ad87ce1271ce0a92c65a9bda8514dadde6c3a6fd40e962fc9b23cb937e0b1b804d456930d6ddeb245d5d3d5ed021639c077a3c8
7
+ data.tar.gz: c4935420257b03f3f90460c7caffb64d0da2792f9793c24c02bf00e7abdc1a80a509d73c3ed86a95098de3cb5aaeb96776e383a537dfab3233fd043a6077c928
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /doc
9
9
  /.yardoc
10
10
  gemfiles/*.lock
11
+ /.idea
@@ -12,11 +12,6 @@ Lint/AssignmentInCondition:
12
12
  Exclude:
13
13
  - 'lib/api_auth/base.rb'
14
14
 
15
- # Offense count: 1
16
- Lint/UselessAssignment:
17
- Exclude:
18
- - 'spec/request_drivers/rest_client_spec.rb'
19
-
20
15
  # Offense count: 2
21
16
  Metrics/AbcSize:
22
17
  Max: 25
@@ -60,43 +55,9 @@ Style/Documentation:
60
55
  - 'lib/api_auth/railtie.rb'
61
56
  - 'lib/api_auth/request_drivers/rest_client.rb'
62
57
 
63
- # Offense count: 1
64
- # Cop supports --auto-correct.
65
- # Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
66
- Style/ExtraSpacing:
67
- Exclude:
68
- - 'lib/api_auth/railtie.rb'
69
-
70
58
  # Offense count: 1
71
59
  # Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts.
72
60
  Style/FileName:
73
61
  Exclude:
74
62
  - 'lib/api-auth.rb'
75
-
76
- # Offense count: 110
77
- # Cop supports --auto-correct.
78
- # Configuration parameters: SupportedStyles, UseHashRocketsWithSymbolValues.
79
- # SupportedStyles: ruby19, ruby19_no_mixed_keys, hash_rockets
80
- Style/HashSyntax:
81
- EnforcedStyle: hash_rockets
82
-
83
- # Offense count: 4
84
- # Cop supports --auto-correct.
85
- # Configuration parameters: PreferredDelimiters.
86
- Style/PercentLiteralDelimiters:
87
- Exclude:
88
- - 'api_auth.gemspec'
89
-
90
- # Offense count: 1
91
- # Cop supports --auto-correct.
92
- # Configuration parameters: EnforcedStyle, SupportedStyles.
93
- # SupportedStyles: use_perl_names, use_english_names
94
- Style/SpecialGlobalVars:
95
- Enabled: false
96
-
97
- # Offense count: 4
98
- # Cop supports --auto-correct.
99
- Style/UnneededPercentQ:
100
- Exclude:
101
- - 'api_auth.gemspec'
102
-
63
+ - 'Appraisals'
@@ -2,64 +2,33 @@ language: ruby
2
2
  sudo: false
3
3
  cache: bundler
4
4
  rvm:
5
- - 1.8.7-p374
6
- - 1.9.3
7
5
  - 2.1.9
8
- - 2.2.5
9
- - 2.3.1
6
+ - 2.2.6
7
+ - 2.3.3
8
+ - 2.4.1
10
9
  gemfile:
11
- - gemfiles/rails_23.gemfile
12
- - gemfiles/rails_30.gemfile
13
- - gemfiles/rails_31.gemfile
14
- - gemfiles/rails_32.gemfile
15
10
  - gemfiles/rails_4.gemfile
16
11
  - gemfiles/rails_41.gemfile
17
12
  - gemfiles/rails_42.gemfile
18
13
  - gemfiles/rails_5.gemfile
14
+ - gemfiles/rails_51.gemfile
19
15
  env:
20
16
  - TEST_SUITE=rake
21
17
 
18
+ before_install:
19
+ - gem update bundler
20
+
22
21
  script:
23
22
  - bundle exec $TEST_SUITE
24
23
 
25
24
  matrix:
26
25
  exclude:
27
- - rvm: 1.8.7-p374
28
- gemfile: gemfiles/rails_4.gemfile
29
- - rvm: 1.8.7-p374
30
- gemfile: gemfiles/rails_41.gemfile
31
- - rvm: 1.8.7-p374
32
- gemfile: gemfiles/rails_42.gemfile
33
- - rvm: 1.8.7-p374
34
- gemfile: gemfiles/rails_5.gemfile
35
- - rvm: 1.9.3
36
- gemfile: gemfiles/rails_5.gemfile
37
- - rvm: 2.1.9
38
- gemfile: gemfiles/rails_23.gemfile
39
- - rvm: 2.1.9
40
- gemfile: gemfiles/rails_30.gemfile
41
- - rvm: 2.1.9
42
- gemfile: gemfiles/rails_31.gemfile
43
26
  - rvm: 2.1.9
44
27
  gemfile: gemfiles/rails_5.gemfile
45
- - rvm: 2.2.5
46
- gemfile: gemfiles/rails_23.gemfile
47
- - rvm: 2.2.5
48
- gemfile: gemfiles/rails_30.gemfile
49
- - rvm: 2.2.5
50
- gemfile: gemfiles/rails_31.gemfile
51
- - rvm: 2.2.5
52
- gemfile: gemfiles/rails_32.gemfile
53
- - rvm: 2.3.1
54
- gemfile: gemfiles/rails_23.gemfile
55
- - rvm: 2.3.1
56
- gemfile: gemfiles/rails_30.gemfile
57
- - rvm: 2.3.1
58
- gemfile: gemfiles/rails_31.gemfile
59
- - rvm: 2.3.1
60
- gemfile: gemfiles/rails_32.gemfile
28
+ - rvm: 2.1.9
29
+ gemfile: gemfiles/rails_51.gemfile
61
30
  include:
62
- - rvm: 2.3.1
31
+ - rvm: 2.4.1
63
32
  gemfile: gemfiles/rails_5.gemfile
64
33
  env: TEST_SUITE="rubocop lib/ spec/"
65
34
 
data/Appraisals CHANGED
@@ -1,49 +1,23 @@
1
- appraise "rails-42" do
2
- gem "actionpack", "~> 4.2.0"
3
- gem "activeresource", "~> 4.0.0"
4
- gem "activesupport", "~> 4.2.0"
1
+ appraise 'rails-5' do
2
+ gem 'actionpack', '~> 5.0.2'
3
+ gem 'activeresource', '~> 5.0.2'
4
+ gem 'activesupport', '~> 5.0.2'
5
5
  end
6
6
 
7
- appraise "rails-41" do
8
- gem "actionpack", "~> 4.1.0"
9
- gem "activeresource", "~> 4.0.0"
10
- gem "activesupport", "~> 4.1.0"
7
+ appraise 'rails-42' do
8
+ gem 'actionpack', '~> 4.2.0'
9
+ gem 'activeresource', '~> 4.0.0'
10
+ gem 'activesupport', '~> 4.2.0'
11
11
  end
12
12
 
13
- appraise "rails-4" do
14
- gem "actionpack", "~> 4.0.4"
15
- gem "activeresource", "~> 4.0.0"
16
- gem "activesupport", "~> 4.0.4"
13
+ appraise 'rails-41' do
14
+ gem 'actionpack', '~> 4.1.0'
15
+ gem 'activeresource', '~> 4.0.0'
16
+ gem 'activesupport', '~> 4.1.0'
17
17
  end
18
18
 
19
- appraise "rails-32" do
20
- gem "actionpack", "~> 3.2.17"
21
- gem "activeresource", "~> 3.2.17"
22
- gem "activesupport", "~> 3.2.17"
23
- gem "httpi", "< 2.3"
24
- gem "i18n", "< 0.7.0"
25
- gem "rack-cache", "< 1.3"
26
- end
27
-
28
- appraise "rails-31" do
29
- gem "actionpack", "~> 3.1.0"
30
- gem "activeresource", "~> 3.1.0"
31
- gem "activesupport", "~> 3.1.0"
32
- gem "httpi", "< 2.3"
33
- gem "i18n", "< 0.7.0"
34
- gem "rack-cache", "< 1.3"
35
- end
36
-
37
- appraise "rails-30" do
38
- gem "actionpack", "~> 3.0.20"
39
- gem "activeresource", "~> 3.0.20"
40
- gem "activesupport", "~> 3.0.20"
41
- gem "httpi", "< 2.3"
42
- end
43
-
44
- appraise "rails-23" do
45
- gem "actionpack", "~> 2.3.2"
46
- gem "activeresource", "~> 2.3.2"
47
- gem "activesupport", "~> 2.3.2"
48
- gem "httpi", "< 2.3"
19
+ appraise 'rails-4' do
20
+ gem 'actionpack', '~> 4.0.4'
21
+ gem 'activeresource', '~> 4.0.0'
22
+ gem 'activesupport', '~> 4.0.4'
49
23
  end
data/Gemfile CHANGED
@@ -1,7 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
- gem 'rake', '< 11.0', :platforms => :ruby_18
5
- gem 'tins', '< 1.7', :platforms => :ruby_19 # amatch dependency
6
-
7
- gem 'rubocop', :platforms => [:ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23]
4
+ gem 'rubocop', platforms: %i[ruby_20 ruby_21 ruby_22 ruby_23 ruby_24]
data/README.md CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/mgomes/api_auth.png?branch=master)](https://travis-ci.org/mgomes/api_auth)
4
4
 
5
- ## IMPORTANT: v2.0.0 is backwards incompatible with the default settings of v1.x to address a security vulnerability. See [CHANGELOG.md](/CHANGELOG.md) for security update information.
6
-
7
5
  Logins and passwords are for humans. Communication between applications need to
8
6
  be protected through different means.
9
7
 
@@ -51,6 +49,14 @@ minutes in order to avoid replay attacks.
51
49
  * [HMAC algorithm](http://en.wikipedia.org/wiki/HMAC)
52
50
  * [RFC 2104 (HMAC)](http://tools.ietf.org/html/rfc2104)
53
51
 
52
+ ## Requirement
53
+
54
+ v3.X require Ruby 2.X and if you use Rails at least Rails 4.0.
55
+
56
+ For older version of Ruby or Rails, please use ApiAuth v2.X.
57
+
58
+ **IMPORTANT: v2.0.0 is backwards incompatible with the default settings of v1.x to address a security vulnerability. See [CHANGELOG.md](/CHANGELOG.md) for security update information.**
59
+
54
60
  ## Install
55
61
 
56
62
  The gem doesn't have any dependencies outside of having a working OpenSSL
@@ -72,6 +78,7 @@ Here is the current list of supported request objects:
72
78
  * Curb (Curl::Easy)
73
79
  * RestClient
74
80
  * Faraday
81
+ * HTTParty
75
82
  * Httpi
76
83
 
77
84
  ### HTTP Client Objects
@@ -171,7 +178,7 @@ To validate whether or not a request is authentic:
171
178
  ```
172
179
 
173
180
  The `authentic?` method uses the digest specified in the `Authorization` header.
174
- For exemple SHA256 for:
181
+ For example SHA256 for:
175
182
 
176
183
  Authorization = APIAuth-HMAC-SHA256 'client access id':'signature'
177
184
 
@@ -183,6 +190,17 @@ If you want to force the usage of another digest method, you should pass it as a
183
190
  ApiAuth.authentic?(signed_request, secret_key, :digest => 'sha256')
184
191
  ```
185
192
 
193
+ For security, requests dated older or newer than a certain timespan are considered inauthentic.
194
+
195
+ This prevents old requests from being reused in replay attacks, and also ensures requests
196
+ can't be dated into the far future.
197
+
198
+ The default span is 15 minutes, but you can override this:
199
+
200
+ ```ruby
201
+ ApiAuth.authentic?(signed_request, secret_key, :clock_skew => 60) # or 1.minute in ActiveSupport
202
+ ```
203
+
186
204
  If your server is a Rails app, the signed request will be the `request` object.
187
205
 
188
206
  In order to obtain the secret key for the client, you first need to look up the
@@ -217,7 +235,13 @@ take care of all that for you.
217
235
 
218
236
  To run the tests:
219
237
 
220
- rake spec
238
+ Install the dependencies for a particular Rails version by specifying a gemfile in `gemfiles` directory:
239
+
240
+ BUNDLE_GEMFILE=gemfiles/rails_5.gemfile bundle install
241
+
242
+ Run the tests with those dependencies:
243
+
244
+ BUNDLE_GEMFILE=gemfiles/rails_5.gemfile bundle exec rake
221
245
 
222
246
  If you'd like to add support for additional HTTP clients, check out the already
223
247
  implemented drivers in `lib/api_auth/request_drivers` for reference. All of
data/Rakefile CHANGED
@@ -10,4 +10,4 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
10
10
  spec.pattern = FileList['spec/**/*_spec.rb']
11
11
  end
12
12
 
13
- task :default => :spec
13
+ task default: :spec
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.0
1
+ 2.2.0
@@ -1,11 +1,10 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path('../lib', __FILE__)
1
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
2
 
4
3
  Gem::Specification.new do |s|
5
- s.name = %q{api-auth}
6
- s.summary = %q{Simple HMAC authentication for your APIs}
7
- s.description = %q{Full HMAC auth implementation for use in your gems and Rails apps.}
8
- s.homepage = %q{https://github.com/mgomes/api_auth}
4
+ s.name = 'api-auth'
5
+ s.summary = 'Simple HMAC authentication for your APIs'
6
+ s.description = 'Full HMAC auth implementation for use in your gems and Rails apps.'
7
+ s.homepage = 'https://github.com/mgomes/api_auth'
9
8
  s.version = File.read(File.join(File.dirname(__FILE__), 'VERSION'))
10
9
  s.authors = ['Mauricio Gomes']
11
10
  s.email = 'mauricio@edge14.com'
@@ -14,15 +13,15 @@ Gem::Specification.new do |s|
14
13
  s.add_development_dependency 'rake'
15
14
  s.add_development_dependency 'amatch'
16
15
  s.add_development_dependency 'rspec', '~> 3.4'
17
- s.add_development_dependency 'actionpack', '< 5.0', '> 2.3.2'
18
- s.add_development_dependency 'activesupport', '< 5.0', '> 2.3.2'
16
+ s.add_development_dependency 'actionpack', '< 6.0', '> 4.0'
17
+ s.add_development_dependency 'activesupport', '< 6.0', '> 4.0'
19
18
  s.add_development_dependency 'activeresource', '~> 4.0'
20
19
  s.add_development_dependency 'rest-client', '~> 1.6.0'
21
20
  s.add_development_dependency 'curb', '~> 0.8.1'
22
21
  s.add_development_dependency 'httpi'
23
- faraday_version = RUBY_VERSION == '1.8.7' ? '< 0.10' : '>= 0.10'
24
- s.add_development_dependency 'faraday', faraday_version
22
+ s.add_development_dependency 'faraday', '>= 0.10'
25
23
  s.add_development_dependency 'multipart-post', '~> 2.0'
24
+ s.add_development_dependency 'httparty', '~> 0.13.0'
26
25
 
27
26
  s.files = `git ls-files`.split("\n")
28
27
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -2,9 +2,9 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "actionpack", "~> 5.0.0"
5
+ gem "actionpack", "~> 5.0.2"
6
6
  gem "activeresource", "~> 5.0.0", git: 'https://github.com/rails/activeresource.git'
7
- gem "activesupport", "~> 5.0.0"
7
+ gem "activesupport", "~> 5.0.2"
8
8
 
9
9
  gem "rubocop"
10
10
 
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "actionpack", "~> 5.1.1"
6
+ gem "activeresource", "~> 5.0.0", git: 'https://github.com/rails/activeresource.git'
7
+ gem "activesupport", "~> 5.1.1"
8
+
9
+ gemspec :path => "../"
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # api-auth is a Ruby gem designed to be used both in your client and server
3
2
  # HTTP-based applications. It implements the same authentication methods (HMAC)
4
3
  # used by Amazon Web Services.
@@ -21,7 +20,7 @@ module ApiAuth
21
20
  #
22
21
  # secret_key: assigned secret key that is known to both parties
23
22
  def sign!(request, access_id, secret_key, options = {})
24
- options = { :override_http_method => nil, :digest => 'sha1' }.merge(options)
23
+ options = { override_http_method: nil, digest: 'sha1' }.merge(options)
25
24
  headers = Headers.new(request)
26
25
  headers.calculate_md5
27
26
  headers.set_date
@@ -33,15 +32,18 @@ module ApiAuth
33
32
  def authentic?(request, secret_key, options = {})
34
33
  return false if secret_key.nil?
35
34
 
36
- options = { :override_http_method => nil }.merge(options)
35
+ options = { override_http_method: nil }.merge(options)
37
36
 
38
37
  headers = Headers.new(request)
39
38
 
39
+ # 900 seconds is 15 minutes
40
+ clock_skew = options.fetch(:clock_skew, 900)
41
+
40
42
  if headers.md5_mismatch?
41
43
  false
42
44
  elsif !signatures_match?(headers, secret_key, options)
43
45
  false
44
- elsif !request_within_time_window?(headers)
46
+ elsif !request_within_time_window?(headers, clock_skew)
45
47
  false
46
48
  else
47
49
  true
@@ -71,11 +73,9 @@ module ApiAuth
71
73
 
72
74
  AUTH_HEADER_PATTERN = /APIAuth(?:-HMAC-(MD5|SHA(?:1|224|256|384|512)?))? ([^:]+):(.+)$/
73
75
 
74
- def request_within_time_window?(headers)
75
- # 900 seconds is 15 minutes
76
-
77
- Time.httpdate(headers.timestamp).utc > (Time.now.utc - 900) &&
78
- Time.httpdate(headers.timestamp).utc < (Time.now.utc + 900)
76
+ def request_within_time_window?(headers, clock_skew)
77
+ Time.httpdate(headers.timestamp).utc > (Time.now.utc - clock_skew) &&
78
+ Time.httpdate(headers.timestamp).utc < (Time.now.utc + clock_skew)
79
79
  rescue ArgumentError
80
80
  false
81
81
  end
@@ -87,7 +87,7 @@ module ApiAuth
87
87
  digest = match_data[1].nil? ? 'SHA1' : match_data[1].upcase
88
88
  raise InvalidRequestDigest if !options[:digest].nil? && !options[:digest].casecmp(digest).zero?
89
89
 
90
- options = { :digest => digest }.merge(options)
90
+ options = { digest: digest }.merge(options)
91
91
 
92
92
  header_sig = match_data[3]
93
93
  calculated_sig = hmac_signature(headers, secret_key, options)
@@ -57,7 +57,7 @@ module ApiAuth
57
57
  [request_method.upcase,
58
58
  @request.content_type,
59
59
  @request.content_md5,
60
- parse_uri(@request.request_uri),
60
+ parse_uri(@request.original_uri || @request.request_uri),
61
61
  @request.timestamp].join(',')
62
62
  end
63
63
 
@@ -67,15 +67,15 @@ module ApiAuth
67
67
  end
68
68
 
69
69
  def set_date
70
- @request.set_date if @request.timestamp.empty?
70
+ @request.set_date if @request.timestamp.nil?
71
71
  end
72
72
 
73
73
  def calculate_md5
74
- @request.populate_content_md5 if @request.content_md5.empty?
74
+ @request.populate_content_md5 if @request.content_md5.nil?
75
75
  end
76
76
 
77
77
  def md5_mismatch?
78
- if @request.content_md5.empty?
78
+ if @request.content_md5.nil?
79
79
  false
80
80
  else
81
81
  @request.md5_mismatch?
@@ -93,12 +93,12 @@ module ApiAuth
93
93
 
94
94
  private
95
95
 
96
- URI_WITHOUT_HOST_REGEXP = %r{https?://[^,?/]*}
97
-
98
96
  def parse_uri(uri)
99
- uri_without_host = uri.gsub(URI_WITHOUT_HOST_REGEXP, '')
100
- return '/' if uri_without_host.empty?
101
- uri_without_host
97
+ parsed_uri = URI.parse(uri)
98
+
99
+ return parsed_uri.request_uri if parsed_uri.respond_to?(:request_uri)
100
+
101
+ uri.empty? ? '/' : uri
102
102
  end
103
103
  end
104
104
  end