bixby-auth 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/Gemfile +28 -0
- data/Gemfile.lock +245 -0
- data/LICENSE.txt +20 -0
- data/README.md +19 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/bixby-auth.gemspec +129 -0
- data/lib/api-auth.rb +2 -0
- data/lib/api_auth/base.rb +105 -0
- data/lib/api_auth/errors.rb +12 -0
- data/lib/api_auth/headers.rb +82 -0
- data/lib/api_auth/helpers.rb +39 -0
- data/lib/api_auth/railtie.rb +129 -0
- data/lib/api_auth/request_drivers/action_controller.rb +84 -0
- data/lib/api_auth/request_drivers/action_dispatch.rb +17 -0
- data/lib/api_auth/request_drivers/bixby_request.rb +65 -0
- data/lib/api_auth/request_drivers/curb.rb +72 -0
- data/lib/api_auth/request_drivers/httpi.rb +82 -0
- data/lib/api_auth/request_drivers/net_http.rb +98 -0
- data/lib/api_auth/request_drivers/rack.rb +88 -0
- data/lib/api_auth/request_drivers/rest_client.rb +98 -0
- data/lib/api_auth/request_drivers.rb +21 -0
- data/lib/api_auth.rb +10 -0
- data/lib/bixby-auth.rb +3 -0
- data/spec/api_auth_spec.rb +660 -0
- data/spec/application_helper.rb +2 -0
- data/spec/fixtures/upload.png +0 -0
- data/spec/headers_spec.rb +356 -0
- data/spec/helpers_spec.rb +14 -0
- data/spec/railtie_spec.rb +134 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/test_helper.rb +2 -0
- data/test/helper.rb +35 -0
- data/test/test_bixby-auth.rb +7 -0
- metadata +346 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
module ApiAuth
|
2
|
+
|
3
|
+
# Builds the canonical string given a request object.
|
4
|
+
class Headers
|
5
|
+
|
6
|
+
include RequestDrivers
|
7
|
+
|
8
|
+
def initialize(request)
|
9
|
+
@original_request = request
|
10
|
+
@request = initialize_request_driver(request)
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize_request_driver(request)
|
15
|
+
clazz = request.class.to_s
|
16
|
+
if RequestDrivers.drivers.include?(clazz) then
|
17
|
+
return RequestDrivers.drivers[clazz].new(request)
|
18
|
+
|
19
|
+
elsif clazz == "ActionController::TestRequest" then
|
20
|
+
# special handling for rails 3 vs 4
|
21
|
+
if defined?(ActionDispatch) then
|
22
|
+
return ActionDispatchRequest.new(request)
|
23
|
+
else
|
24
|
+
return ActionControllerRequest.new(request)
|
25
|
+
end
|
26
|
+
|
27
|
+
elsif Module.const_defined?(:Rack) && Rack.const_defined?(:Request) && request.kind_of?(Rack::Request) then
|
28
|
+
# this goes last because TestRequest is also a subclass of Rack::Request
|
29
|
+
return RackRequest.new(request)
|
30
|
+
end
|
31
|
+
|
32
|
+
raise UnknownHTTPRequest, "#{clazz} is not yet supported."
|
33
|
+
end
|
34
|
+
private :initialize_request_driver
|
35
|
+
|
36
|
+
# Returns the request timestamp
|
37
|
+
def timestamp
|
38
|
+
@request.timestamp
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns the canonical string computed from the request's headers
|
42
|
+
def canonical_string
|
43
|
+
[ @request.content_type,
|
44
|
+
@request.content_md5,
|
45
|
+
@request.request_uri.gsub(/https?:\/\/[^(,|\?|\/)]*/,''), # remove host
|
46
|
+
@request.timestamp
|
47
|
+
].join(",")
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the authorization header from the request's headers
|
51
|
+
def authorization_header
|
52
|
+
@request.authorization_header
|
53
|
+
end
|
54
|
+
|
55
|
+
def set_date
|
56
|
+
@request.set_date if @request.timestamp.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
def calculate_md5
|
60
|
+
@request.populate_content_md5 if @request.content_md5.empty?
|
61
|
+
end
|
62
|
+
|
63
|
+
def md5_mismatch?
|
64
|
+
if @request.content_md5.empty?
|
65
|
+
false
|
66
|
+
else
|
67
|
+
@request.md5_mismatch?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Sets the request's authorization header with the passed in value.
|
72
|
+
# The header should be the ApiAuth HMAC signature.
|
73
|
+
#
|
74
|
+
# This will return the original request object with the signed Authorization
|
75
|
+
# header already in place.
|
76
|
+
def sign_header(header)
|
77
|
+
@request.set_auth_header header
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ApiAuth
|
2
|
+
|
3
|
+
module Helpers # :nodoc:
|
4
|
+
|
5
|
+
def b64_encode(string)
|
6
|
+
if Base64.respond_to?(:strict_encode64)
|
7
|
+
Base64.strict_encode64(string)
|
8
|
+
else
|
9
|
+
# Fall back to stripping out newlines on Ruby 1.8.
|
10
|
+
Base64.encode64(string).gsub(/\n/, '')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def md5_base64digest(string)
|
15
|
+
if Digest::MD5.respond_to?(:base64digest)
|
16
|
+
Digest::MD5.base64digest(string)
|
17
|
+
else
|
18
|
+
b64_encode(Digest::MD5.digest(string))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Capitalizes the keys of a hash
|
23
|
+
def capitalize_keys(hsh)
|
24
|
+
capitalized_hash = {}
|
25
|
+
hsh.each_pair {|k,v| capitalized_hash[k.to_s.upcase] = v }
|
26
|
+
capitalized_hash
|
27
|
+
end
|
28
|
+
|
29
|
+
def time_as_httpdate
|
30
|
+
Helpers.time_as_httpdate
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.time_as_httpdate
|
34
|
+
Time.now.utc.strftime("%a, %d %b %Y %T GMT")
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module ApiAuth
|
2
|
+
|
3
|
+
# Integration with Rails
|
4
|
+
#
|
5
|
+
class Rails # :nodoc:
|
6
|
+
|
7
|
+
module ControllerMethods # :nodoc:
|
8
|
+
|
9
|
+
module InstanceMethods # :nodoc:
|
10
|
+
|
11
|
+
def get_api_access_id_from_request
|
12
|
+
ApiAuth.access_id(request)
|
13
|
+
end
|
14
|
+
|
15
|
+
def api_authenticated?(secret_key)
|
16
|
+
ApiAuth.authentic?(request, secret_key)
|
17
|
+
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
|
+
end
|
32
|
+
|
33
|
+
if defined?(ActionController::Base)
|
34
|
+
ActionController::Base.send(:include, ControllerMethods::InstanceMethods)
|
35
|
+
end
|
36
|
+
|
37
|
+
end # ControllerMethods
|
38
|
+
|
39
|
+
module ActiveResourceExtension # :nodoc:
|
40
|
+
|
41
|
+
module ActiveResourceApiAuth # :nodoc:
|
42
|
+
|
43
|
+
def self.included(base)
|
44
|
+
base.extend(ClassMethods)
|
45
|
+
|
46
|
+
if base.respond_to?('class_attribute')
|
47
|
+
base.class_attribute :hmac_access_id
|
48
|
+
base.class_attribute :hmac_secret_key
|
49
|
+
base.class_attribute :use_hmac
|
50
|
+
else
|
51
|
+
base.class_inheritable_accessor :hmac_access_id
|
52
|
+
base.class_inheritable_accessor :hmac_secret_key
|
53
|
+
base.class_inheritable_accessor :use_hmac
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
module ClassMethods
|
59
|
+
|
60
|
+
def with_api_auth(access_id, secret_key)
|
61
|
+
self.hmac_access_id = access_id
|
62
|
+
self.hmac_secret_key = secret_key
|
63
|
+
self.use_hmac = true
|
64
|
+
|
65
|
+
class << self
|
66
|
+
alias_method_chain :connection, :auth
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def connection_with_auth(refresh = false)
|
71
|
+
c = connection_without_auth(refresh)
|
72
|
+
c.hmac_access_id = self.hmac_access_id
|
73
|
+
c.hmac_secret_key = self.hmac_secret_key
|
74
|
+
c.use_hmac = self.use_hmac
|
75
|
+
c
|
76
|
+
end
|
77
|
+
|
78
|
+
end # class methods
|
79
|
+
|
80
|
+
module InstanceMethods
|
81
|
+
end
|
82
|
+
|
83
|
+
end # BaseApiAuth
|
84
|
+
|
85
|
+
module Connection
|
86
|
+
|
87
|
+
def self.included(base)
|
88
|
+
base.send :alias_method_chain, :request, :auth
|
89
|
+
base.class_eval do
|
90
|
+
attr_accessor :hmac_secret_key, :hmac_access_id, :use_hmac
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def request_with_auth(method, path, *arguments)
|
95
|
+
if use_hmac && hmac_access_id && hmac_secret_key
|
96
|
+
h = arguments.last
|
97
|
+
tmp = "Net::HTTP::#{method.to_s.capitalize}".constantize.new(path, h)
|
98
|
+
tmp.body = arguments[0] if arguments.length > 1
|
99
|
+
ApiAuth.sign!(tmp, hmac_access_id, hmac_secret_key)
|
100
|
+
arguments.last['Content-MD5'] = tmp['Content-MD5'] if tmp['Content-MD5']
|
101
|
+
arguments.last['DATE'] = tmp['DATE']
|
102
|
+
arguments.last['Authorization'] = tmp['Authorization']
|
103
|
+
end
|
104
|
+
|
105
|
+
request_without_auth(method, path, *arguments)
|
106
|
+
end
|
107
|
+
|
108
|
+
end # Connection
|
109
|
+
|
110
|
+
unless defined?(ActiveResource)
|
111
|
+
begin
|
112
|
+
require 'rubygems'
|
113
|
+
gem 'activeresource'
|
114
|
+
require 'active_resource'
|
115
|
+
rescue LoadError
|
116
|
+
nil
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
if defined?(ActiveResource)
|
121
|
+
ActiveResource::Base.send(:include, ActiveResourceApiAuth)
|
122
|
+
ActiveResource::Connection.send(:include, Connection)
|
123
|
+
end
|
124
|
+
|
125
|
+
end # ActiveResourceExtension
|
126
|
+
|
127
|
+
end # Rails
|
128
|
+
|
129
|
+
end # ApiAuth
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module ApiAuth
|
2
|
+
|
3
|
+
module RequestDrivers # :nodoc:
|
4
|
+
|
5
|
+
class ActionControllerRequest # :nodoc:
|
6
|
+
|
7
|
+
include ApiAuth::Helpers
|
8
|
+
|
9
|
+
def initialize(request)
|
10
|
+
@request = request
|
11
|
+
@headers = fetch_headers
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_auth_header(header)
|
16
|
+
@request.env["Authorization"] = header
|
17
|
+
@headers = fetch_headers
|
18
|
+
@request
|
19
|
+
end
|
20
|
+
|
21
|
+
def calculated_md5
|
22
|
+
body = @request.raw_post
|
23
|
+
md5_base64digest(body)
|
24
|
+
end
|
25
|
+
|
26
|
+
def populate_content_md5
|
27
|
+
if @request.put? || @request.post?
|
28
|
+
@request.env["Content-MD5"] = calculated_md5
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def md5_mismatch?
|
33
|
+
if @request.put? || @request.post?
|
34
|
+
calculated_md5 != content_md5
|
35
|
+
else
|
36
|
+
false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def fetch_headers
|
41
|
+
capitalize_keys @request.env
|
42
|
+
end
|
43
|
+
|
44
|
+
def content_type
|
45
|
+
value = find_header(%w(CONTENT-TYPE CONTENT_TYPE HTTP_CONTENT_TYPE))
|
46
|
+
value.nil? ? "" : value
|
47
|
+
end
|
48
|
+
|
49
|
+
def content_md5
|
50
|
+
value = find_header(%w(CONTENT-MD5 CONTENT_MD5 HTTP_CONTENT_MD5))
|
51
|
+
value.nil? ? "" : value
|
52
|
+
end
|
53
|
+
|
54
|
+
def request_uri
|
55
|
+
@request.request_uri
|
56
|
+
end
|
57
|
+
|
58
|
+
def set_date
|
59
|
+
@request.env['HTTP_DATE'] = time_as_httpdate
|
60
|
+
end
|
61
|
+
|
62
|
+
def timestamp
|
63
|
+
value = find_header(%w(DATE HTTP_DATE))
|
64
|
+
value.nil? ? "" : value
|
65
|
+
end
|
66
|
+
|
67
|
+
def authorization_header
|
68
|
+
find_header %w(Authorization AUTHORIZATION HTTP_AUTHORIZATION)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def find_header(keys)
|
74
|
+
keys.map {|key| @headers[key] }.compact.first
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
drivers["ActionController::Request"] = ActionControllerRequest
|
80
|
+
drivers["ActionController::CgiRequest"] = ActionControllerRequest
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ApiAuth
|
2
|
+
|
3
|
+
module RequestDrivers # :nodoc:
|
4
|
+
|
5
|
+
class ActionDispatchRequest < ActionControllerRequest # :nodoc:
|
6
|
+
|
7
|
+
def request_uri
|
8
|
+
@request.fullpath
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
drivers["ActionDispatch::Request"] = ActionDispatchRequest
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
|
2
|
+
module ApiAuth
|
3
|
+
module RequestDrivers
|
4
|
+
|
5
|
+
class BixbyRequest
|
6
|
+
|
7
|
+
include ApiAuth::Helpers
|
8
|
+
|
9
|
+
def initialize(request)
|
10
|
+
@request = request
|
11
|
+
@headers = request.headers
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_auth_header(header)
|
16
|
+
@headers["Authorization"] = header
|
17
|
+
@request
|
18
|
+
end
|
19
|
+
|
20
|
+
def calculated_md5
|
21
|
+
Digest::MD5.base64digest(@request.body || '')
|
22
|
+
end
|
23
|
+
|
24
|
+
def populate_content_md5
|
25
|
+
# Should *always* be a POST!
|
26
|
+
@headers["Content-MD5"] = calculated_md5
|
27
|
+
end
|
28
|
+
|
29
|
+
def md5_mismatch?
|
30
|
+
calculated_md5 != content_md5
|
31
|
+
end
|
32
|
+
|
33
|
+
def content_type
|
34
|
+
value = @headers["Content-Type"]
|
35
|
+
value.nil? ? "" : value
|
36
|
+
end
|
37
|
+
|
38
|
+
def content_md5
|
39
|
+
value = @headers["Content-MD5"]
|
40
|
+
value.nil? ? "" : value
|
41
|
+
end
|
42
|
+
|
43
|
+
def request_uri
|
44
|
+
@request.path
|
45
|
+
end
|
46
|
+
|
47
|
+
def set_date
|
48
|
+
@request.headers["Date"] = time_as_httpdate
|
49
|
+
end
|
50
|
+
|
51
|
+
def timestamp
|
52
|
+
value = @headers["Date"]
|
53
|
+
value.nil? ? "" : value
|
54
|
+
end
|
55
|
+
|
56
|
+
def authorization_header
|
57
|
+
@headers["Authorization"]
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
drivers["Bixby::SignedJsonRequest"] = BixbyRequest
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module ApiAuth
|
2
|
+
|
3
|
+
module RequestDrivers # :nodoc:
|
4
|
+
|
5
|
+
class CurbRequest # :nodoc:
|
6
|
+
|
7
|
+
include ApiAuth::Helpers
|
8
|
+
|
9
|
+
def initialize(request)
|
10
|
+
@request = request
|
11
|
+
@headers = fetch_headers
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_auth_header(header)
|
16
|
+
@request.headers.merge!({ "Authorization" => header })
|
17
|
+
@headers = fetch_headers
|
18
|
+
@request
|
19
|
+
end
|
20
|
+
|
21
|
+
def populate_content_md5
|
22
|
+
nil #doesn't appear to be possible
|
23
|
+
end
|
24
|
+
|
25
|
+
def md5_mismatch?
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
def fetch_headers
|
30
|
+
capitalize_keys @request.headers
|
31
|
+
end
|
32
|
+
|
33
|
+
def content_type
|
34
|
+
value = find_header(%w(CONTENT-TYPE CONTENT_TYPE HTTP_CONTENT_TYPE))
|
35
|
+
value.nil? ? "" : value
|
36
|
+
end
|
37
|
+
|
38
|
+
def content_md5
|
39
|
+
value = find_header(%w(CONTENT-MD5 CONTENT_MD5))
|
40
|
+
value.nil? ? "" : value
|
41
|
+
end
|
42
|
+
|
43
|
+
def request_uri
|
44
|
+
@request.url
|
45
|
+
end
|
46
|
+
|
47
|
+
def set_date
|
48
|
+
@request.headers.merge!({ "DATE" => time_as_httpdate })
|
49
|
+
end
|
50
|
+
|
51
|
+
def timestamp
|
52
|
+
value = find_header(%w(DATE HTTP_DATE))
|
53
|
+
value.nil? ? "" : value
|
54
|
+
end
|
55
|
+
|
56
|
+
def authorization_header
|
57
|
+
find_header %w(Authorization AUTHORIZATION HTTP_AUTHORIZATION)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def find_header(keys)
|
63
|
+
keys.map {|key| @headers[key] }.compact.first
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
drivers["Curl::Easy"] = CurbRequest
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module ApiAuth
|
2
|
+
|
3
|
+
module RequestDrivers # :nodoc:
|
4
|
+
|
5
|
+
class HttpiRequest # :nodoc:
|
6
|
+
|
7
|
+
include ApiAuth::Helpers
|
8
|
+
|
9
|
+
def initialize(request)
|
10
|
+
@request = request
|
11
|
+
@headers = fetch_headers
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_auth_header(header)
|
16
|
+
@request.headers["Authorization"] = header
|
17
|
+
@headers = fetch_headers
|
18
|
+
@request
|
19
|
+
end
|
20
|
+
|
21
|
+
def calculated_md5
|
22
|
+
md5_base64digest(@request.body || '')
|
23
|
+
end
|
24
|
+
|
25
|
+
def populate_content_md5
|
26
|
+
if @request.body
|
27
|
+
@request.headers["Content-MD5"] = calculated_md5
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def md5_mismatch?
|
32
|
+
if @request.body
|
33
|
+
calculated_md5 != content_md5
|
34
|
+
else
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def fetch_headers
|
40
|
+
capitalize_keys @request.headers
|
41
|
+
end
|
42
|
+
|
43
|
+
def content_type
|
44
|
+
value = find_header(%w(CONTENT-TYPE CONTENT_TYPE HTTP_CONTENT_TYPE))
|
45
|
+
value.nil? ? "" : value
|
46
|
+
end
|
47
|
+
|
48
|
+
def content_md5
|
49
|
+
value = find_header(%w(CONTENT-MD5 CONTENT_MD5))
|
50
|
+
value.nil? ? "" : value
|
51
|
+
end
|
52
|
+
|
53
|
+
def request_uri
|
54
|
+
@request.url.request_uri
|
55
|
+
end
|
56
|
+
|
57
|
+
def set_date
|
58
|
+
@request.headers["DATE"] = time_as_httpdate
|
59
|
+
end
|
60
|
+
|
61
|
+
def timestamp
|
62
|
+
value = find_header(%w(DATE HTTP_DATE))
|
63
|
+
value.nil? ? "" : value
|
64
|
+
end
|
65
|
+
|
66
|
+
def authorization_header
|
67
|
+
find_header %w(Authorization AUTHORIZATION HTTP_AUTHORIZATION)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def find_header(keys)
|
73
|
+
keys.map {|key| @headers[key] }.compact.first
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
drivers["HTTPI::Request"] = HttpiRequest
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module ApiAuth
|
2
|
+
|
3
|
+
module RequestDrivers # :nodoc:
|
4
|
+
|
5
|
+
class NetHttpRequest # :nodoc:
|
6
|
+
|
7
|
+
include ApiAuth::Helpers
|
8
|
+
|
9
|
+
def initialize(request)
|
10
|
+
@request = request
|
11
|
+
@headers = fetch_headers
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_auth_header(header)
|
16
|
+
@request["Authorization"] = header
|
17
|
+
@headers = fetch_headers
|
18
|
+
@request
|
19
|
+
end
|
20
|
+
|
21
|
+
def calculated_md5
|
22
|
+
if @request.respond_to?(:body_stream) && @request.body_stream
|
23
|
+
body = @request.body_stream.read
|
24
|
+
@request.body_stream.rewind
|
25
|
+
else
|
26
|
+
body = @request.body
|
27
|
+
end
|
28
|
+
|
29
|
+
md5_base64digest(body || '')
|
30
|
+
end
|
31
|
+
|
32
|
+
def populate_content_md5
|
33
|
+
if @request.class::REQUEST_HAS_BODY
|
34
|
+
@request["Content-MD5"] = calculated_md5
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def md5_mismatch?
|
39
|
+
if @request.class::REQUEST_HAS_BODY
|
40
|
+
calculated_md5 != content_md5
|
41
|
+
else
|
42
|
+
false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_headers
|
47
|
+
@request
|
48
|
+
end
|
49
|
+
|
50
|
+
def content_type
|
51
|
+
value = find_header(%w(CONTENT-TYPE CONTENT_TYPE HTTP_CONTENT_TYPE))
|
52
|
+
value.nil? ? "" : value
|
53
|
+
end
|
54
|
+
|
55
|
+
def content_md5
|
56
|
+
value = find_header(%w(CONTENT-MD5 CONTENT_MD5))
|
57
|
+
value.nil? ? "" : value
|
58
|
+
end
|
59
|
+
|
60
|
+
def request_uri
|
61
|
+
@request.path
|
62
|
+
end
|
63
|
+
|
64
|
+
def set_date
|
65
|
+
@request["DATE"] = time_as_httpdate
|
66
|
+
end
|
67
|
+
|
68
|
+
def timestamp
|
69
|
+
value = find_header(%w(DATE HTTP_DATE))
|
70
|
+
value.nil? ? "" : value
|
71
|
+
end
|
72
|
+
|
73
|
+
def authorization_header
|
74
|
+
find_header %w(Authorization AUTHORIZATION HTTP_AUTHORIZATION)
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def find_header(keys)
|
80
|
+
keys.map {|key| @headers[key] }.compact.first
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
drivers["Net::HTTP"] = NetHttpRequest
|
86
|
+
drivers["Net::HTTP::Put::Multipart"] = NetHttpRequest
|
87
|
+
drivers["Net::HTTP::Post::Multipart"] = NetHttpRequest
|
88
|
+
|
89
|
+
Net::HTTP.constants.each do |c|
|
90
|
+
c = Net::HTTP.const_get(c)
|
91
|
+
if c.kind_of?(Class) && c.ancestors.include?(Net::HTTPRequest) then
|
92
|
+
drivers[c.to_s] = NetHttpRequest
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|