spark_api 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (257) hide show
  1. data/History.txt +139 -0
  2. data/LICENSE +14 -0
  3. data/README.md +153 -0
  4. data/Rakefile +18 -0
  5. data/VERSION +1 -0
  6. data/bin/spark_api +8 -0
  7. data/bin/spark_api~ +8 -0
  8. data/lib/spark_api.rb +46 -0
  9. data/lib/spark_api/authentication.rb +55 -0
  10. data/lib/spark_api/authentication/api_auth.rb +104 -0
  11. data/lib/spark_api/authentication/api_auth.rb~ +104 -0
  12. data/lib/spark_api/authentication/base_auth.rb +47 -0
  13. data/lib/spark_api/authentication/base_auth.rb~ +47 -0
  14. data/lib/spark_api/authentication/oauth2.rb +198 -0
  15. data/lib/spark_api/authentication/oauth2.rb~ +199 -0
  16. data/lib/spark_api/authentication/oauth2_impl/grant_type_base.rb +87 -0
  17. data/lib/spark_api/authentication/oauth2_impl/grant_type_base.rb~ +87 -0
  18. data/lib/spark_api/authentication/oauth2_impl/grant_type_code.rb +48 -0
  19. data/lib/spark_api/authentication/oauth2_impl/grant_type_code.rb~ +49 -0
  20. data/lib/spark_api/authentication/oauth2_impl/grant_type_password.rb +44 -0
  21. data/lib/spark_api/authentication/oauth2_impl/grant_type_password.rb~ +45 -0
  22. data/lib/spark_api/authentication/oauth2_impl/grant_type_refresh.rb +35 -0
  23. data/lib/spark_api/authentication/oauth2_impl/grant_type_refresh.rb~ +36 -0
  24. data/lib/spark_api/authentication/oauth2_impl/middleware.rb +38 -0
  25. data/lib/spark_api/authentication/oauth2_impl/middleware.rb~ +39 -0
  26. data/lib/spark_api/authentication/oauth2_impl/password_provider.rb +24 -0
  27. data/lib/spark_api/authentication/oauth2_impl/password_provider.rb~ +25 -0
  28. data/lib/spark_api/cli.rb +158 -0
  29. data/lib/spark_api/cli.rb~ +158 -0
  30. data/lib/spark_api/cli/api_auth.rb +8 -0
  31. data/lib/spark_api/cli/api_auth.rb~ +8 -0
  32. data/lib/spark_api/cli/oauth2.rb +14 -0
  33. data/lib/spark_api/cli/oauth2.rb~ +14 -0
  34. data/lib/spark_api/cli/setup.rb +47 -0
  35. data/lib/spark_api/cli/setup.rb~ +47 -0
  36. data/lib/spark_api/client.rb +27 -0
  37. data/lib/spark_api/configuration.rb +54 -0
  38. data/lib/spark_api/configuration.rb~ +54 -0
  39. data/lib/spark_api/configuration/yaml.rb +101 -0
  40. data/lib/spark_api/configuration/yaml.rb~ +101 -0
  41. data/lib/spark_api/connection.rb +42 -0
  42. data/lib/spark_api/faraday.rb +64 -0
  43. data/lib/spark_api/faraday.rb~ +64 -0
  44. data/lib/spark_api/models.rb +33 -0
  45. data/lib/spark_api/models.rb~ +33 -0
  46. data/lib/spark_api/models/account.rb +115 -0
  47. data/lib/spark_api/models/account.rb~ +115 -0
  48. data/lib/spark_api/models/base.rb +118 -0
  49. data/lib/spark_api/models/base.rb~ +118 -0
  50. data/lib/spark_api/models/connect_prefs.rb +10 -0
  51. data/lib/spark_api/models/connect_prefs.rb~ +10 -0
  52. data/lib/spark_api/models/constraint.rb +16 -0
  53. data/lib/spark_api/models/constraint.rb~ +16 -0
  54. data/lib/spark_api/models/contact.rb +49 -0
  55. data/lib/spark_api/models/contact.rb~ +49 -0
  56. data/lib/spark_api/models/custom_fields.rb +12 -0
  57. data/lib/spark_api/models/custom_fields.rb~ +12 -0
  58. data/lib/spark_api/models/document.rb +11 -0
  59. data/lib/spark_api/models/document.rb~ +11 -0
  60. data/lib/spark_api/models/finders.rb +45 -0
  61. data/lib/spark_api/models/finders.rb~ +45 -0
  62. data/lib/spark_api/models/idx_link.rb +47 -0
  63. data/lib/spark_api/models/idx_link.rb~ +47 -0
  64. data/lib/spark_api/models/listing.rb +197 -0
  65. data/lib/spark_api/models/listing.rb~ +197 -0
  66. data/lib/spark_api/models/listing_cart.rb +72 -0
  67. data/lib/spark_api/models/listing_cart.rb~ +72 -0
  68. data/lib/spark_api/models/market_statistics.rb +33 -0
  69. data/lib/spark_api/models/market_statistics.rb~ +33 -0
  70. data/lib/spark_api/models/message.rb +21 -0
  71. data/lib/spark_api/models/message.rb~ +21 -0
  72. data/lib/spark_api/models/note.rb +41 -0
  73. data/lib/spark_api/models/note.rb~ +41 -0
  74. data/lib/spark_api/models/notification.rb +42 -0
  75. data/lib/spark_api/models/notification.rb~ +42 -0
  76. data/lib/spark_api/models/open_house.rb +24 -0
  77. data/lib/spark_api/models/open_house.rb~ +24 -0
  78. data/lib/spark_api/models/photo.rb +70 -0
  79. data/lib/spark_api/models/photo.rb~ +70 -0
  80. data/lib/spark_api/models/property_types.rb +7 -0
  81. data/lib/spark_api/models/property_types.rb~ +7 -0
  82. data/lib/spark_api/models/saved_search.rb +16 -0
  83. data/lib/spark_api/models/saved_search.rb~ +16 -0
  84. data/lib/spark_api/models/shared_listing.rb +35 -0
  85. data/lib/spark_api/models/shared_listing.rb~ +35 -0
  86. data/lib/spark_api/models/standard_fields.rb +50 -0
  87. data/lib/spark_api/models/standard_fields.rb~ +50 -0
  88. data/lib/spark_api/models/subresource.rb +19 -0
  89. data/lib/spark_api/models/subresource.rb~ +19 -0
  90. data/lib/spark_api/models/system_info.rb +14 -0
  91. data/lib/spark_api/models/system_info.rb~ +14 -0
  92. data/lib/spark_api/models/tour_of_home.rb +24 -0
  93. data/lib/spark_api/models/tour_of_home.rb~ +24 -0
  94. data/lib/spark_api/models/video.rb +16 -0
  95. data/lib/spark_api/models/video.rb~ +16 -0
  96. data/lib/spark_api/models/virtual_tour.rb +18 -0
  97. data/lib/spark_api/models/virtual_tour.rb~ +18 -0
  98. data/lib/spark_api/multi_client.rb +59 -0
  99. data/lib/spark_api/multi_client.rb~ +59 -0
  100. data/lib/spark_api/paginate.rb +109 -0
  101. data/lib/spark_api/paginate.rb~ +109 -0
  102. data/lib/spark_api/primary_array.rb +29 -0
  103. data/lib/spark_api/primary_array.rb~ +29 -0
  104. data/lib/spark_api/request.rb +96 -0
  105. data/lib/spark_api/request.rb~ +96 -0
  106. data/lib/spark_api/response.rb +70 -0
  107. data/lib/spark_api/response.rb~ +70 -0
  108. data/lib/spark_api/version.rb +4 -0
  109. data/lib/spark_api/version.rb~ +4 -0
  110. data/script/console +6 -0
  111. data/script/console~ +6 -0
  112. data/script/example.rb +27 -0
  113. data/script/example.rb~ +27 -0
  114. data/spec/fixtures/accounts/all.json +160 -0
  115. data/spec/fixtures/accounts/my.json +74 -0
  116. data/spec/fixtures/accounts/my_portal.json +20 -0
  117. data/spec/fixtures/accounts/my_put.json +5 -0
  118. data/spec/fixtures/accounts/my_save.json +5 -0
  119. data/spec/fixtures/accounts/office.json +142 -0
  120. data/spec/fixtures/accounts/password_save.json +6 -0
  121. data/spec/fixtures/authentication_failure.json +7 -0
  122. data/spec/fixtures/base.json +13 -0
  123. data/spec/fixtures/contacts/contacts.json +28 -0
  124. data/spec/fixtures/contacts/my.json +19 -0
  125. data/spec/fixtures/contacts/new.json +11 -0
  126. data/spec/fixtures/contacts/new_empty.json +8 -0
  127. data/spec/fixtures/contacts/new_notify.json +11 -0
  128. data/spec/fixtures/contacts/post.json +10 -0
  129. data/spec/fixtures/contacts/tags.json +11 -0
  130. data/spec/fixtures/count.json +10 -0
  131. data/spec/fixtures/empty.json +3 -0
  132. data/spec/fixtures/errors/expired.json +7 -0
  133. data/spec/fixtures/errors/failure.json +5 -0
  134. data/spec/fixtures/errors/failure_with_constraint.json +17 -0
  135. data/spec/fixtures/errors/failure_with_msg.json +7 -0
  136. data/spec/fixtures/generic_delete.json +1 -0
  137. data/spec/fixtures/generic_failure.json +5 -0
  138. data/spec/fixtures/listing_carts/add_listing.json +13 -0
  139. data/spec/fixtures/listing_carts/add_listing_post.json +5 -0
  140. data/spec/fixtures/listing_carts/empty.json +5 -0
  141. data/spec/fixtures/listing_carts/listing_cart.json +19 -0
  142. data/spec/fixtures/listing_carts/new.json +12 -0
  143. data/spec/fixtures/listing_carts/post.json +10 -0
  144. data/spec/fixtures/listing_carts/remove_listing.json +13 -0
  145. data/spec/fixtures/listings/constraints.json +18 -0
  146. data/spec/fixtures/listings/constraints_with_pagination.json +24 -0
  147. data/spec/fixtures/listings/document_index.json +19 -0
  148. data/spec/fixtures/listings/multiple.json +69 -0
  149. data/spec/fixtures/listings/no_subresources.json +38 -0
  150. data/spec/fixtures/listings/open_houses.json +21 -0
  151. data/spec/fixtures/listings/photos/index.json +469 -0
  152. data/spec/fixtures/listings/photos/new.json +12 -0
  153. data/spec/fixtures/listings/photos/post.json +20 -0
  154. data/spec/fixtures/listings/put.json +5 -0
  155. data/spec/fixtures/listings/put_expiration_date.json +5 -0
  156. data/spec/fixtures/listings/saved_search.json +17 -0
  157. data/spec/fixtures/listings/shared_listing_get.json +14 -0
  158. data/spec/fixtures/listings/shared_listing_new.json +9 -0
  159. data/spec/fixtures/listings/shared_listing_post.json +10 -0
  160. data/spec/fixtures/listings/tour_of_homes.json +23 -0
  161. data/spec/fixtures/listings/videos_index.json +18 -0
  162. data/spec/fixtures/listings/virtual_tours_index.json +42 -0
  163. data/spec/fixtures/listings/with_documents.json +52 -0
  164. data/spec/fixtures/listings/with_permissions.json +44 -0
  165. data/spec/fixtures/listings/with_photos.json +110 -0
  166. data/spec/fixtures/listings/with_supplement.json +39 -0
  167. data/spec/fixtures/listings/with_videos.json +54 -0
  168. data/spec/fixtures/listings/with_vtour.json +48 -0
  169. data/spec/fixtures/logo_fbs.png +0 -0
  170. data/spec/fixtures/messages/new.json +14 -0
  171. data/spec/fixtures/messages/new_empty.json +7 -0
  172. data/spec/fixtures/messages/new_with_recipients.json +15 -0
  173. data/spec/fixtures/messages/post.json +5 -0
  174. data/spec/fixtures/notes/add.json +11 -0
  175. data/spec/fixtures/notes/agent_shared.json +11 -0
  176. data/spec/fixtures/notes/agent_shared_empty.json +7 -0
  177. data/spec/fixtures/notes/new.json +5 -0
  178. data/spec/fixtures/notifications/mark_read.json +1 -0
  179. data/spec/fixtures/notifications/new.json +8 -0
  180. data/spec/fixtures/notifications/new_empty.json +7 -0
  181. data/spec/fixtures/notifications/notifications.json +43 -0
  182. data/spec/fixtures/notifications/post.json +10 -0
  183. data/spec/fixtures/notifications/unread.json +10 -0
  184. data/spec/fixtures/oauth2/access.json +3 -0
  185. data/spec/fixtures/oauth2/access_with_old_refresh.json +5 -0
  186. data/spec/fixtures/oauth2/access_with_refresh.json +5 -0
  187. data/spec/fixtures/oauth2/authorization_code_body.json +7 -0
  188. data/spec/fixtures/oauth2/error.json +3 -0
  189. data/spec/fixtures/oauth2/password_body.json +7 -0
  190. data/spec/fixtures/oauth2/refresh_body.json +7 -0
  191. data/spec/fixtures/oauth2_error.json +3 -0
  192. data/spec/fixtures/property_types/property_types.json +31 -0
  193. data/spec/fixtures/session.json +10 -0
  194. data/spec/fixtures/standardfields/city.json +1031 -0
  195. data/spec/fixtures/standardfields/nearby.json +53 -0
  196. data/spec/fixtures/standardfields/standardfields.json +188 -0
  197. data/spec/fixtures/standardfields/stateorprovince.json +36 -0
  198. data/spec/fixtures/success.json +5 -0
  199. data/spec/json_helper.rb +76 -0
  200. data/spec/mock_helper.rb +124 -0
  201. data/spec/oauth2_helper.rb +68 -0
  202. data/spec/spec_helper.rb +48 -0
  203. data/spec/unit/flexmls_api_spec.rb~ +23 -0
  204. data/spec/unit/spark_api/authentication/api_auth_spec.rb +169 -0
  205. data/spec/unit/spark_api/authentication/api_auth_spec.rb~ +169 -0
  206. data/spec/unit/spark_api/authentication/base_auth_spec.rb +10 -0
  207. data/spec/unit/spark_api/authentication/base_auth_spec.rb~ +10 -0
  208. data/spec/unit/spark_api/authentication/oauth2_impl/grant_type_base_spec.rb +10 -0
  209. data/spec/unit/spark_api/authentication/oauth2_impl/grant_type_base_spec.rb~ +10 -0
  210. data/spec/unit/spark_api/authentication/oauth2_spec.rb +205 -0
  211. data/spec/unit/spark_api/authentication/oauth2_spec.rb~ +205 -0
  212. data/spec/unit/spark_api/authentication_spec.rb +38 -0
  213. data/spec/unit/spark_api/authentication_spec.rb~ +38 -0
  214. data/spec/unit/spark_api/configuration/yaml_spec.rb +72 -0
  215. data/spec/unit/spark_api/configuration/yaml_spec.rb~ +72 -0
  216. data/spec/unit/spark_api/configuration_spec.rb +122 -0
  217. data/spec/unit/spark_api/configuration_spec.rb~ +122 -0
  218. data/spec/unit/spark_api/faraday_spec.rb +90 -0
  219. data/spec/unit/spark_api/faraday_spec.rb~ +90 -0
  220. data/spec/unit/spark_api/models/account_spec.rb +176 -0
  221. data/spec/unit/spark_api/models/base_spec.rb +106 -0
  222. data/spec/unit/spark_api/models/connect_prefs_spec.rb +9 -0
  223. data/spec/unit/spark_api/models/constraint_spec.rb +19 -0
  224. data/spec/unit/spark_api/models/contact_spec.rb +108 -0
  225. data/spec/unit/spark_api/models/contact_spec.rb~ +108 -0
  226. data/spec/unit/spark_api/models/document_spec.rb +32 -0
  227. data/spec/unit/spark_api/models/listing_cart_spec.rb +127 -0
  228. data/spec/unit/spark_api/models/listing_cart_spec.rb~ +127 -0
  229. data/spec/unit/spark_api/models/listing_spec.rb +320 -0
  230. data/spec/unit/spark_api/models/listing_spec.rb~ +320 -0
  231. data/spec/unit/spark_api/models/message_spec.rb +47 -0
  232. data/spec/unit/spark_api/models/message_spec.rb~ +47 -0
  233. data/spec/unit/spark_api/models/note_spec.rb +63 -0
  234. data/spec/unit/spark_api/models/note_spec.rb~ +63 -0
  235. data/spec/unit/spark_api/models/notification_spec.rb +62 -0
  236. data/spec/unit/spark_api/models/notification_spec.rb~ +62 -0
  237. data/spec/unit/spark_api/models/open_house_spec.rb +39 -0
  238. data/spec/unit/spark_api/models/photo_spec.rb +92 -0
  239. data/spec/unit/spark_api/models/property_types_spec.rb +33 -0
  240. data/spec/unit/spark_api/models/saved_search_spec.rb +40 -0
  241. data/spec/unit/spark_api/models/shared_listing_spec.rb +45 -0
  242. data/spec/unit/spark_api/models/shared_listing_spec.rb~ +45 -0
  243. data/spec/unit/spark_api/models/standard_fields_spec.rb +60 -0
  244. data/spec/unit/spark_api/models/system_info_spec.rb +83 -0
  245. data/spec/unit/spark_api/models/tour_of_home_spec.rb +44 -0
  246. data/spec/unit/spark_api/models/video_spec.rb +36 -0
  247. data/spec/unit/spark_api/models/virtual_tour_spec.rb +44 -0
  248. data/spec/unit/spark_api/multi_client_spec.rb +56 -0
  249. data/spec/unit/spark_api/multi_client_spec.rb~ +56 -0
  250. data/spec/unit/spark_api/paginate_spec.rb +224 -0
  251. data/spec/unit/spark_api/paginate_spec.rb~ +224 -0
  252. data/spec/unit/spark_api/primary_array_spec.rb +41 -0
  253. data/spec/unit/spark_api/primary_array_spec.rb~ +41 -0
  254. data/spec/unit/spark_api/request_spec.rb +344 -0
  255. data/spec/unit/spark_api/request_spec.rb~ +344 -0
  256. data/spec/unit/spark_api_spec.rb +23 -0
  257. metadata +725 -0
@@ -0,0 +1,199 @@
1
+ require 'uri'
2
+
3
+
4
+ module FlexmlsApi
5
+
6
+ module Authentication
7
+
8
+ #=OAuth2 Authentication
9
+ # Auth implementation to the API using the OAuth2 service endpoint. Current adheres to the 10
10
+ # draft of the OAuth2 specification. With OAuth2, the application supplies credentials for the
11
+ # application, and a separate a user authentication flow dictactes the active user for
12
+ # requests.
13
+ #
14
+ #===Setup
15
+ # When using this authentication method, there is a bit more setup involved to make the client
16
+ # work. All applications need to extend the BaseOAuth2Provider class to supply the application
17
+ # specific configuration. Also depending on the application type (command line, native, or web
18
+ # based), the user authentication step will be handled differently.
19
+
20
+ #==OAuth2
21
+ # Implementation the BaseAuth interface for API style authentication
22
+ class OAuth2 < BaseAuth
23
+
24
+ def initialize(client)
25
+ super(client)
26
+ @provider = client.oauth2_provider
27
+ end
28
+
29
+ def session
30
+ @provider.load_session()
31
+ end
32
+ def session=(s)
33
+ @provider.save_session(s)
34
+ end
35
+
36
+ def authenticate
37
+ granter = OAuth2Impl::GrantTypeBase.create(@client, @provider, session)
38
+ self.session = granter.authenticate
39
+ session
40
+ end
41
+
42
+ # Perform an HTTP request (no data)
43
+ def request(method, path, body, options={})
44
+ escaped_path = URI.escape(path)
45
+ connection = @client.connection(true) # SSL Only!
46
+ connection.headers.merge!(self.auth_header)
47
+ parameter_string = options.size > 0 ? "?#{build_url_parameters(options)}" : ""
48
+ request_path = "#{escaped_path}#{parameter_string}"
49
+ FlexmlsApi.logger.debug("Request: #{request_path}")
50
+ if body.nil?
51
+ response = connection.send(method, request_path)
52
+ else
53
+ FlexmlsApi.logger.debug("Data: #{body}")
54
+ response = connection.send(method, request_path, body)
55
+ end
56
+ response
57
+ end
58
+
59
+ def logout
60
+ @provider.save_session(nil)
61
+ end
62
+
63
+ def authorization_url()
64
+ params = {
65
+ "client_id" => @provider.client_id,
66
+ "response_type" => "code",
67
+ "redirect_uri" => @provider.redirect_uri
68
+ }
69
+ "#{@provider.authorization_uri}?#{build_url_parameters(params)}"
70
+ end
71
+
72
+
73
+ protected
74
+
75
+ def auth_header
76
+ {"Authorization"=> "OAuth #{session.access_token}"}
77
+ end
78
+
79
+ def provider
80
+ @provider
81
+ end
82
+ def client
83
+ @client
84
+ end
85
+
86
+ end
87
+
88
+ # Representation of a session with the api using oauth2
89
+ class OAuthSession
90
+ SESSION_ATTRIBUTES = [:access_token, :expires_in, :scope, :refresh_token, :refresh_timeout, :start_time]
91
+ attr_accessor *SESSION_ATTRIBUTES
92
+ def initialize(options={})
93
+ @access_token = options["access_token"]
94
+ @expires_in = options["expires_in"]
95
+ @scope = options["scope"]
96
+ @refresh_token = options["refresh_token"]
97
+ @start_time = options.fetch("start_time", DateTime.now)
98
+ @refresh_timeout = options.fetch("refresh_timeout",3600)
99
+ if @start_time.is_a? String
100
+ @start_time = DateTime.parse(@start_time)
101
+ end
102
+ end
103
+ # Is the user session token expired?
104
+ def expired?
105
+ @start_time + Rational(@expires_in - @refresh_timeout, 86400) < DateTime.now
106
+ end
107
+
108
+ def to_json(*a)
109
+ hash = {}
110
+ SESSION_ATTRIBUTES.each do |k|
111
+ value = self.send(k)
112
+ hash[k.to_s] = value unless value.nil?
113
+ end
114
+ hash.to_json(*a)
115
+ end
116
+ end
117
+
118
+ #=OAuth2 configuration provider for applications
119
+ # Applications planning to use OAuth2 authentication with the API must extend this class as
120
+ # part of the client configuration, providing values for the following attributes:
121
+ # @authorization_uri - User oauth2 login page for flexmls
122
+ # @access_uri - Location of the OAuth2 access token resource for the api. OAuth2 code and
123
+ # credentials will be sent to this uri to generate an access token.
124
+ # @redirect_uri - Application uri to redirect to
125
+ # @client_id - OAuth2 provided application identifier
126
+ # @client_secret - OAuth2 provided password for the client id
127
+ class BaseOAuth2Provider
128
+ attr_accessor *Configuration::OAUTH2_KEYS
129
+ # Requirements for authorization_code grant type
130
+ attr_accessor :code
131
+ attr_accessor :grant_type
132
+
133
+ def initialize(opts={})
134
+ Configuration::OAUTH2_KEYS.each do |key|
135
+ send("#{key}=", opts[key]) if opts.include? key
136
+ end
137
+ @grant_type = :authorization_code
138
+ end
139
+
140
+ def grant_type
141
+ # backwards compatibility check
142
+ @grant_type.nil? ? :authorization_code : @grant_type
143
+ end
144
+
145
+ # Application using the client must handle user redirect for user authentication. For
146
+ # command line applications, this method is called prior to initial client requests so that
147
+ # the process can notify the user to go to the url and retrieve the access_code for the app.
148
+ # In a web based web application, this method can be mostly ignored. However, the web based
149
+ # application is then responsible for ensuring the code is saved to the the provider instance
150
+ # prior to any client requests are performed (or the error below will be thrown).
151
+ def redirect(url)
152
+ raise "To be implemented by client application"
153
+ end
154
+
155
+ #==For any persistence to be supported outside application process, the application shall
156
+ # implement the following methods for storing and retrieving the user OAuth2 session
157
+ # (e.g. to and from memcached).
158
+
159
+ # Load the current OAuth session
160
+ # returns - active OAuthSession or nil
161
+ def load_session
162
+ nil
163
+ end
164
+
165
+ # Save current session
166
+ # session - active OAuthSession
167
+ def save_session(session)
168
+
169
+ end
170
+
171
+ # Provides a default session time out
172
+ # returns - the session timeout length (in seconds)
173
+ def session_timeout
174
+ 86400 # 1.day
175
+ end
176
+
177
+ end
178
+
179
+ module OAuth2Impl
180
+ require 'flexmls_api/authentication/oauth2_impl/middleware'
181
+ require 'flexmls_api/authentication/oauth2_impl/grant_type_base'
182
+ require 'flexmls_api/authentication/oauth2_impl/grant_type_refresh'
183
+ require 'flexmls_api/authentication/oauth2_impl/grant_type_code'
184
+ require 'flexmls_api/authentication/oauth2_impl/grant_type_password'
185
+ require 'flexmls_api/authentication/oauth2_impl/password_provider'
186
+
187
+ # Loads a provider class from a string
188
+ def self.load_provider(string, args={})
189
+ constant = Object
190
+ string.split("::").compact.each { |name| constant = constant.const_get(name) unless name == ""}
191
+ constant.new(args)
192
+ rescue => e
193
+ raise ArgumentError, "The value '#{string}' is an invalid class name for an oauth2 provider: #{e.message}"
194
+ end
195
+ end
196
+
197
+ end
198
+
199
+ end
@@ -0,0 +1,87 @@
1
+ module SparkApi
2
+ module Authentication
3
+ module OAuth2Impl
4
+ class GrantTypeBase
5
+ GRANT_TYPES = [:authorization_code, :password, :refresh_token]
6
+
7
+ def self.create(client, provider, session=nil)
8
+ granter = nil
9
+ case provider.grant_type
10
+ when :authorization_code
11
+ granter = GrantTypeCode.new(client, provider, session)
12
+ when :password
13
+ granter = GrantTypePassword.new(client, provider, session)
14
+ # This method should only be used internally to the library
15
+ when :refresh_token
16
+ granter = GrantTypeRefresh.new(client, provider, session)
17
+ else
18
+ raise ClientError, "Unsupported grant type [#{provider.grant_type}]"
19
+ end
20
+ SparkApi.logger.debug("[oauth2] setup #{granter.class.name}")
21
+ granter
22
+ end
23
+
24
+ attr_reader :provider, :client, :session
25
+ def initialize(client, provider, session)
26
+ @client = client
27
+ @provider = provider
28
+ @session = session
29
+ end
30
+ def authenticate
31
+
32
+ end
33
+
34
+ def refresh
35
+
36
+ end
37
+
38
+ protected
39
+
40
+ def create_session(token_params)
41
+ SparkApi.logger.debug("[oauth2] create_session to #{provider.access_uri} params #{token_params}")
42
+ uri = URI.parse(provider.access_uri)
43
+ request_path = "#{uri.path}"
44
+ response = oauth_access_connection("#{uri.scheme}://#{uri.host}").post(request_path, "#{token_params}").body
45
+ response.expires_in = provider.session_timeout if response.expires_in.nil?
46
+ SparkApi.logger.debug("[oauth2] New session created #{response}")
47
+ response
48
+ end
49
+
50
+ def needs_refreshing?
51
+ !@session.nil? && !@session.refresh_token.nil? && @session.expired?
52
+ end
53
+
54
+ # Generate the appropriate request uri for authorizing this application for current user.
55
+ def authorization_url()
56
+ params = {
57
+ "client_id" => @provider.client_id,
58
+ "response_type" => "code",
59
+ "redirect_uri" => @provider.redirect_uri
60
+ }
61
+ "#{@provider.authorization_uri}?#{build_url_parameters(params)}"
62
+ end
63
+
64
+ # Setup a faraday connection for dealing with an OAuth2 endpoint
65
+ def oauth_access_connection(endpoint)
66
+ opts = {
67
+ :headers => @client.headers
68
+ }
69
+ opts[:ssl] = {:verify => false }
70
+ opts[:url] = endpoint
71
+ conn = Faraday::Connection.new(opts) do |builder|
72
+ builder.adapter Faraday.default_adapter
73
+ builder.use SparkApi::Authentication::OAuth2Impl::Middleware
74
+ end
75
+ end
76
+ def build_url_parameters(parameters={})
77
+ array = parameters.map do |key,value|
78
+ escaped_value = CGI.escape("#{value}")
79
+ "#{key}=#{escaped_value}"
80
+ end
81
+ array.join "&"
82
+ end
83
+ end
84
+
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,87 @@
1
+ module FlexmlsApi
2
+ module Authentication
3
+ module OAuth2Impl
4
+ class GrantTypeBase
5
+ GRANT_TYPES = [:authorization_code, :password, :refresh_token]
6
+
7
+ def self.create(client, provider, session=nil)
8
+ granter = nil
9
+ case provider.grant_type
10
+ when :authorization_code
11
+ granter = GrantTypeCode.new(client, provider, session)
12
+ when :password
13
+ granter = GrantTypePassword.new(client, provider, session)
14
+ # This method should only be used internally to the library
15
+ when :refresh_token
16
+ granter = GrantTypeRefresh.new(client, provider, session)
17
+ else
18
+ raise ClientError, "Unsupported grant type [#{provider.grant_type}]"
19
+ end
20
+ FlexmlsApi.logger.debug("[oauth2] setup #{granter.class.name}")
21
+ granter
22
+ end
23
+
24
+ attr_reader :provider, :client, :session
25
+ def initialize(client, provider, session)
26
+ @client = client
27
+ @provider = provider
28
+ @session = session
29
+ end
30
+ def authenticate
31
+
32
+ end
33
+
34
+ def refresh
35
+
36
+ end
37
+
38
+ protected
39
+
40
+ def create_session(token_params)
41
+ FlexmlsApi.logger.debug("[oauth2] create_session to #{provider.access_uri} params #{token_params}")
42
+ uri = URI.parse(provider.access_uri)
43
+ request_path = "#{uri.path}"
44
+ response = oauth_access_connection("#{uri.scheme}://#{uri.host}").post(request_path, "#{token_params}").body
45
+ response.expires_in = provider.session_timeout if response.expires_in.nil?
46
+ FlexmlsApi.logger.debug("[oauth2] New session created #{response}")
47
+ response
48
+ end
49
+
50
+ def needs_refreshing?
51
+ !@session.nil? && !@session.refresh_token.nil? && @session.expired?
52
+ end
53
+
54
+ # Generate the appropriate request uri for authorizing this application for current user.
55
+ def authorization_url()
56
+ params = {
57
+ "client_id" => @provider.client_id,
58
+ "response_type" => "code",
59
+ "redirect_uri" => @provider.redirect_uri
60
+ }
61
+ "#{@provider.authorization_uri}?#{build_url_parameters(params)}"
62
+ end
63
+
64
+ # Setup a faraday connection for dealing with an OAuth2 endpoint
65
+ def oauth_access_connection(endpoint)
66
+ opts = {
67
+ :headers => @client.headers
68
+ }
69
+ opts[:ssl] = {:verify => false }
70
+ opts[:url] = endpoint
71
+ conn = Faraday::Connection.new(opts) do |builder|
72
+ builder.adapter Faraday.default_adapter
73
+ builder.use FlexmlsApi::Authentication::OAuth2Impl::Middleware
74
+ end
75
+ end
76
+ def build_url_parameters(parameters={})
77
+ array = parameters.map do |key,value|
78
+ escaped_value = CGI.escape("#{value}")
79
+ "#{key}=#{escaped_value}"
80
+ end
81
+ array.join "&"
82
+ end
83
+ end
84
+
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,48 @@
1
+ module SparkApi
2
+ module Authentication
3
+ module OAuth2Impl
4
+ # OAuth2 authentication flow using username and password parameters for the user in the
5
+ # request. This implementation is geared towards authentication styles for web applications
6
+ # that have a OAuth flow for redirects.
7
+ class GrantTypeCode < GrantTypeBase
8
+ def initialize(client, provider, session)
9
+ super(client, provider, session)
10
+ end
11
+ def authenticate
12
+ if(provider.code.nil?)
13
+ SparkApi.logger.debug("[oauth2] No authoriztion code present. Redirecting to #{authorization_url}.")
14
+ provider.redirect(authorization_url)
15
+ end
16
+ if needs_refreshing?
17
+ new_session = refresh
18
+ end
19
+ return new_session unless new_session.nil?
20
+ create_session(token_params)
21
+ end
22
+
23
+ def refresh()
24
+ SparkApi.logger.debug("[oauth2] Refresh oauth session.")
25
+ refresher = GrantTypeRefresh.new(client,provider,session)
26
+ refresher.params = {"redirect_uri" => @provider.redirect_uri}
27
+ refresher.authenticate
28
+ rescue ClientError => e
29
+ SparkApi.logger.info("[oauth2] Refreshing token failed, the library will try and authenticate from scratch: #{e.message}")
30
+ nil
31
+ end
32
+
33
+ private
34
+ def token_params
35
+ params = {
36
+ "client_id" => @provider.client_id,
37
+ "client_secret" => @provider.client_secret,
38
+ "grant_type" => "authorization_code",
39
+ "code" => @provider.code,
40
+ "redirect_uri" => @provider.redirect_uri
41
+ }.to_json
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,49 @@
1
+
2
+ module FlexmlsApi
3
+ module Authentication
4
+ module OAuth2Impl
5
+ # OAuth2 authentication flow using username and password parameters for the user in the
6
+ # request. This implementation is geared towards authentication styles for web applications
7
+ # that have a OAuth flow for redirects.
8
+ class GrantTypeCode < GrantTypeBase
9
+ def initialize(client, provider, session)
10
+ super(client, provider, session)
11
+ end
12
+ def authenticate
13
+ if(provider.code.nil?)
14
+ FlexmlsApi.logger.debug("[oauth2] No authoriztion code present. Redirecting to #{authorization_url}.")
15
+ provider.redirect(authorization_url)
16
+ end
17
+ if needs_refreshing?
18
+ new_session = refresh
19
+ end
20
+ return new_session unless new_session.nil?
21
+ create_session(token_params)
22
+ end
23
+
24
+ def refresh()
25
+ FlexmlsApi.logger.debug("[oauth2] Refresh oauth session.")
26
+ refresher = GrantTypeRefresh.new(client,provider,session)
27
+ refresher.params = {"redirect_uri" => @provider.redirect_uri}
28
+ refresher.authenticate
29
+ rescue ClientError => e
30
+ FlexmlsApi.logger.info("[oauth2] Refreshing token failed, the library will try and authenticate from scratch: #{e.message}")
31
+ nil
32
+ end
33
+
34
+ private
35
+ def token_params
36
+ params = {
37
+ "client_id" => @provider.client_id,
38
+ "client_secret" => @provider.client_secret,
39
+ "grant_type" => "authorization_code",
40
+ "code" => @provider.code,
41
+ "redirect_uri" => @provider.redirect_uri
42
+ }.to_json
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+ end
49
+ end