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.
- 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
|
[![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
|
-
###
|
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
|