/
base_oauth.rb
105 lines (91 loc) · 3.04 KB
/
base_oauth.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# This class contains the common behavior for middlewares
# implementing either versions of OAuth.
#
# Extending classes are required to implement
# the following methods:
# * request_authorization_from_user
# * fetch_contatcs
module OmniContacts
module Middleware
class BaseOAuth
attr_reader :ssl_ca_file
def initialize app, options
@app = app
@listening_path = "/contacts/" + class_name
@ssl_ca_file = options[:ssl_ca_file]
end
def class_name
self.class.name.split('::').last.downcase
end
# Rack callback. It handles three cases:
# * user visit middleware entry point.
# In this case request_authorization_from_user is called
# * user is redirected back to the application
# from the authorization site. In this case the list
# of contacts is fetched and stored in the variables
# omnicontacts.contacts within the Rack env variable.
# Once that is done the next middleware component is called.
# * user visits any other resource. In this case the request
# is simply forwarded to the next middleware component.
def call env
@env = env
if env["PATH_INFO"] =~ /^#{@listening_path}\/?$/
handle_initial_request
elsif env["PATH_INFO"] =~ /^#{redirect_path}/
handle_callback
else
@app.call(env)
end
end
private
def test_mode?
IntegrationTest.instance.enabled
end
def handle_initial_request
execute_and_rescue_exceptions do
if test_mode?
IntegrationTest.instance.mock_authorization_from_user(self)
else
request_authorization_from_user
end
end
end
def handle_callback
execute_and_rescue_exceptions do
@env["omnicontacts.contacts"] = if test_mode?
IntegrationTest.instance.mock_fetch_contacts(self)
else
fetch_contacts
end
@app.call(@env)
end
end
# This method rescues executes a block of code and
# rescue all exceptions. In case of an exception the
# user is redirected to the failure endpoint.
def execute_and_rescue_exceptions
yield
rescue AuthorizationError => e
handle_error :not_authorized, e
rescue ::Timeout::Error, ::Errno::ETIMEDOUT => e
handle_error :timeout, e
rescue ::RuntimeError => e
handle_error :internal_error, e
end
def handle_error error_type, exception
logger << ("Error #{error_type} while processing #{@env["PATH_INFO"]}: #{exception.message}") if logger
[302, {"location" => "/contacts/failure?error_message=#{error_type}"}, []]
end
def session
raise "You must provide a session to use OmniContacts" unless @env["rack.session"]
@env["rack.session"]
end
def logger
@env["rack.errors"] if @env
end
def base_prop_name
"omnicontacts." + class_name
end
end
end
end