api-auth 1.5.0 → 2.0.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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +10 -44
  3. data/.rubocop.yml +102 -0
  4. data/.travis.yml +1 -0
  5. data/Appraisals +8 -0
  6. data/CHANGELOG.md +8 -1
  7. data/Gemfile +3 -0
  8. data/README.md +33 -5
  9. data/VERSION +1 -1
  10. data/api_auth.gemspec +17 -17
  11. data/gemfiles/rails_23.gemfile +3 -0
  12. data/gemfiles/rails_30.gemfile +3 -0
  13. data/gemfiles/rails_31.gemfile +5 -0
  14. data/gemfiles/rails_32.gemfile +5 -0
  15. data/gemfiles/rails_4.gemfile +2 -0
  16. data/gemfiles/rails_41.gemfile +2 -0
  17. data/gemfiles/rails_42.gemfile +2 -0
  18. data/lib/api-auth.rb +1 -1
  19. data/lib/api_auth/base.rb +21 -25
  20. data/lib/api_auth/errors.rb +4 -3
  21. data/lib/api_auth/headers.rb +11 -27
  22. data/lib/api_auth/helpers.rb +2 -6
  23. data/lib/api_auth/railtie.rb +5 -50
  24. data/lib/api_auth/request_drivers/action_controller.rb +7 -13
  25. data/lib/api_auth/request_drivers/action_dispatch.rb +0 -6
  26. data/lib/api_auth/request_drivers/curb.rb +8 -14
  27. data/lib/api_auth/request_drivers/faraday.rb +11 -21
  28. data/lib/api_auth/request_drivers/httpi.rb +8 -14
  29. data/lib/api_auth/request_drivers/net_http.rb +8 -14
  30. data/lib/api_auth/request_drivers/rack.rb +10 -16
  31. data/lib/api_auth/request_drivers/rest_client.rb +9 -15
  32. data/spec/api_auth_spec.rb +90 -88
  33. data/spec/headers_spec.rb +69 -84
  34. data/spec/helpers_spec.rb +7 -9
  35. data/spec/railtie_spec.rb +42 -72
  36. data/spec/request_drivers/action_controller_spec.rb +53 -55
  37. data/spec/request_drivers/action_dispatch_spec.rb +52 -55
  38. data/spec/request_drivers/curb_spec.rb +25 -28
  39. data/spec/request_drivers/faraday_spec.rb +54 -56
  40. data/spec/request_drivers/httpi_spec.rb +42 -48
  41. data/spec/request_drivers/net_http_spec.rb +51 -53
  42. data/spec/request_drivers/rack_spec.rb +58 -60
  43. data/spec/request_drivers/rest_client_spec.rb +86 -89
  44. data/spec/spec_helper.rb +9 -9
  45. metadata +4 -11
  46. data/Gemfile.lock +0 -115
  47. data/gemfiles/rails_23.gemfile.lock +0 -70
  48. data/gemfiles/rails_30.gemfile.lock +0 -92
  49. data/gemfiles/rails_31.gemfile.lock +0 -98
  50. data/gemfiles/rails_32.gemfile.lock +0 -97
  51. data/gemfiles/rails_4.gemfile.lock +0 -94
  52. data/gemfiles/rails_41.gemfile.lock +0 -98
  53. data/gemfiles/rails_42.gemfile.lock +0 -115
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 79cbdc86c27b9748d521ca8e0efe2038efa0641b
4
- data.tar.gz: 2cc39d41382118e60496a8c9ca9693fb6a4baf02
3
+ metadata.gz: a0fd8e9563fd57370a49c2c3b909432df2047bca
4
+ data.tar.gz: 4e3ca050145a2e8271e904f852ac43ad608dd5e9
5
5
  SHA512:
6
- metadata.gz: f6f7a9271d443ffc86bb0cbb3f674febbe860832429e677a54c7e03cea418597768b746b8ce90f51789be20f21f97011be1e6ff50f1ba4ec3e665cc4351c6da7
7
- data.tar.gz: 28873d74e56b7e7cb9b8aee01811841971a79a2d3fa459ca399ac28088495e9e29f26d35216369db5fd626e9f8917877dbcc53d40cb08a23c66bb48f5a6f4975
6
+ metadata.gz: 717a5e94e609715659eb3355c062436962ba93fb0352d05041fe85604fb4cd7bbd3d4c460595c944c7a14fba2705960637026b2d66d8b5d63a328c845c96e9b8
7
+ data.tar.gz: 8edeaa5acf7c890900531441ea137bbf59264ec99862896bd2f168232899b9451d34930813a21bfbe50d761ad1e41f84eb431ead00d5620fc56e1aaffa042632
data/.gitignore CHANGED
@@ -1,44 +1,10 @@
1
- .rvmrc
2
-
3
- # rcov generated
4
- coverage
5
-
6
- # rdoc generated
7
- rdoc
8
-
9
- # yard generated
10
- doc
11
- .yardoc
12
-
13
- # bundler
14
- .bundle
15
-
16
- # jeweler generated
17
- pkg
18
-
19
- # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
20
- #
21
- # * Create a file at ~/.gitignore
22
- # * Include files you want ignored
23
- # * Run: git config --global core.excludesfile ~/.gitignore
24
- #
25
- # After doing this, these files will be ignored in all your git projects,
26
- # saving you from having to 'pollute' every project you touch with them
27
- #
28
- # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
29
- #
30
- # For MacOS:
31
- #
32
- #.DS_Store
33
- #
34
- # For TextMate
35
- #*.tmproj
36
- #tmtags
37
- #
38
- # For emacs:
39
- #*~
40
- #\#*
41
- #.\#*
42
- #
43
- # For vim:
44
- #*.swp
1
+ /.bundle
2
+ /.ruby-version
3
+ /.rvmrc
4
+ /Gemfile.lock
5
+ /rdoc
6
+ /pkg
7
+ /coverage
8
+ /doc
9
+ /.yardoc
10
+ gemfiles/*.lock
@@ -0,0 +1,102 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2016-02-10 17:06:30 +0100 using RuboCop version 0.37.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: AllowSafeAssignment.
11
+ Lint/AssignmentInCondition:
12
+ Exclude:
13
+ - 'lib/api_auth/base.rb'
14
+
15
+ # Offense count: 1
16
+ Lint/UselessAssignment:
17
+ Exclude:
18
+ - 'spec/request_drivers/rest_client_spec.rb'
19
+
20
+ # Offense count: 2
21
+ Metrics/AbcSize:
22
+ Max: 25
23
+
24
+ # Offense count: 2
25
+ Metrics/CyclomaticComplexity:
26
+ Max: 13
27
+
28
+ # Offense count: 74
29
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
30
+ # URISchemes: http, https
31
+ Metrics/LineLength:
32
+ Max: 137
33
+
34
+ # Offense count: 4
35
+ # Configuration parameters: CountComments.
36
+ Metrics/MethodLength:
37
+ Max: 30
38
+
39
+ # Offense count: 1
40
+ Metrics/PerceivedComplexity:
41
+ Max: 8
42
+
43
+ # Offense count: 8
44
+ Style/AccessorMethodName:
45
+ Exclude:
46
+ - 'lib/api_auth/railtie.rb'
47
+ - 'lib/api_auth/request_drivers/action_controller.rb'
48
+ - 'lib/api_auth/request_drivers/curb.rb'
49
+ - 'lib/api_auth/request_drivers/faraday.rb'
50
+ - 'lib/api_auth/request_drivers/httpi.rb'
51
+ - 'lib/api_auth/request_drivers/net_http.rb'
52
+ - 'lib/api_auth/request_drivers/rack.rb'
53
+ - 'lib/api_auth/request_drivers/rest_client.rb'
54
+
55
+ # Offense count: 4
56
+ Style/Documentation:
57
+ Exclude:
58
+ - 'spec/**/*'
59
+ - 'test/**/*'
60
+ - 'lib/api_auth/railtie.rb'
61
+ - 'lib/api_auth/request_drivers/rest_client.rb'
62
+
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
+ # Offense count: 1
71
+ # Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts.
72
+ Style/FileName:
73
+ Exclude:
74
+ - '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
+
@@ -1,5 +1,6 @@
1
1
  language: ruby
2
2
  sudo: false
3
+ cache: bundler
3
4
  rvm:
4
5
  - 1.8.7-p374
5
6
  - 1.9.3
data/Appraisals CHANGED
@@ -20,22 +20,30 @@ appraise "rails-32" do
20
20
  gem "actionpack", "~> 3.2.17"
21
21
  gem "activeresource", "~> 3.2.17"
22
22
  gem "activesupport", "~> 3.2.17"
23
+ gem "httpi", "< 2.3"
24
+ gem "i18n", "< 0.7.0"
25
+ gem "rack-cache", "< 1.3"
23
26
  end
24
27
 
25
28
  appraise "rails-31" do
26
29
  gem "actionpack", "~> 3.1.0"
27
30
  gem "activeresource", "~> 3.1.0"
28
31
  gem "activesupport", "~> 3.1.0"
32
+ gem "httpi", "< 2.3"
33
+ gem "i18n", "< 0.7.0"
34
+ gem "rack-cache", "< 1.3"
29
35
  end
30
36
 
31
37
  appraise "rails-30" do
32
38
  gem "actionpack", "~> 3.0.20"
33
39
  gem "activeresource", "~> 3.0.20"
34
40
  gem "activesupport", "~> 3.0.20"
41
+ gem "httpi", "< 2.3"
35
42
  end
36
43
 
37
44
  appraise "rails-23" do
38
45
  gem "actionpack", "~> 2.3.2"
39
46
  gem "activeresource", "~> 2.3.2"
40
47
  gem "activesupport", "~> 2.3.2"
48
+ gem "httpi", "< 2.3"
41
49
  end
@@ -1,3 +1,10 @@
1
+ # 2.0.0 (2016-05-11)
2
+ - IMPORTANT: 2.0.0 is backwards incompatible with the default settings of v1.x
3
+ v2.0.0 always includes the http method in the canonical string.
4
+ You can use the upgrade strategy in v1.4.x and above to migrate to v2.0.0
5
+ without any down time. Please see the 1.4.0 release nodes for more info
6
+ - Added support for other digest algorithms like SHA-256 (#98 fwininger)
7
+
1
8
  # 1.5.0 (2016-01-21)
2
9
  - Added a sign_with_http_method configuration option to the ActiveResource
3
10
  rails tie to correspond to passing the `:with_http_method => true` into
@@ -7,7 +14,7 @@
7
14
  - Fixed an issue where getters wouldn't immediately have the correct value after
8
15
  setting a date or content md5 in some of the request drivers (#91)
9
16
 
10
- # 1.4 (2015-12-16)
17
+ # 1.4.0 (2015-12-16)
11
18
 
12
19
  ## IMPORTANT SECURITY FIX (with backwards compatible fallback)
13
20
 
data/Gemfile CHANGED
@@ -1,2 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
+
4
+ gem "rake", "< 11.0", :platforms => :ruby_18
5
+ gem "tins", "< 1.7", :platforms => :ruby_19 # amatch dependency
data/README.md CHANGED
@@ -2,7 +2,7 @@
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: See [CHANGELOG.md](/CHANGELOG.md) for security update information
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
6
 
7
7
  Logins and passwords are for humans. Communication between applications need to
8
8
  be protected through different means.
@@ -115,6 +115,21 @@ into the sign! method like so:
115
115
  @signed_request = ApiAuth.sign!(@request, @access_id, @secret_key, :override_http_method => "PUT")
116
116
  ```
117
117
 
118
+ If you want to use another digest existing in `OpenSSL::Digest`,
119
+ you can pass the http method as an option into the sign! method like so:
120
+
121
+ ``` ruby
122
+ @signed_request = ApiAuth.sign!(@request, @access_id, @secret_key, :digest => 'sha256')
123
+ ```
124
+
125
+ With the `digest` option, the `Authorization` header will be change from:
126
+
127
+ Authorization = APIAuth 'client access id':'signature'
128
+
129
+ to:
130
+
131
+ Authorization = APIAuth-HMAC-DIGEST_NAME 'client access id':'signature'
132
+
118
133
  ### ActiveResource Clients
119
134
 
120
135
  ApiAuth can transparently protect your ActiveResource communications with a
@@ -128,13 +143,13 @@ single configuration line:
128
143
 
129
144
  This will automatically sign all outgoing ActiveResource requests from your app.
130
145
 
131
- ### Active Rest Client
146
+ ### Flexirest
132
147
 
133
- ApiAuth also works with [ActiveRestClient](https://github.com/whichdigital/active-rest-client) in a very similar way.
134
- Simply add this configuration to your ActiveRestClient initializer in your app and it will automatically sign all outgoing requests.
148
+ ApiAuth also works with [Flexirest](https://github.com/andyjeffries/flexirest) (used to be ActiveRestClient, but that is now unsupported) in a very similar way.
149
+ Simply add this configuration to your Flexirest initializer in your app and it will automatically sign all outgoing requests.
135
150
 
136
151
  ``` ruby
137
- ActiveRestClient::Base.api_auth_credentials(@access_id, @secret_key)
152
+ Flexirest::Base.api_auth_credentials(@access_id, @secret_key)
138
153
  ```
139
154
 
140
155
  ## Server
@@ -154,6 +169,19 @@ To validate whether or not a request is authentic:
154
169
  ApiAuth.authentic?(signed_request, secret_key)
155
170
  ```
156
171
 
172
+ The `authentic?` method uses the digest specified in the `Authorization` header.
173
+ For exemple SHA256 for:
174
+
175
+ Authorization = APIAuth-HMAC-SHA256 'client access id':'signature'
176
+
177
+ And by default SHA1 if the HMAC-DIGEST is not specified.
178
+
179
+ If you want to force the usage of another digest method, you should pass it as an option parameter:
180
+
181
+ ``` ruby
182
+ ApiAuth.authentic?(signed_request, secret_key, :digest => 'sha256')
183
+ ```
184
+
157
185
  If your server is a Rails app, the signed request will be the `request` object.
158
186
 
159
187
  In order to obtain the secret key for the client, you first need to look up the
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.5.0
1
+ 2.0.0
@@ -1,5 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
2
+ $:.push File.expand_path('../lib', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = %q{api-auth}
@@ -7,24 +7,24 @@ Gem::Specification.new do |s|
7
7
  s.description = %q{Full HMAC auth implementation for use in your gems and Rails apps.}
8
8
  s.homepage = %q{https://github.com/mgomes/api_auth}
9
9
  s.version = File.read(File.join(File.dirname(__FILE__), 'VERSION'))
10
- s.authors = ["Mauricio Gomes"]
11
- s.email = "mauricio@edge14.com"
10
+ s.authors = ['Mauricio Gomes']
11
+ s.email = 'mauricio@edge14.com'
12
12
 
13
- s.add_development_dependency "appraisal"
14
- s.add_development_dependency "rake"
15
- s.add_development_dependency "amatch"
16
- 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"
19
- s.add_development_dependency "activeresource", "~> 4.0"
20
- s.add_development_dependency "rest-client", "~> 1.6.0"
21
- s.add_development_dependency "curb", "~> 0.8.1"
22
- s.add_development_dependency "httpi"
23
- s.add_development_dependency "faraday"
24
- s.add_development_dependency "multipart-post", "~> 2.0"
13
+ s.add_development_dependency 'appraisal'
14
+ s.add_development_dependency 'rake'
15
+ s.add_development_dependency 'amatch'
16
+ 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'
19
+ s.add_development_dependency 'activeresource', '~> 4.0'
20
+ s.add_development_dependency 'rest-client', '~> 1.6.0'
21
+ s.add_development_dependency 'curb', '~> 0.8.1'
22
+ s.add_development_dependency 'httpi'
23
+ s.add_development_dependency 'faraday'
24
+ s.add_development_dependency 'multipart-post', '~> 2.0'
25
25
 
26
26
  s.files = `git ls-files`.split("\n")
27
27
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
28
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
29
- s.require_paths = ["lib"]
28
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
29
+ s.require_paths = ['lib']
30
30
  end
@@ -2,8 +2,11 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "rake", "< 11.0", :platforms => :ruby_18
6
+ gem "tins", "< 1.7", :platforms => :ruby_19
5
7
  gem "actionpack", "~> 2.3.2"
6
8
  gem "activeresource", "~> 2.3.2"
7
9
  gem "activesupport", "~> 2.3.2"
10
+ gem "httpi", "< 2.3"
8
11
 
9
12
  gemspec :path => "../"
@@ -2,8 +2,11 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "rake", "< 11.0", :platforms => :ruby_18
6
+ gem "tins", "< 1.7", :platforms => :ruby_19
5
7
  gem "actionpack", "~> 3.0.20"
6
8
  gem "activeresource", "~> 3.0.20"
7
9
  gem "activesupport", "~> 3.0.20"
10
+ gem "httpi", "< 2.3"
8
11
 
9
12
  gemspec :path => "../"
@@ -2,8 +2,13 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "rake", "< 11.0", :platforms => :ruby_18
6
+ gem "tins", "< 1.7", :platforms => :ruby_19
5
7
  gem "actionpack", "~> 3.1.0"
6
8
  gem "activeresource", "~> 3.1.0"
7
9
  gem "activesupport", "~> 3.1.0"
10
+ gem "httpi", "< 2.3"
11
+ gem "i18n", "< 0.7.0"
12
+ gem "rack-cache", "< 1.3"
8
13
 
9
14
  gemspec :path => "../"
@@ -2,8 +2,13 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "rake", "< 11.0", :platforms => :ruby_18
6
+ gem "tins", "< 1.7", :platforms => :ruby_19
5
7
  gem "actionpack", "~> 3.2.17"
6
8
  gem "activeresource", "~> 3.2.17"
7
9
  gem "activesupport", "~> 3.2.17"
10
+ gem "httpi", "< 2.3"
11
+ gem "i18n", "< 0.7.0"
12
+ gem "rack-cache", "< 1.3"
8
13
 
9
14
  gemspec :path => "../"
@@ -2,6 +2,8 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "rake", "< 11.0", :platforms => :ruby_18
6
+ gem "tins", "< 1.7", :platforms => :ruby_19
5
7
  gem "actionpack", "~> 4.0.4"
6
8
  gem "activeresource", "~> 4.0.0"
7
9
  gem "activesupport", "~> 4.0.4"
@@ -2,6 +2,8 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "rake", "< 11.0", :platforms => :ruby_18
6
+ gem "tins", "< 1.7", :platforms => :ruby_19
5
7
  gem "actionpack", "~> 4.1.0"
6
8
  gem "activeresource", "~> 4.0.0"
7
9
  gem "activesupport", "~> 4.1.0"
@@ -2,6 +2,8 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem "rake", "< 11.0", :platforms => :ruby_18
6
+ gem "tins", "< 1.7", :platforms => :ruby_19
5
7
  gem "actionpack", "~> 4.2.0"
6
8
  gem "activeresource", "~> 4.0.0"
7
9
  gem "activesupport", "~> 4.2.0"
@@ -1,2 +1,2 @@
1
1
  # So you can require "api-auth" instead of "api_auth"
2
- require "api_auth"
2
+ require 'api_auth'
@@ -8,9 +8,7 @@
8
8
  # Rails ActiveResource, it will integrate with that. It will even generate the
9
9
  # secret keys necessary for your clients to sign their requests.
10
10
  module ApiAuth
11
-
12
11
  class << self
13
-
14
12
  include Helpers
15
13
 
16
14
  # Signs an HTTP request using the client's access id and secret key.
@@ -23,7 +21,7 @@ module ApiAuth
23
21
  #
24
22
  # secret_key: assigned secret key that is known to both parties
25
23
  def sign!(request, access_id, secret_key, options = {})
26
- options = { :override_http_method => nil, :with_http_method => false }.merge(options)
24
+ options = { :override_http_method => nil, :digest => 'sha1' }.merge(options)
27
25
  headers = Headers.new(request)
28
26
  headers.calculate_md5
29
27
  headers.set_date
@@ -34,9 +32,11 @@ module ApiAuth
34
32
  # secret key. Returns true if the request is authentic and false otherwise.
35
33
  def authentic?(request, secret_key, options = {})
36
34
  return false if secret_key.nil?
35
+
37
36
  options = { :override_http_method => nil }.merge(options)
38
37
 
39
38
  headers = Headers.new(request)
39
+
40
40
  if headers.md5_mismatch?
41
41
  false
42
42
  elsif !signatures_match?(headers, secret_key, options)
@@ -52,7 +52,7 @@ module ApiAuth
52
52
  def access_id(request)
53
53
  headers = Headers.new(request)
54
54
  if match_data = parse_auth_header(headers.authorization_header)
55
- return match_data[1]
55
+ return match_data[2]
56
56
  end
57
57
 
58
58
  nil
@@ -67,50 +67,46 @@ module ApiAuth
67
67
  b64_encode(Digest::SHA2.new(512).digest(random_bytes))
68
68
  end
69
69
 
70
- private
70
+ private
71
71
 
72
- AUTH_HEADER_PATTERN = /APIAuth ([^:]+):(.+)$/
72
+ AUTH_HEADER_PATTERN = /APIAuth(?:-HMAC-(MD[245]|SHA(?:1|224|256|384|512)*))? ([^:]+):(.+)$/
73
73
 
74
74
  def request_too_old?(headers)
75
75
  # 900 seconds is 15 minutes
76
- begin
77
- Time.httpdate(headers.timestamp).utc < (Time.now.utc - 900)
78
- rescue ArgumentError
79
- true
80
- end
76
+
77
+ Time.httpdate(headers.timestamp).utc < (Time.now.utc - 900)
78
+ rescue ArgumentError
79
+ true
81
80
  end
82
81
 
83
82
  def signatures_match?(headers, secret_key, options)
84
83
  match_data = parse_auth_header(headers.authorization_header)
85
84
  return false unless match_data
86
85
 
87
- options = options.merge(:with_http_method => true)
86
+ digest = match_data[1].blank? ? 'SHA1' : match_data[1].upcase
87
+ raise InvalidRequestDigest if !options[:digest].nil? && !options[:digest].casecmp(digest).zero?
88
+
89
+ options = { :digest => digest }.merge(options)
88
90
 
89
- header_sig = match_data[2]
90
- calculated_sig_no_http = hmac_signature(headers, secret_key, {})
91
- calculated_sig_with_http = hmac_signature(headers, secret_key, options)
91
+ header_sig = match_data[3]
92
+ calculated_sig = hmac_signature(headers, secret_key, options)
92
93
 
93
- header_sig == calculated_sig_with_http || header_sig == calculated_sig_no_http
94
+ header_sig == calculated_sig
94
95
  end
95
96
 
96
97
  def hmac_signature(headers, secret_key, options)
97
- if options[:with_http_method]
98
- canonical_string = headers.canonical_string_with_http_method(options[:override_http_method])
99
- else
100
- canonical_string = headers.canonical_string
101
- end
102
- digest = OpenSSL::Digest.new('sha1')
98
+ canonical_string = headers.canonical_string(options[:override_http_method])
99
+ digest = OpenSSL::Digest.new(options[:digest])
103
100
  b64_encode(OpenSSL::HMAC.digest(digest, secret_key, canonical_string))
104
101
  end
105
102
 
106
103
  def auth_header(headers, access_id, secret_key, options)
107
- "APIAuth #{access_id}:#{hmac_signature(headers, secret_key, options)}"
104
+ hmac_string = "-HMAC-#{options[:digest].upcase}" unless options[:digest] == 'sha1'
105
+ "APIAuth#{hmac_string} #{access_id}:#{hmac_signature(headers, secret_key, options)}"
108
106
  end
109
107
 
110
108
  def parse_auth_header(auth_header)
111
109
  AUTH_HEADER_PATTERN.match(auth_header)
112
110
  end
113
-
114
111
  end # class methods
115
-
116
112
  end # ApiAuth