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.
- checksums.yaml +4 -4
- data/.gitignore +10 -44
- data/.rubocop.yml +102 -0
- data/.travis.yml +1 -0
- data/Appraisals +8 -0
- data/CHANGELOG.md +8 -1
- data/Gemfile +3 -0
- data/README.md +33 -5
- data/VERSION +1 -1
- data/api_auth.gemspec +17 -17
- data/gemfiles/rails_23.gemfile +3 -0
- data/gemfiles/rails_30.gemfile +3 -0
- data/gemfiles/rails_31.gemfile +5 -0
- data/gemfiles/rails_32.gemfile +5 -0
- data/gemfiles/rails_4.gemfile +2 -0
- data/gemfiles/rails_41.gemfile +2 -0
- data/gemfiles/rails_42.gemfile +2 -0
- data/lib/api-auth.rb +1 -1
- data/lib/api_auth/base.rb +21 -25
- data/lib/api_auth/errors.rb +4 -3
- data/lib/api_auth/headers.rb +11 -27
- data/lib/api_auth/helpers.rb +2 -6
- data/lib/api_auth/railtie.rb +5 -50
- data/lib/api_auth/request_drivers/action_controller.rb +7 -13
- data/lib/api_auth/request_drivers/action_dispatch.rb +0 -6
- data/lib/api_auth/request_drivers/curb.rb +8 -14
- data/lib/api_auth/request_drivers/faraday.rb +11 -21
- data/lib/api_auth/request_drivers/httpi.rb +8 -14
- data/lib/api_auth/request_drivers/net_http.rb +8 -14
- data/lib/api_auth/request_drivers/rack.rb +10 -16
- data/lib/api_auth/request_drivers/rest_client.rb +9 -15
- data/spec/api_auth_spec.rb +90 -88
- data/spec/headers_spec.rb +69 -84
- data/spec/helpers_spec.rb +7 -9
- data/spec/railtie_spec.rb +42 -72
- data/spec/request_drivers/action_controller_spec.rb +53 -55
- data/spec/request_drivers/action_dispatch_spec.rb +52 -55
- data/spec/request_drivers/curb_spec.rb +25 -28
- data/spec/request_drivers/faraday_spec.rb +54 -56
- data/spec/request_drivers/httpi_spec.rb +42 -48
- data/spec/request_drivers/net_http_spec.rb +51 -53
- data/spec/request_drivers/rack_spec.rb +58 -60
- data/spec/request_drivers/rest_client_spec.rb +86 -89
- data/spec/spec_helper.rb +9 -9
- metadata +4 -11
- data/Gemfile.lock +0 -115
- data/gemfiles/rails_23.gemfile.lock +0 -70
- data/gemfiles/rails_30.gemfile.lock +0 -92
- data/gemfiles/rails_31.gemfile.lock +0 -98
- data/gemfiles/rails_32.gemfile.lock +0 -97
- data/gemfiles/rails_4.gemfile.lock +0 -94
- data/gemfiles/rails_41.gemfile.lock +0 -98
- data/gemfiles/rails_42.gemfile.lock +0 -115
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0fd8e9563fd57370a49c2c3b909432df2047bca
|
4
|
+
data.tar.gz: 4e3ca050145a2e8271e904f852ac43ad608dd5e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 717a5e94e609715659eb3355c062436962ba93fb0352d05041fe85604fb4cd7bbd3d4c460595c944c7a14fba2705960637026b2d66d8b5d63a328c845c96e9b8
|
7
|
+
data.tar.gz: 8edeaa5acf7c890900531441ea137bbf59264ec99862896bd2f168232899b9451d34930813a21bfbe50d761ad1e41f84eb431ead00d5620fc56e1aaffa042632
|
data/.gitignore
CHANGED
@@ -1,44 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
data/.rubocop.yml
ADDED
@@ -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
|
+
|
data/.travis.yml
CHANGED
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
|
data/CHANGELOG.md
CHANGED
@@ -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
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[](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
|
-
###
|
146
|
+
### Flexirest
|
132
147
|
|
133
|
-
ApiAuth also works with [
|
134
|
-
Simply add this configuration to your
|
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
|
-
|
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
|
+
2.0.0
|
data/api_auth.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path(
|
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 = [
|
11
|
-
s.email =
|
10
|
+
s.authors = ['Mauricio Gomes']
|
11
|
+
s.email = 'mauricio@edge14.com'
|
12
12
|
|
13
|
-
s.add_development_dependency
|
14
|
-
s.add_development_dependency
|
15
|
-
s.add_development_dependency
|
16
|
-
s.add_development_dependency
|
17
|
-
s.add_development_dependency
|
18
|
-
s.add_development_dependency
|
19
|
-
s.add_development_dependency
|
20
|
-
s.add_development_dependency
|
21
|
-
s.add_development_dependency
|
22
|
-
s.add_development_dependency
|
23
|
-
s.add_development_dependency
|
24
|
-
s.add_development_dependency
|
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 = [
|
28
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
29
|
+
s.require_paths = ['lib']
|
30
30
|
end
|
data/gemfiles/rails_23.gemfile
CHANGED
@@ -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 => "../"
|
data/gemfiles/rails_30.gemfile
CHANGED
@@ -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 => "../"
|
data/gemfiles/rails_31.gemfile
CHANGED
@@ -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 => "../"
|
data/gemfiles/rails_32.gemfile
CHANGED
@@ -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 => "../"
|
data/gemfiles/rails_4.gemfile
CHANGED
data/gemfiles/rails_41.gemfile
CHANGED
data/gemfiles/rails_42.gemfile
CHANGED
data/lib/api-auth.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
# So you can require "api-auth" instead of "api_auth"
|
2
|
-
require
|
2
|
+
require 'api_auth'
|
data/lib/api_auth/base.rb
CHANGED
@@ -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, :
|
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[
|
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
|
-
|
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
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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
|
-
|
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[
|
90
|
-
|
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 ==
|
94
|
+
header_sig == calculated_sig
|
94
95
|
end
|
95
96
|
|
96
97
|
def hmac_signature(headers, secret_key, options)
|
97
|
-
|
98
|
-
|
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
|
-
"
|
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
|