api-auth 1.5.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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