api-auth 2.1.0 → 2.2.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 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