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
data/lib/api_auth/errors.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
module ApiAuth
|
2
|
-
|
3
2
|
# :nodoc:
|
4
3
|
class ApiAuthError < StandardError; end
|
5
|
-
|
4
|
+
|
6
5
|
# Raised when the HTTP request object passed is not supported
|
7
6
|
class UnknownHTTPRequest < ApiAuthError; end
|
8
|
-
|
7
|
+
|
8
|
+
# Raised when the client request digest is not the same as the server
|
9
|
+
class InvalidRequestDigest < ApiAuthError; end
|
9
10
|
end
|
data/lib/api_auth/headers.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
module ApiAuth
|
2
|
-
|
3
2
|
# Builds the canonical string given a request object.
|
4
3
|
class Headers
|
5
|
-
|
6
4
|
include RequestDrivers
|
7
5
|
|
8
6
|
def initialize(request)
|
@@ -36,46 +34,32 @@ module ApiAuth
|
|
36
34
|
HttpiRequest.new(request)
|
37
35
|
when /Faraday::Request/
|
38
36
|
FaradayRequest.new(request)
|
39
|
-
else
|
40
|
-
nil
|
41
37
|
end
|
42
38
|
|
43
39
|
return new_request if new_request
|
44
|
-
return RackRequest.new(request) if request.
|
45
|
-
raise UnknownHTTPRequest, "#{request.class
|
40
|
+
return RackRequest.new(request) if request.is_a?(Rack::Request)
|
41
|
+
raise UnknownHTTPRequest, "#{request.class} is not yet supported."
|
46
42
|
end
|
47
43
|
private :initialize_request_driver
|
48
44
|
|
49
45
|
# Returns the request timestamp
|
50
46
|
def timestamp
|
51
|
-
|
47
|
+
@request.timestamp
|
52
48
|
end
|
53
49
|
|
54
|
-
|
55
|
-
def canonical_string_without_http_method
|
56
|
-
[ @request.content_type,
|
57
|
-
@request.content_md5,
|
58
|
-
parse_uri(@request.request_uri),
|
59
|
-
@request.timestamp
|
60
|
-
].join(",")
|
61
|
-
end
|
62
|
-
|
63
|
-
# temp backwards compatibility
|
64
|
-
alias_method :canonical_string, :canonical_string_without_http_method
|
65
|
-
|
66
|
-
def canonical_string_with_http_method(override_method = nil)
|
50
|
+
def canonical_string(override_method = nil)
|
67
51
|
request_method = override_method || @request.http_method
|
68
52
|
|
69
53
|
if request_method.nil?
|
70
|
-
raise ArgumentError,
|
54
|
+
raise ArgumentError, 'unable to determine the http method from the request, please supply an override'
|
71
55
|
end
|
72
56
|
|
73
|
-
[
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
].join(
|
57
|
+
[request_method.upcase,
|
58
|
+
@request.content_type,
|
59
|
+
@request.content_md5,
|
60
|
+
parse_uri(@request.request_uri),
|
61
|
+
@request.timestamp
|
62
|
+
].join(',')
|
79
63
|
end
|
80
64
|
|
81
65
|
# Returns the authorization header from the request's headers
|
data/lib/api_auth/helpers.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
module ApiAuth
|
2
|
-
|
3
2
|
module Helpers # :nodoc:
|
4
|
-
|
5
3
|
def b64_encode(string)
|
6
4
|
if Base64.respond_to?(:strict_encode64)
|
7
5
|
Base64.strict_encode64(string)
|
8
6
|
else
|
9
7
|
# Fall back to stripping out newlines on Ruby 1.8.
|
10
|
-
Base64.encode64(string).
|
8
|
+
Base64.encode64(string).delete("\n")
|
11
9
|
end
|
12
10
|
end
|
13
11
|
|
@@ -22,10 +20,8 @@ module ApiAuth
|
|
22
20
|
# Capitalizes the keys of a hash
|
23
21
|
def capitalize_keys(hsh)
|
24
22
|
capitalized_hash = {}
|
25
|
-
hsh.each_pair {|k,v| capitalized_hash[k.to_s.upcase] = v }
|
23
|
+
hsh.each_pair { |k, v| capitalized_hash[k.to_s.upcase] = v }
|
26
24
|
capitalized_hash
|
27
25
|
end
|
28
|
-
|
29
26
|
end
|
30
|
-
|
31
27
|
end
|
data/lib/api_auth/railtie.rb
CHANGED
@@ -1,13 +1,9 @@
|
|
1
1
|
module ApiAuth
|
2
|
-
|
3
2
|
# Integration with Rails
|
4
3
|
#
|
5
4
|
class Rails # :nodoc:
|
6
|
-
|
7
5
|
module ControllerMethods # :nodoc:
|
8
|
-
|
9
6
|
module InstanceMethods # :nodoc:
|
10
|
-
|
11
7
|
def get_api_access_id_from_request
|
12
8
|
ApiAuth.access_id(request)
|
13
9
|
end
|
@@ -15,31 +11,15 @@ module ApiAuth
|
|
15
11
|
def api_authenticated?(secret_key)
|
16
12
|
ApiAuth.authentic?(request, secret_key)
|
17
13
|
end
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
unless defined?(ActionController)
|
22
|
-
begin
|
23
|
-
require 'rubygems'
|
24
|
-
gem 'actionpack'
|
25
|
-
gem 'activesupport'
|
26
|
-
require 'action_controller'
|
27
|
-
require 'active_support'
|
28
|
-
rescue LoadError
|
29
|
-
nil
|
30
|
-
end
|
31
14
|
end
|
32
15
|
|
33
16
|
if defined?(ActionController::Base)
|
34
17
|
ActionController::Base.send(:include, ControllerMethods::InstanceMethods)
|
35
18
|
end
|
36
|
-
|
37
19
|
end # ControllerMethods
|
38
20
|
|
39
21
|
module ActiveResourceExtension # :nodoc:
|
40
|
-
|
41
22
|
module ActiveResourceApiAuth # :nodoc:
|
42
|
-
|
43
23
|
def self.included(base)
|
44
24
|
base.extend(ClassMethods)
|
45
25
|
|
@@ -47,24 +27,17 @@ module ApiAuth
|
|
47
27
|
base.class_attribute :hmac_access_id
|
48
28
|
base.class_attribute :hmac_secret_key
|
49
29
|
base.class_attribute :use_hmac
|
50
|
-
base.class_attribute :sign_with_http_method
|
51
30
|
else
|
52
31
|
base.class_inheritable_accessor :hmac_access_id
|
53
32
|
base.class_inheritable_accessor :hmac_secret_key
|
54
33
|
base.class_inheritable_accessor :use_hmac
|
55
|
-
base.class_inheritable_accessor :sign_with_http_method
|
56
34
|
end
|
57
|
-
|
58
35
|
end
|
59
36
|
|
60
37
|
module ClassMethods
|
61
|
-
|
62
38
|
def with_api_auth(access_id, secret_key, options = {})
|
63
|
-
sign_with_http_method = options[:sign_with_http_method] || false
|
64
|
-
|
65
39
|
self.hmac_access_id = access_id
|
66
40
|
self.hmac_secret_key = secret_key
|
67
|
-
self.sign_with_http_method = sign_with_http_method
|
68
41
|
self.use_hmac = true
|
69
42
|
|
70
43
|
class << self
|
@@ -74,26 +47,22 @@ module ApiAuth
|
|
74
47
|
|
75
48
|
def connection_with_auth(refresh = false)
|
76
49
|
c = connection_without_auth(refresh)
|
77
|
-
c.hmac_access_id =
|
78
|
-
c.hmac_secret_key =
|
79
|
-
c.use_hmac =
|
80
|
-
c.sign_with_http_method = self.sign_with_http_method
|
50
|
+
c.hmac_access_id = hmac_access_id
|
51
|
+
c.hmac_secret_key = hmac_secret_key
|
52
|
+
c.use_hmac = use_hmac
|
81
53
|
c
|
82
54
|
end
|
83
|
-
|
84
55
|
end # class methods
|
85
56
|
|
86
57
|
module InstanceMethods
|
87
58
|
end
|
88
|
-
|
89
59
|
end # BaseApiAuth
|
90
60
|
|
91
61
|
module Connection
|
92
|
-
|
93
62
|
def self.included(base)
|
94
63
|
base.send :alias_method_chain, :request, :auth
|
95
64
|
base.class_eval do
|
96
|
-
attr_accessor :hmac_secret_key, :hmac_access_id, :use_hmac
|
65
|
+
attr_accessor :hmac_secret_key, :hmac_access_id, :use_hmac
|
97
66
|
end
|
98
67
|
end
|
99
68
|
|
@@ -102,7 +71,7 @@ module ApiAuth
|
|
102
71
|
h = arguments.last
|
103
72
|
tmp = "Net::HTTP::#{method.to_s.capitalize}".constantize.new(path, h)
|
104
73
|
tmp.body = arguments[0] if arguments.length > 1
|
105
|
-
ApiAuth.sign!(tmp, hmac_access_id, hmac_secret_key
|
74
|
+
ApiAuth.sign!(tmp, hmac_access_id, hmac_secret_key)
|
106
75
|
arguments.last['Content-MD5'] = tmp['Content-MD5'] if tmp['Content-MD5']
|
107
76
|
arguments.last['DATE'] = tmp['DATE']
|
108
77
|
arguments.last['Authorization'] = tmp['Authorization']
|
@@ -110,26 +79,12 @@ module ApiAuth
|
|
110
79
|
|
111
80
|
request_without_auth(method, path, *arguments)
|
112
81
|
end
|
113
|
-
|
114
82
|
end # Connection
|
115
83
|
|
116
|
-
unless defined?(ActiveResource)
|
117
|
-
begin
|
118
|
-
require 'rubygems'
|
119
|
-
gem 'activeresource'
|
120
|
-
require 'active_resource'
|
121
|
-
rescue LoadError
|
122
|
-
nil
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
84
|
if defined?(ActiveResource)
|
127
85
|
ActiveResource::Base.send(:include, ActiveResourceApiAuth)
|
128
86
|
ActiveResource::Connection.send(:include, Connection)
|
129
87
|
end
|
130
|
-
|
131
88
|
end # ActiveResourceExtension
|
132
|
-
|
133
89
|
end # Rails
|
134
|
-
|
135
90
|
end # ApiAuth
|
@@ -1,9 +1,6 @@
|
|
1
1
|
module ApiAuth
|
2
|
-
|
3
2
|
module RequestDrivers # :nodoc:
|
4
|
-
|
5
3
|
class ActionControllerRequest # :nodoc:
|
6
|
-
|
7
4
|
include ApiAuth::Helpers
|
8
5
|
|
9
6
|
def initialize(request)
|
@@ -13,7 +10,7 @@ module ApiAuth
|
|
13
10
|
end
|
14
11
|
|
15
12
|
def set_auth_header(header)
|
16
|
-
@request.env[
|
13
|
+
@request.env['Authorization'] = header
|
17
14
|
fetch_headers
|
18
15
|
@request
|
19
16
|
end
|
@@ -25,7 +22,7 @@ module ApiAuth
|
|
25
22
|
|
26
23
|
def populate_content_md5
|
27
24
|
if @request.put? || @request.post?
|
28
|
-
@request.env[
|
25
|
+
@request.env['Content-MD5'] = calculated_md5
|
29
26
|
fetch_headers
|
30
27
|
end
|
31
28
|
end
|
@@ -48,12 +45,12 @@ module ApiAuth
|
|
48
45
|
|
49
46
|
def content_type
|
50
47
|
value = find_header(%w(CONTENT-TYPE CONTENT_TYPE HTTP_CONTENT_TYPE))
|
51
|
-
value.nil? ?
|
48
|
+
value.nil? ? '' : value
|
52
49
|
end
|
53
50
|
|
54
51
|
def content_md5
|
55
52
|
value = find_header(%w(CONTENT-MD5 CONTENT_MD5 HTTP_CONTENT_MD5))
|
56
|
-
value.nil? ?
|
53
|
+
value.nil? ? '' : value
|
57
54
|
end
|
58
55
|
|
59
56
|
def request_uri
|
@@ -67,21 +64,18 @@ module ApiAuth
|
|
67
64
|
|
68
65
|
def timestamp
|
69
66
|
value = find_header(%w(DATE HTTP_DATE))
|
70
|
-
value.nil? ?
|
67
|
+
value.nil? ? '' : value
|
71
68
|
end
|
72
69
|
|
73
70
|
def authorization_header
|
74
71
|
find_header %w(Authorization AUTHORIZATION HTTP_AUTHORIZATION)
|
75
72
|
end
|
76
73
|
|
77
|
-
|
74
|
+
private
|
78
75
|
|
79
76
|
def find_header(keys)
|
80
|
-
keys.map {|key| @headers[key] }.compact.first
|
77
|
+
keys.map { |key| @headers[key] }.compact.first
|
81
78
|
end
|
82
|
-
|
83
79
|
end
|
84
|
-
|
85
80
|
end
|
86
|
-
|
87
81
|
end
|
@@ -1,9 +1,6 @@
|
|
1
1
|
module ApiAuth
|
2
|
-
|
3
2
|
module RequestDrivers # :nodoc:
|
4
|
-
|
5
3
|
class CurbRequest # :nodoc:
|
6
|
-
|
7
4
|
include ApiAuth::Helpers
|
8
5
|
|
9
6
|
def initialize(request)
|
@@ -13,13 +10,13 @@ module ApiAuth
|
|
13
10
|
end
|
14
11
|
|
15
12
|
def set_auth_header(header)
|
16
|
-
@request.headers
|
13
|
+
@request.headers['Authorization'] = header
|
17
14
|
fetch_headers
|
18
15
|
@request
|
19
16
|
end
|
20
17
|
|
21
18
|
def populate_content_md5
|
22
|
-
nil #doesn't appear to be possible
|
19
|
+
nil # doesn't appear to be possible
|
23
20
|
end
|
24
21
|
|
25
22
|
def md5_mismatch?
|
@@ -36,12 +33,12 @@ module ApiAuth
|
|
36
33
|
|
37
34
|
def content_type
|
38
35
|
value = find_header(%w(CONTENT-TYPE CONTENT_TYPE HTTP_CONTENT_TYPE))
|
39
|
-
value.nil? ?
|
36
|
+
value.nil? ? '' : value
|
40
37
|
end
|
41
38
|
|
42
39
|
def content_md5
|
43
40
|
value = find_header(%w(CONTENT-MD5 CONTENT_MD5))
|
44
|
-
value.nil? ?
|
41
|
+
value.nil? ? '' : value
|
45
42
|
end
|
46
43
|
|
47
44
|
def request_uri
|
@@ -49,27 +46,24 @@ module ApiAuth
|
|
49
46
|
end
|
50
47
|
|
51
48
|
def set_date
|
52
|
-
@request.headers
|
49
|
+
@request.headers['DATE'] = Time.now.utc.httpdate
|
53
50
|
fetch_headers
|
54
51
|
end
|
55
52
|
|
56
53
|
def timestamp
|
57
54
|
value = find_header(%w(DATE HTTP_DATE))
|
58
|
-
value.nil? ?
|
55
|
+
value.nil? ? '' : value
|
59
56
|
end
|
60
57
|
|
61
58
|
def authorization_header
|
62
59
|
find_header %w(Authorization AUTHORIZATION HTTP_AUTHORIZATION)
|
63
60
|
end
|
64
61
|
|
65
|
-
|
62
|
+
private
|
66
63
|
|
67
64
|
def find_header(keys)
|
68
|
-
keys.map {|key| @headers[key] }.compact.first
|
65
|
+
keys.map { |key| @headers[key] }.compact.first
|
69
66
|
end
|
70
|
-
|
71
67
|
end
|
72
|
-
|
73
68
|
end
|
74
|
-
|
75
69
|
end
|
@@ -1,9 +1,6 @@
|
|
1
1
|
module ApiAuth
|
2
|
-
|
3
2
|
module RequestDrivers # :nodoc:
|
4
|
-
|
5
3
|
class FaradayRequest # :nodoc:
|
6
|
-
|
7
4
|
include ApiAuth::Helpers
|
8
5
|
|
9
6
|
def initialize(request)
|
@@ -13,29 +10,25 @@ module ApiAuth
|
|
13
10
|
end
|
14
11
|
|
15
12
|
def set_auth_header(header)
|
16
|
-
@request.headers
|
13
|
+
@request.headers['Authorization'] = header
|
17
14
|
fetch_headers
|
18
15
|
@request
|
19
16
|
end
|
20
17
|
|
21
18
|
def calculated_md5
|
22
|
-
|
23
|
-
body = @request.body
|
24
|
-
else
|
25
|
-
body = ''
|
26
|
-
end
|
19
|
+
body = @request.body ? @request.body : ''
|
27
20
|
md5_base64digest(body)
|
28
21
|
end
|
29
22
|
|
30
23
|
def populate_content_md5
|
31
|
-
if
|
32
|
-
@request.headers[
|
24
|
+
if %w(POST PUT).include?(@request.method.to_s.upcase)
|
25
|
+
@request.headers['Content-MD5'] = calculated_md5
|
33
26
|
fetch_headers
|
34
27
|
end
|
35
28
|
end
|
36
29
|
|
37
30
|
def md5_mismatch?
|
38
|
-
if
|
31
|
+
if %w(POST PUT).include?(@request.method.to_s.upcase)
|
39
32
|
calculated_md5 != content_md5
|
40
33
|
else
|
41
34
|
false
|
@@ -52,12 +45,12 @@ module ApiAuth
|
|
52
45
|
|
53
46
|
def content_type
|
54
47
|
value = find_header(%w(CONTENT-TYPE CONTENT_TYPE HTTP_CONTENT_TYPE))
|
55
|
-
value.nil? ?
|
48
|
+
value.nil? ? '' : value
|
56
49
|
end
|
57
50
|
|
58
51
|
def content_md5
|
59
52
|
value = find_header(%w(CONTENT-MD5 CONTENT_MD5 HTTP-CONTENT-MD5 HTTP_CONTENT_MD5))
|
60
|
-
value.nil? ?
|
53
|
+
value.nil? ? '' : value
|
61
54
|
end
|
62
55
|
|
63
56
|
def request_uri
|
@@ -68,27 +61,24 @@ module ApiAuth
|
|
68
61
|
end
|
69
62
|
|
70
63
|
def set_date
|
71
|
-
@request.headers
|
64
|
+
@request.headers['DATE'] = Time.now.utc.httpdate
|
72
65
|
fetch_headers
|
73
66
|
end
|
74
67
|
|
75
68
|
def timestamp
|
76
69
|
value = find_header(%w(DATE HTTP_DATE))
|
77
|
-
value.nil? ?
|
70
|
+
value.nil? ? '' : value
|
78
71
|
end
|
79
72
|
|
80
73
|
def authorization_header
|
81
74
|
find_header %w(Authorization AUTHORIZATION HTTP_AUTHORIZATION)
|
82
75
|
end
|
83
76
|
|
84
|
-
|
77
|
+
private
|
85
78
|
|
86
79
|
def find_header(keys)
|
87
|
-
keys.map {|key| @headers[key] }.compact.first
|
80
|
+
keys.map { |key| @headers[key] }.compact.first
|
88
81
|
end
|
89
|
-
|
90
82
|
end
|
91
|
-
|
92
83
|
end
|
93
|
-
|
94
84
|
end
|