spark_api 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +14 -0
- data/README.md +42 -233
- data/VERSION +1 -1
- data/lib/spark_api.rb +1 -0
- data/lib/spark_api/authentication/oauth2.rb +39 -9
- data/lib/spark_api/authentication/oauth2_impl/cli_provider.rb +96 -0
- data/lib/spark_api/authentication/oauth2_impl/faraday_middleware.rb +28 -0
- data/lib/spark_api/authentication/oauth2_impl/grant_type_base.rb +7 -2
- data/lib/spark_api/authentication/oauth2_impl/single_session_provider.rb +27 -0
- data/lib/spark_api/cli.rb +29 -10
- data/lib/spark_api/cli/api_auth.rb +1 -0
- data/lib/spark_api/cli/oauth2.rb +23 -8
- data/lib/spark_api/cli/setup.rb +31 -0
- data/lib/spark_api/configuration.rb +10 -2
- data/lib/spark_api/configuration/yaml.rb +6 -1
- data/lib/spark_api/connection.rb +1 -1
- data/lib/spark_api/errors.rb +48 -0
- data/lib/spark_api/models.rb +3 -0
- data/lib/spark_api/models/account.rb +9 -1
- data/lib/spark_api/models/base.rb +24 -19
- data/lib/spark_api/models/concerns.rb +7 -0
- data/lib/spark_api/models/concerns/destroyable.rb +32 -0
- data/lib/spark_api/models/concerns/savable.rb +66 -0
- data/lib/spark_api/models/contact.rb +6 -25
- data/lib/spark_api/models/dirty.rb +57 -0
- data/lib/spark_api/models/finders.rb +0 -4
- data/lib/spark_api/models/saved_search.rb +10 -0
- data/lib/spark_api/models/subresource.rb +5 -1
- data/lib/spark_api/models/subscription.rb +52 -0
- data/lib/spark_api/request.rb +17 -4
- data/lib/spark_api/response.rb +0 -37
- data/script/combined_flow_example.rb +3 -3
- data/script/oauth2_example.rb +3 -3
- data/spec/fixtures/base.json +3 -1
- data/spec/fixtures/contacts/new.json +2 -3
- data/spec/fixtures/contacts/new_empty.json +2 -3
- data/spec/fixtures/contacts/new_notify.json +1 -1
- data/spec/fixtures/{listings/saved_search.json → saved_searches/get.json} +1 -1
- data/spec/fixtures/saved_searches/new.json +8 -0
- data/spec/fixtures/saved_searches/post.json +12 -0
- data/spec/fixtures/saved_searches/update.json +6 -0
- data/spec/fixtures/subscriptions/get.json +19 -0
- data/spec/fixtures/subscriptions/new.json +13 -0
- data/spec/fixtures/subscriptions/post.json +10 -0
- data/spec/fixtures/subscriptions/put.json +12 -0
- data/spec/fixtures/subscriptions/subscribe.json +5 -0
- data/spec/fixtures/subscriptions/update.json +6 -0
- data/spec/mock_helper.rb +14 -6
- data/spec/oauth2_helper.rb +2 -0
- data/spec/spec_helper.rb +4 -7
- data/spec/unit/spark_api/authentication/api_auth_spec.rb +0 -1
- data/spec/unit/spark_api/authentication/oauth2_impl/faraday_middleware_spec.rb +32 -0
- data/spec/unit/spark_api/authentication/oauth2_impl/single_session_provider_spec.rb +9 -0
- data/spec/unit/spark_api/authentication/oauth2_spec.rb +29 -3
- data/spec/unit/spark_api/authentication_spec.rb +4 -10
- data/spec/unit/spark_api/configuration/yaml_spec.rb +4 -3
- data/spec/unit/spark_api/configuration_spec.rb +22 -8
- data/spec/unit/spark_api/models/account_spec.rb +5 -0
- data/spec/unit/spark_api/models/base_spec.rb +27 -0
- data/spec/unit/spark_api/models/concerns/destroyable_spec.rb +28 -0
- data/spec/unit/spark_api/models/concerns/savable_spec.rb +61 -0
- data/spec/unit/spark_api/models/contact_spec.rb +5 -5
- data/spec/unit/spark_api/models/dirty_spec.rb +46 -0
- data/spec/unit/spark_api/models/finders_spec.rb +0 -7
- data/spec/unit/spark_api/models/saved_search_spec.rb +34 -3
- data/spec/unit/spark_api/models/shared_listing_spec.rb +1 -1
- data/spec/unit/spark_api/models/subscription_spec.rb +106 -0
- data/spec/unit/spark_api/multi_client_spec.rb +14 -4
- data/spec/unit/spark_api/paginate_spec.rb +0 -1
- data/spec/unit/spark_api/request_spec.rb +10 -0
- data/spec/unit/spark_api_spec.rb +0 -3
- metadata +127 -45
- data/lib/spark_api/authentication/oauth2_impl/password_provider.rb +0 -24
data/History.txt
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
== v1.2.0 2012-11-14
|
2
|
+
* SSL verification enabled by default
|
3
|
+
* Sparkbar token access support
|
4
|
+
* Fixed oauth2 CLI usage
|
5
|
+
* Model behaviors for CRUD operations
|
6
|
+
* Dirty module to help manage dirty attributes for updating a model
|
7
|
+
* Removed nonsensical "all" method for finder models
|
8
|
+
* ApiUser support for OAuth2 flow
|
9
|
+
* Subscriptions models
|
10
|
+
* Single session OAuth2 support
|
11
|
+
* Update RecipientIds attribute on subscribe/unsubscribe
|
12
|
+
* Restrict API wrapped json post data for hashes that have content
|
13
|
+
* Fix sorting on nils in accounts model
|
14
|
+
* Pluralize module
|
1
15
|
== v1.1.0 2012-08-07
|
2
16
|
* Upgraded faraday and other gems, cleand up the middleware
|
3
17
|
== v1.0.4 2012-07-26
|
data/README.md
CHANGED
@@ -5,6 +5,9 @@ A Ruby wrapper for the Spark REST API. Loosely based on ActiveResource to provid
|
|
5
5
|
|
6
6
|
Documentation
|
7
7
|
-------------
|
8
|
+
|
9
|
+
For further client documentation, please consult our [wiki](wiki).
|
10
|
+
|
8
11
|
For full information on the API, see [http://sparkplatform.com/docs/overview/api](http://sparkplatform.com/docs/overview/api)
|
9
12
|
|
10
13
|
|
@@ -14,268 +17,74 @@ Installation
|
|
14
17
|
|
15
18
|
Usage Examples
|
16
19
|
------------------------
|
17
|
-
|
18
|
-
#### Ruby Script: OpenId/OAuth2 Combined Flow
|
19
|
-
# initialize the gem with your key/secret.
|
20
|
-
# See also: script/combined_flow_example.rb
|
21
|
-
# api_key, api_secret, and callback are all required.
|
22
|
-
# The following options are required:
|
23
|
-
# - api_key: Your client key
|
24
|
-
# - api_secret: Your client secret
|
25
|
-
# - callback: Your redirect_uri, which the end user will be redirected
|
26
|
-
# to after authorizing your application to access their data.
|
27
|
-
# - auth_endpoint: The URI to redirect the user's web browser to, in order for them to
|
28
|
-
# authorize your application to access their data.
|
29
|
-
# other options and their defaults:
|
30
|
-
# - endpoint: 'https://api.sparkapi.com'
|
31
|
-
# - version: 'v1'
|
32
|
-
# - ssl: true
|
33
|
-
# - user_agent: 'Spark API Ruby Gem'
|
34
|
-
SparkApi.configure do |config|
|
35
|
-
config.authentication_mode = SparkApi::Authentication::OpenIdOAuth2Hybrid
|
36
|
-
config.api_key = "YOUR_CLIENT_ID"
|
37
|
-
config.api_secret = "YOUR_CLIENT_SECRET"
|
38
|
-
config.callback = "YOUR_REDIRECT_URI"
|
39
|
-
config.auth_endpoint = "https://developers.sparkplatform.com/openid"
|
40
|
-
config.endpoint = 'https://developers.sparkapi.com'
|
41
|
-
end
|
42
|
-
|
43
|
-
# Code is retrieved from the method: SparkApi.client.authenticator.authorization_url
|
44
|
-
# See script/combined_flow_example.rb for more details.
|
45
|
-
|
46
|
-
|
47
|
-
SparkApi.client.oauth2_provider.code = "CODE_FROM_ABOVE_URI"
|
48
|
-
SparkApi.client.authenticate
|
49
|
-
|
50
|
-
# Alternatively, if you've already received an access token, you may
|
51
|
-
# do the following instead of the above two lines:
|
52
|
-
# SparkApi.client.session = SparkApi::Authentication::OAuthSession.new "access_token"=> "ACCESS_TOKEN",
|
53
|
-
# "refresh_token" => "REFRESH_TOKEN", "expires_in" => 86400
|
54
|
-
|
55
|
-
# mixin the models so you can use them without prefix
|
56
|
-
include SparkApi::Models
|
57
|
-
|
58
|
-
# Grab your listings!
|
59
|
-
my_listings = Listing.my()
|
60
|
-
|
61
|
-
#### Ruby Script: OAuth 2
|
62
|
-
# initialize the gem with your OAuth 2 key/secret.
|
63
|
-
# See also: script/oauth2_example.rb
|
64
|
-
# api_key, api_secret, and callback are all required.
|
65
|
-
# The following options are required:
|
66
|
-
# - api_key: Your OAuth 2 client key
|
67
|
-
# - api_secret: Your OAuth 2 client secret
|
68
|
-
# - callback: Your OAuth 2 redirect_uri, which the end user will be redirected
|
69
|
-
# to after authorizing your application to access their data.
|
70
|
-
# - auth_endpoint: The URI to redirect the user's web browser to, in order for them to
|
71
|
-
# authorize your application to access their data.
|
72
|
-
# other options and their defaults:
|
73
|
-
# - endpoint: 'https://api.sparkapi.com'
|
74
|
-
# - version: 'v1'
|
75
|
-
# - ssl: true
|
76
|
-
# - user_agent: 'Spark API Ruby Gem'
|
77
20
|
SparkApi.configure do |config|
|
78
|
-
config.
|
79
|
-
|
80
|
-
config.
|
81
|
-
config.
|
82
|
-
config.auth_endpoint = "https://developers.sparkplatform.com/oauth2"
|
83
|
-
config.endpoint = 'https://developers.sparkapi.com'
|
21
|
+
config.endpoint = 'https://sparkapi.com'
|
22
|
+
# Using Spark API Authentication, refer to the Authentication documentation for OAuth2
|
23
|
+
config.api_key = 'MY_SPARK_API_KEY'
|
24
|
+
config.api_secret = 'MY_SPARK_API_SECRET'
|
84
25
|
end
|
85
|
-
|
86
|
-
# Code is retrieved from the method. SparkApi.client.authenticator.authorization_url
|
87
|
-
# See script/oauth2_example.rb for more details.
|
26
|
+
SparkApi.client.get '/my/account'
|
88
27
|
|
89
28
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
# Alternatively, if you've already received an access token, you may
|
94
|
-
# do the following instead of the above two lines:
|
95
|
-
#SparkApi.client.session = SparkApi::Authentication::OAuthSession.new "access_token"=> "ACCESS_TOKEN",
|
96
|
-
# "refresh_token" => "REFRESH_TOKEN", "expires_in" => 86400
|
97
|
-
|
98
|
-
# mixin the models so you can use them without prefix
|
99
|
-
include SparkApi::Models
|
29
|
+
#### Interactive Console
|
30
|
+
Included in the gem is an interactive spark_api console to interact with the api in a manner similar to the rails console. Below is a brief example of interacting with the console:
|
100
31
|
|
101
|
-
|
102
|
-
|
32
|
+
> spark_api --api_key MY_SPARK_API_KEY --api_secret MY_SPARK_API_SECRET
|
33
|
+
SparkApi> SparkApi.client.get '/my/account'
|
103
34
|
|
35
|
+
Using OAuth2 requires different arguments, and is a bit more complicated as it requires a step for logging in through the browser to gain access to the access code for a client_id.
|
104
36
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
# other options and their defaults:
|
116
|
-
# - user_agent: 'Spark API Ruby Gem'
|
117
|
-
SparkApi.configure do |config|
|
118
|
-
config.authentication_mode = SparkApi::Authentication::OpenId
|
119
|
-
config.api_key = "YOUR_CLIENT_ID"
|
120
|
-
config.api_secret = "YOUR_CLIENT_SECRET"
|
121
|
-
config.callback = "YOUR_REDIRECT_URI"
|
122
|
-
config.auth_endpoint = "https://developers.sparkplatform.com/openid"
|
123
|
-
end
|
37
|
+
> bundle exec spark_api --oauth2 --client_id my_oauth2_client_id --client_secret my_oauth2_client_secret
|
38
|
+
Loading spark_api gem...
|
39
|
+
SparkApi:001:0> Account.my.Name
|
40
|
+
Missing OAuth2 session, redirecting...
|
41
|
+
Please visit https://sparkplatform.com/oauth2?client_id=my_oauth2_client_id&response_type=code&redirect_uri=https%3A%2F%2Fsparkplatform.com%2Foauth2%2Fcallback, login as a user, and paste the authorization code here:
|
42
|
+
Authorization code?
|
43
|
+
9zsrc7jk7m4x7r4kers8n6sp5
|
44
|
+
"Demo User"
|
45
|
+
SparkApi:002:0> Account.my.UserType
|
46
|
+
"Member"
|
124
47
|
|
125
|
-
|
126
|
-
# See script/combined_flow_example.rb for more details.
|
127
|
-
# Optionally, additional a GET parameters can be supplied as a hash to
|
128
|
-
# authorization_url.
|
129
|
-
# SparkApi.client.authenticator.authorization_url
|
48
|
+
You can also provide other options from the command line, see "spark_api -h" for more information.
|
130
49
|
|
131
|
-
|
50
|
+
#### HTTP Interface
|
51
|
+
The base client provides a bare bones HTTP interface for working with the RESTful Spark API. This is basically a stylized curl interface that handles authentication, error handling, and processes JSON results as Ruby Hashes.
|
132
52
|
|
53
|
+
SparkApi.client.get "/listings/#{listing_id}", :_expand => "CustomFields"
|
54
|
+
SparkApi.client.post "/listings/#{listing_id}/photos", photo_body_hash
|
55
|
+
SparkApi.client.put "/listings/#{listing_id}/photos/#{photo_id}", updated_photo_name_hash
|
56
|
+
SparkApi.client.delete "/listings/#{listing_id}/photos/#{photo_id}"
|
133
57
|
|
134
|
-
####
|
135
|
-
|
136
|
-
# api_key and _api_secret are the only required settings
|
137
|
-
# other options and their defaults:
|
138
|
-
# - endpoint: 'https://api.sparkapi.com'
|
139
|
-
# - version: 'v1'
|
140
|
-
# - ssl: false
|
141
|
-
# - user_agent: 'Spark API Ruby Gem'
|
142
|
-
SparkApi.configure do |config|
|
143
|
-
config.endpoint = 'https://developers.sparkapi.com'
|
144
|
-
config.api_key = 'my_api_key'
|
145
|
-
config.api_secret = 'my_api_secret'
|
146
|
-
end
|
58
|
+
#### [API Models](wiki/API-Models)
|
59
|
+
The client also provides ActiveModelesque interface for working with the api responses. Notably, the models use finder methods for searching, and similar instanciation and persistence also on supported services.
|
147
60
|
|
148
|
-
# mixin the models so you can use them without
|
61
|
+
# Tip: mixin the models so you can use them without namespaces
|
149
62
|
include SparkApi::Models
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
#### Interactive Console
|
156
|
-
Included in the gem is a simple setup script to run the client in IRB. To use it, first create the file called _.spark_api_testing_ filling in the credentials for your account.
|
157
|
-
|
158
|
-
API_USER="12345678901234567890123456" # 26-digit identifier of an API user
|
159
|
-
API_ENDPOINT="https://developers.sparkapi.com"
|
160
|
-
API_KEY="my_api_key"
|
161
|
-
API_SECRET="my_api_secret"
|
162
|
-
|
163
|
-
export API_USER API_ENDPOINT API_KEY API_SECRET
|
164
|
-
|
165
|
-
Now, to run with this setup, run the following from the command line:
|
166
|
-
|
167
|
-
> source .spark_api_testing
|
168
|
-
> spark_api
|
169
|
-
SparkApi> SparkApi.client.get '/my/account'
|
170
|
-
|
171
|
-
You can also provide these options from the command line, see "spark_api -h" for more information
|
63
|
+
listings = Listing.find(:all, :_filter => "ListPrice Gt 150000.0 And ListPrice Lt 200000.0", :_orderby => "-ListPrice")
|
64
|
+
puts "Top list price: $%.2f" % listings.first.ListPrice
|
65
|
+
# Top list price: $199999.99
|
66
|
+
puts Account.find(:first, :_filter => "UserType Eq 'Member' And Name Eq 'John*'").Name
|
67
|
+
# John Doe
|
172
68
|
|
173
69
|
|
174
70
|
Authentication Types
|
175
71
|
--------------
|
176
72
|
Authentication is handled transparently by the request framework in the gem, so you should never need to manually make an authentication request. More than one mode of authentication is supported, so the client needs to be configured accordingly.
|
177
73
|
|
178
|
-
#### API Authentication (Default)
|
74
|
+
#### [Spark API Authentication](wiki/Spark-Authentication) (Default)
|
179
75
|
Usually supplied for a single user, this authentication mode is the simplest, and is setup as the default. The example usage above demonstrates how to get started using this authentication mode.
|
180
76
|
|
181
|
-
#### OpenId/OAuth2 Combined Flow (Preferred)
|
77
|
+
#### [OpenId/OAuth2 Combined Flow](wiki/Hybrid-Authentication) (Preferred)
|
182
78
|
Authorization mode the separates application and user authentication. This mode requires the end user to be redirected to Spark Platform's openid endpoint. See "script/combined_flow_example.rb" for an example.
|
183
79
|
|
184
80
|
Read more about Spark Platform's combined flow <a href="http://sparkplatform.com/docs/authentication/openid_oauth2_authentication">here</a>.
|
185
81
|
|
186
|
-
#### OAuth2 Authorization
|
82
|
+
#### [OAuth2 Authorization](wiki/OAuth2-Only-Authentication)
|
187
83
|
Authorization mode the separates application and user authentication. This mode requires the end user to be redirected to Spark Platform's auth endpoint. See "script/oauth2_example.rb" for an example.
|
188
84
|
|
189
85
|
Read more about Spark Platform's OAuth 2 flow <a href="http://sparkplatform.com/docs/authentication/oauth2_authentication">here</a>.
|
190
86
|
|
191
|
-
#### OpenId Authentication
|
87
|
+
#### [OpenId Authentication](wiki/OpenId-Only-Authentication)
|
192
88
|
There is also the option to only access a user's Spark Platform identity without accessing any data (e.g. listings, contacts, etc.). In circumstances where you ONLY with to authenticate users through the Spark Platform, but do not have a use case to access any of their data, consider the OpenId authentication flow in lieu of API Authentication or the Combined flow.
|
193
89
|
|
194
90
|
Read more about Spark Platform's OpenId flow <a href="http://sparkplatform.com/docs/authentication/openid_authentication">here</a>.
|
195
|
-
|
196
|
-
Error Codes
|
197
|
-
---------------------
|
198
|
-
<table>
|
199
|
-
<thead>
|
200
|
-
<tr>
|
201
|
-
<th>HTTP Code</th>
|
202
|
-
<th>Spark API Error Code</th>
|
203
|
-
<th>Exception Raised</th>
|
204
|
-
<th>Description</th>
|
205
|
-
</tr>
|
206
|
-
</thead>
|
207
|
-
<tbody>
|
208
|
-
<tr>
|
209
|
-
<td><tt>401</tt></td>
|
210
|
-
<td><tt>1000</tt></td>
|
211
|
-
<td><tt></tt></td>
|
212
|
-
<td>Invalid API Key and/or Request signed improperly</td>
|
213
|
-
</tr>
|
214
|
-
<tr>
|
215
|
-
<td><tt>401</tt></td>
|
216
|
-
<td><tt>1010</tt></td>
|
217
|
-
<td><tt></tt></td>
|
218
|
-
<td>API key is disabled</td>
|
219
|
-
</tr>
|
220
|
-
<tr>
|
221
|
-
<td><tt>403</tt></td>
|
222
|
-
<td><tt>1015</tt></td>
|
223
|
-
<td><tt></tt></td>
|
224
|
-
<td><tt>ApiUser</tt> must be supplied, or the provided key does not have access to the supplied user</td>
|
225
|
-
</tr>
|
226
|
-
<tr>
|
227
|
-
<td><tt>401</tt></td>
|
228
|
-
<td><tt>1020</tt></td>
|
229
|
-
<td><tt></tt></td>
|
230
|
-
<td>Session token has expired</td>
|
231
|
-
</tr>
|
232
|
-
<tr>
|
233
|
-
<td><tt>403</tt></td>
|
234
|
-
<td><tt>1030</tt></td>
|
235
|
-
<td><tt></tt></td>
|
236
|
-
<td>SSL required for this type of request</td>
|
237
|
-
</tr>
|
238
|
-
<tr>
|
239
|
-
<td><tt>400</tt></td>
|
240
|
-
<td><tt>1035</tt></td>
|
241
|
-
<td><tt></tt></td>
|
242
|
-
<td>POST data not supplied as valid JSON. Issued if the <tt>Content-Type</tt> header is not <tt>application/json/</tt> and/or if the POST data is not in valid JSON format.</td>
|
243
|
-
</tr>
|
244
|
-
<tr>
|
245
|
-
<td><tt>400</tt></td>
|
246
|
-
<td><tt>1040</tt></td>
|
247
|
-
<td><tt></tt></td>
|
248
|
-
<td>The <tt>_filter</tt> syntax was invalid or a specified field to search on does not exist</td>
|
249
|
-
</tr>
|
250
|
-
<tr>
|
251
|
-
<td><tt>400</tt></td>
|
252
|
-
<td><tt>1050</tt></td>
|
253
|
-
<td><tt></tt></td>
|
254
|
-
<td>(message varies) A required parameter was not provided</td>
|
255
|
-
</tr>
|
256
|
-
<tr>
|
257
|
-
<td><tt>400</tt></td>
|
258
|
-
<td><tt>1053</tt></td>
|
259
|
-
<td><tt></tt></td>
|
260
|
-
<td>(message varies) A parameter was provided but does not adhere to constraints</td>
|
261
|
-
</tr>
|
262
|
-
<tr>
|
263
|
-
<td><tt>409</tt></td>
|
264
|
-
<td><tt>1055</tt></td>
|
265
|
-
<td><tt></tt></td>
|
266
|
-
<td>(message varies)Issued when a write is requested that will conflict with existing data. For example, adding a new contact with an e-mail that already exists.</td>
|
267
|
-
</tr>
|
268
|
-
<tr>
|
269
|
-
<td><tt>403</tt></td>
|
270
|
-
<td><tt>1500</tt></td>
|
271
|
-
<td><tt></tt></td>
|
272
|
-
<td>The resource is not available at the current API key's service level. For example, this error applies if a user attempts to access the IDX Links API via a free API key. </td>
|
273
|
-
</tr>
|
274
|
-
<tr>
|
275
|
-
<td><tt>503</tt></td>
|
276
|
-
<td><tt>1550</tt></td>
|
277
|
-
<td><tt></tt></td>
|
278
|
-
<td>Over rate limit</td>
|
279
|
-
</tbody>
|
280
|
-
</table>
|
281
|
-
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
data/lib/spark_api.rb
CHANGED
@@ -43,6 +43,7 @@ module SparkApi
|
|
43
43
|
escaped_path = URI.escape(path)
|
44
44
|
connection = @client.connection(true) # SSL Only!
|
45
45
|
connection.headers.merge!(self.auth_header)
|
46
|
+
options.merge!(:ApiUser => "#{@client.api_user}") unless @client.api_user.nil?
|
46
47
|
parameter_string = options.size > 0 ? "?#{build_url_parameters(options)}" : ""
|
47
48
|
request_path = "#{escaped_path}#{parameter_string}"
|
48
49
|
SparkApi.logger.debug("Request: #{request_path}")
|
@@ -67,19 +68,42 @@ module SparkApi
|
|
67
68
|
}
|
68
69
|
"#{@provider.authorization_uri}?#{build_url_parameters(params)}"
|
69
70
|
end
|
70
|
-
|
71
|
+
|
72
|
+
# Create a sparkbar token based on the current user's access token
|
73
|
+
def sparkbar_token()
|
74
|
+
raise ClientError, "OAuth2Provider must configure the sparkbar_uri to use sparkbar tokens" if provider.sparkbar_uri.nil?
|
75
|
+
SparkApi.logger.debug("[sparkbar] create token to #{provider.sparkbar_uri}")
|
76
|
+
uri = URI.parse(provider.sparkbar_uri)
|
77
|
+
request_path = "#{uri.path}"
|
78
|
+
|
79
|
+
SparkApi.logger.info("[sparkbar] create token to #{request_path}, #{session.access_token.inspect}")
|
80
|
+
response = sparkbar_connection("#{uri.scheme}://#{uri.host}").post(request_path, "access_token=#{session.access_token}").body
|
81
|
+
token = response["token"]
|
82
|
+
SparkApi.logger.debug("[sparkbar] New token created #{token}")
|
83
|
+
token
|
84
|
+
end
|
85
|
+
|
71
86
|
protected
|
72
87
|
|
88
|
+
attr_reader :provider, :client
|
89
|
+
|
73
90
|
def auth_header
|
74
91
|
{"Authorization"=> "OAuth #{session.access_token}"}
|
75
92
|
end
|
76
93
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
94
|
+
# Faraday handle to the sparkbar
|
95
|
+
def sparkbar_connection(endpoint)
|
96
|
+
opts = {
|
97
|
+
:headers => client.headers
|
98
|
+
}
|
99
|
+
opts[:headers].delete(:content_type)
|
100
|
+
opts[:ssl] = {:verify => false } unless @client.ssl_verify
|
101
|
+
opts[:url] = endpoint
|
102
|
+
conn = Faraday::Connection.new(opts) do |conn|
|
103
|
+
conn.response :sparkbar_impl
|
104
|
+
conn.adapter Faraday.default_adapter
|
105
|
+
end
|
106
|
+
end
|
83
107
|
|
84
108
|
end
|
85
109
|
|
@@ -142,16 +166,21 @@ module SparkApi
|
|
142
166
|
end
|
143
167
|
# Is the user session token expired?
|
144
168
|
def expired?
|
169
|
+
return false if @expires_in.nil?
|
145
170
|
@start_time + Rational(@expires_in - @refresh_timeout, 86400) < DateTime.now
|
146
171
|
end
|
147
172
|
|
148
173
|
def to_json(*a)
|
174
|
+
to_hash.to_json(*a)
|
175
|
+
end
|
176
|
+
|
177
|
+
def to_hash
|
149
178
|
hash = {}
|
150
179
|
SESSION_ATTRIBUTES.each do |k|
|
151
180
|
value = self.send(k)
|
152
181
|
hash[k.to_s] = value unless value.nil?
|
153
182
|
end
|
154
|
-
hash
|
183
|
+
hash
|
155
184
|
end
|
156
185
|
end
|
157
186
|
|
@@ -222,8 +251,9 @@ module SparkApi
|
|
222
251
|
require 'spark_api/authentication/oauth2_impl/grant_type_refresh'
|
223
252
|
require 'spark_api/authentication/oauth2_impl/grant_type_code'
|
224
253
|
require 'spark_api/authentication/oauth2_impl/grant_type_password'
|
225
|
-
require 'spark_api/authentication/oauth2_impl/
|
254
|
+
require 'spark_api/authentication/oauth2_impl/cli_provider'
|
226
255
|
require 'spark_api/authentication/oauth2_impl/simple_provider'
|
256
|
+
require 'spark_api/authentication/oauth2_impl/single_session_provider'
|
227
257
|
|
228
258
|
# Loads a provider class from a string
|
229
259
|
def self.load_provider(string, args={})
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require "highline/import"
|
2
|
+
|
3
|
+
module SparkApi
|
4
|
+
module Authentication
|
5
|
+
module OAuth2Impl
|
6
|
+
class CLIProvider < SparkApi::Authentication::BaseOAuth2Provider
|
7
|
+
SESSION_FILE = '.spark_api_oauth2'
|
8
|
+
|
9
|
+
def initialize(credentials)
|
10
|
+
super(credentials)
|
11
|
+
@grant_type = :password
|
12
|
+
@persistent_sessions = false
|
13
|
+
@session_alias = "default"
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_accessor :persistent_sessions, :session_alias
|
17
|
+
|
18
|
+
def redirect(url)
|
19
|
+
puts "Missing OAuth2 session, redirecting..."
|
20
|
+
puts "Please visit #{url}, login as a user, and paste the authorization code here:"
|
21
|
+
self.code = ask("Authorization code?") do |q|
|
22
|
+
q.whitespace = :strip_and_collapse
|
23
|
+
q.validate = /^\w+$/
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def load_session()
|
28
|
+
@session ||= load_persistent_session
|
29
|
+
end
|
30
|
+
|
31
|
+
def save_session(session)
|
32
|
+
@session = session
|
33
|
+
save_persistent_session
|
34
|
+
end
|
35
|
+
|
36
|
+
def destroy_session
|
37
|
+
destroy_persistent_session
|
38
|
+
@session = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def persistent_sessions?
|
42
|
+
persistent_sessions == true
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def load_persistent_session
|
48
|
+
return nil unless persistent_sessions?
|
49
|
+
s = load_file[session_key]["session"]
|
50
|
+
OAuthSession.new(s)
|
51
|
+
rescue => e
|
52
|
+
puts "no file: #{e.message}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def save_persistent_session
|
56
|
+
return unless persistent_sessions? && !@session.nil?
|
57
|
+
yaml = load_file
|
58
|
+
unless yaml.include? session_key
|
59
|
+
yaml[session_key] = {}
|
60
|
+
yaml[session_key]["created"] = Time.now
|
61
|
+
end
|
62
|
+
yaml[session_key]["session"] = @session.to_hash
|
63
|
+
yaml[session_key]["modified"] = Time.now
|
64
|
+
File.open(filename, "w") {|f| f.write(yaml.to_yaml) }
|
65
|
+
end
|
66
|
+
|
67
|
+
def session_key
|
68
|
+
"#{client_id}_#{session_alias}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def destroy_persistent_session
|
72
|
+
return unless persistent_sessions?
|
73
|
+
yaml = load_file
|
74
|
+
return unless yaml.include? session_key
|
75
|
+
yaml[session_key].delete("session")
|
76
|
+
File.open(filename, "w") {|f| f.write(yaml.to_yaml) }
|
77
|
+
end
|
78
|
+
|
79
|
+
def filename
|
80
|
+
ENV['HOME'] + "/" + SESSION_FILE
|
81
|
+
end
|
82
|
+
|
83
|
+
def load_file
|
84
|
+
yaml = {}
|
85
|
+
begin
|
86
|
+
yaml = YAML.load(File.open(filename))
|
87
|
+
yaml = {} if yaml == false
|
88
|
+
rescue => e
|
89
|
+
puts "no file: #{e.message}"
|
90
|
+
end
|
91
|
+
yaml
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|