stormpath-sdk 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +12 -0
- data/lib/stormpath-sdk.rb +4 -0
- data/lib/stormpath-sdk/data_store.rb +172 -166
- data/lib/stormpath-sdk/provider/account_request.rb +5 -6
- data/lib/stormpath-sdk/provider/account_resolver.rb +27 -12
- data/lib/stormpath-sdk/provider/twitter/twitter_provider.rb +18 -0
- data/lib/stormpath-sdk/provider/twitter/twitter_provider_data.rb +18 -0
- data/lib/stormpath-sdk/resource/account_linking_policy.rb +21 -0
- data/lib/stormpath-sdk/resource/application.rb +7 -5
- data/lib/stormpath-sdk/resource/application_web_config.rb +9 -0
- data/lib/stormpath-sdk/resource/field.rb +2 -1
- data/lib/stormpath-sdk/resource/organization.rb +2 -1
- data/lib/stormpath-sdk/version.rb +2 -2
- data/spec/auth/basic_authenticator_spec.rb +100 -13
- data/spec/provider/account_resolver_spec.rb +34 -10
- data/spec/provider/provider_spec.rb +21 -6
- data/spec/resource/account_linking_policy_spec.rb +31 -0
- data/spec/resource/application_spec.rb +44 -2
- data/spec/resource/application_web_config_spec.rb +65 -0
- data/spec/resource/collection_spec.rb +2 -2
- data/spec/resource/directory_spec.rb +7 -0
- data/spec/resource/organization_spec.rb +1 -0
- data/spec/resource/schema_spec.rb +10 -2
- data/spec/spec_helper.rb +1 -0
- data/spec/support/custom_data_save_period.rb +12 -0
- data/spec/support/mocked_provider_accounts.rb +30 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39b0f751a08c13d32addaf304b2b82edeaa4c0bf
|
4
|
+
data.tar.gz: 03136baf262d23ca52d8580c809500a53c95be39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be90405ab987f48232ac9bb0cfd55272de9baff5f3e4ae04cb019f92a4ebf740a42181a20b14f63215def4ec1fd2fa1e541a2a560b6887b485c91399358cbb8b
|
7
|
+
data.tar.gz: d48ed19deab4469407c6337fdaea4f87eea74fb8f10e943055a95fdc486988da443e17f45b334d00defe860f519635d60928804793aacf498b6a9c8062fe8852
|
data/CHANGES.md
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
stormpath-sdk-ruby Changelog
|
2
2
|
============================
|
3
3
|
|
4
|
+
Version 1.5.0
|
5
|
+
-------------
|
6
|
+
|
7
|
+
Released on January 24, 2017
|
8
|
+
|
9
|
+
- Create AccountLinkingPolicy resource and associate it to Application and Organization
|
10
|
+
- Create Twitter provider
|
11
|
+
- Implement ApplicationWebConfig on the Application resource
|
12
|
+
- Added more specs for basic authentication
|
13
|
+
- Refactor codebase
|
14
|
+
|
15
|
+
|
4
16
|
Version 1.4.0
|
5
17
|
-------------
|
6
18
|
|
data/lib/stormpath-sdk.rb
CHANGED
@@ -38,6 +38,7 @@ module Stormpath
|
|
38
38
|
autoload :Tenant, 'stormpath-sdk/resource/tenant'
|
39
39
|
autoload :LinkedAccount, 'stormpath-sdk/resource/linked_account'
|
40
40
|
autoload :AccountLink, 'stormpath-sdk/resource/account_link'
|
41
|
+
autoload :AccountLinkingPolicy, 'stormpath-sdk/resource/account_linking_policy'
|
41
42
|
autoload :Application, 'stormpath-sdk/resource/application'
|
42
43
|
autoload :Directory, 'stormpath-sdk/resource/directory'
|
43
44
|
autoload :Account, 'stormpath-sdk/resource/account'
|
@@ -52,6 +53,7 @@ module Stormpath
|
|
52
53
|
autoload :PasswordResetToken, 'stormpath-sdk/resource/password_reset_token'
|
53
54
|
autoload :VerificationEmail, 'stormpath-sdk/resource/verification_email'
|
54
55
|
autoload :OauthPolicy, 'stormpath-sdk/resource/oauth_policy'
|
56
|
+
autoload :ApplicationWebConfig, 'stormpath-sdk/resource/application_web_config'
|
55
57
|
autoload :AccessToken, 'stormpath-sdk/resource/access_token'
|
56
58
|
autoload :RefreshToken, 'stormpath-sdk/resource/refresh_token'
|
57
59
|
autoload :Organization, 'stormpath-sdk/resource/organization'
|
@@ -103,6 +105,8 @@ module Stormpath
|
|
103
105
|
autoload :LinkedinProviderData, 'stormpath-sdk/provider/linkedin/linkedin_provider_data'
|
104
106
|
autoload :GithubProvider, 'stormpath-sdk/provider/github/github_provider'
|
105
107
|
autoload :GithubProviderData, 'stormpath-sdk/provider/github/github_provider_data'
|
108
|
+
autoload :TwitterProvider, 'stormpath-sdk/provider/twitter/twitter_provider'
|
109
|
+
autoload :TwitterProviderData, 'stormpath-sdk/provider/twitter/twitter_provider_data'
|
106
110
|
autoload :SamlProvider, 'stormpath-sdk/provider/saml/saml_provider'
|
107
111
|
autoload :SamlProviderData, 'stormpath-sdk/provider/saml/saml_provider_data'
|
108
112
|
autoload :SamlProviderMetadata, 'stormpath-sdk/provider/saml/saml_provider_metadata'
|
@@ -118,231 +118,237 @@ class Stormpath::DataStore
|
|
118
118
|
|
119
119
|
private
|
120
120
|
|
121
|
-
|
122
|
-
|
123
|
-
|
121
|
+
def needs_to_be_fully_qualified?(href)
|
122
|
+
!href.downcase.start_with? 'http'
|
123
|
+
end
|
124
124
|
|
125
|
-
|
126
|
-
|
127
|
-
|
125
|
+
def qualify(href)
|
126
|
+
needs_to_be_fully_qualified?(href) ? @base_url + href : href
|
127
|
+
end
|
128
128
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
129
|
+
def execute_request(http_method, href, resource=nil, query=nil)
|
130
|
+
if http_method == 'get' && (cache = cache_for href)
|
131
|
+
cached_result = cache.get href
|
132
|
+
return cached_result if cached_result
|
133
|
+
end
|
134
134
|
|
135
|
-
|
135
|
+
body = extract_body_from_resource(resource)
|
136
136
|
|
137
|
-
|
137
|
+
request = Request.new(http_method, href, query, Hash.new, body, @api_key)
|
138
138
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
139
|
+
if resource.try(:form_data?)
|
140
|
+
apply_form_data_request_headers request
|
141
|
+
else
|
142
|
+
apply_default_request_headers request
|
143
|
+
end
|
144
144
|
|
145
|
-
|
145
|
+
response = @request_executor.execute_request request
|
146
146
|
|
147
|
-
|
147
|
+
result = response.body.length > 0 ? MultiJson.load(response.body) : ''
|
148
148
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
149
|
+
if response.error?
|
150
|
+
error = Stormpath::Resource::Error.new result
|
151
|
+
raise Stormpath::Error.new error
|
152
|
+
end
|
153
153
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
154
|
+
if resource.is_a? Stormpath::Provider::AccountAccess
|
155
|
+
is_new_account = response.http_status == 201
|
156
|
+
result = {is_new_account: is_new_account, account: result }
|
157
|
+
end
|
158
158
|
|
159
|
-
|
159
|
+
return if http_method == 'delete'
|
160
160
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
end
|
161
|
+
if result[HREF_PROP_NAME] and !resource_is_saml_mapping_rules? resource
|
162
|
+
cache_walk result
|
163
|
+
else
|
164
|
+
result
|
166
165
|
end
|
166
|
+
end
|
167
167
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
end
|
172
|
-
clear_cache href
|
168
|
+
def clear_cache_on_delete href
|
169
|
+
if href =~ custom_data_delete_field_url_regex
|
170
|
+
href = href.split('/')[0..-2].join('/')
|
173
171
|
end
|
172
|
+
clear_cache href
|
173
|
+
end
|
174
174
|
|
175
|
-
|
176
|
-
|
177
|
-
|
175
|
+
def custom_data_delete_field_url_regex
|
176
|
+
/#{@base_url}\/(accounts|groups)\/\w+\/customData\/\w+[\/]{0,1}$/
|
177
|
+
end
|
178
178
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
179
|
+
def clear_cache(href)
|
180
|
+
cache = cache_for href
|
181
|
+
cache.delete href if cache
|
182
|
+
end
|
183
183
|
|
184
|
-
|
185
|
-
|
186
|
-
|
184
|
+
def cache_walk(resource)
|
185
|
+
assert_not_nil resource[HREF_PROP_NAME], "resource must have 'href' property"
|
186
|
+
items = resource['items']
|
187
187
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
end
|
188
|
+
if items # collection resource
|
189
|
+
resource['items'] = items.map do |item|
|
190
|
+
cache_walk item
|
191
|
+
{ HREF_PROP_NAME => item[HREF_PROP_NAME] }
|
192
|
+
end
|
193
|
+
else # single resource
|
194
|
+
resource.each do |attr, value|
|
195
|
+
if value.is_a? Hash and value[HREF_PROP_NAME]
|
196
|
+
walked = cache_walk value
|
197
|
+
resource[attr] = { HREF_PROP_NAME => value[HREF_PROP_NAME] }
|
198
|
+
resource[attr]['items'] = walked['items'] if walked['items']
|
200
199
|
end
|
201
|
-
cache resource if resource.length > 1
|
202
200
|
end
|
203
|
-
resource
|
201
|
+
cache resource if resource.length > 1
|
204
202
|
end
|
203
|
+
resource
|
204
|
+
end
|
205
205
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
206
|
+
def cache(resource)
|
207
|
+
cache = cache_for resource[HREF_PROP_NAME]
|
208
|
+
cache.put resource[HREF_PROP_NAME], resource if cache
|
209
|
+
end
|
210
210
|
|
211
|
-
|
212
|
-
|
213
|
-
|
211
|
+
def cache_for(href)
|
212
|
+
@cache_manager.get_cache(region_for href)
|
213
|
+
end
|
214
214
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
end
|
222
|
-
CACHE_REGIONS.include?(region) ? region : nil
|
215
|
+
def region_for(href)
|
216
|
+
return nil if href.nil?
|
217
|
+
if href.include? "/customData"
|
218
|
+
region = href.split('/')[-1]
|
219
|
+
else
|
220
|
+
region = href.split('/')[-2]
|
223
221
|
end
|
222
|
+
CACHE_REGIONS.include?(region) ? region : nil
|
223
|
+
end
|
224
224
|
|
225
|
-
|
226
|
-
|
227
|
-
|
225
|
+
def apply_default_request_headers(request)
|
226
|
+
request.http_headers.store 'Accept', 'application/json'
|
227
|
+
apply_default_user_agent(request)
|
228
228
|
|
229
|
-
|
230
|
-
|
231
|
-
end
|
229
|
+
if request.body and request.body.length > 0
|
230
|
+
request.http_headers.store 'Content-Type', 'application/json'
|
232
231
|
end
|
232
|
+
end
|
233
233
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
234
|
+
def apply_form_data_request_headers(request)
|
235
|
+
request.http_headers.store 'Content-Type', 'application/x-www-form-urlencoded'
|
236
|
+
apply_default_user_agent(request)
|
237
|
+
end
|
238
238
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
239
|
+
def apply_default_user_agent(request)
|
240
|
+
request.http_headers.store 'User-Agent', 'stormpath-sdk-ruby/' + Stormpath::VERSION +
|
241
|
+
" ruby/#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}" +
|
242
|
+
" " + Gem::Platform.local.os.to_s + "/" + Gem::Platform.local.version.to_s
|
243
|
+
end
|
244
244
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
245
|
+
def save_resource(href, resource, return_type)
|
246
|
+
assert_not_nil resource, "resource argument cannot be null."
|
247
|
+
assert_not_nil return_type, "returnType class cannot be null."
|
248
|
+
assert_kind_of Stormpath::Resource::Base, resource, "resource argument must be instance of Stormpath::Resource::Base"
|
249
249
|
|
250
|
-
|
250
|
+
q_href = qualify href
|
251
251
|
|
252
|
-
|
252
|
+
clear_cache_on_save(resource)
|
253
253
|
|
254
|
-
|
254
|
+
response = execute_request 'post', q_href, resource
|
255
255
|
|
256
|
-
|
257
|
-
|
256
|
+
instantiate return_type, parse_response(response)
|
257
|
+
end
|
258
258
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
259
|
+
def parse_response(response)
|
260
|
+
return {} if response.is_a? String and response.blank?
|
261
|
+
response.to_hash
|
262
|
+
end
|
263
263
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
end
|
264
|
+
def clear_cache_on_save(resource)
|
265
|
+
if resource.is_a? Stormpath::Resource::CustomDataStorage
|
266
|
+
clear_custom_data_cache_on_custom_data_storage_save(resource)
|
267
|
+
elsif resource.is_a? Stormpath::Resource::AccountStoreMapping
|
268
|
+
clear_application_cache_on_account_store_save(resource)
|
270
269
|
end
|
270
|
+
end
|
271
271
|
|
272
272
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
end
|
273
|
+
def clear_custom_data_cache_on_custom_data_storage_save resource
|
274
|
+
if resource.dirty_properties.has_key? "customData" and resource.new? == false
|
275
|
+
cached_href = resource.href + "/customData"
|
276
|
+
clear_cache cached_href
|
278
277
|
end
|
278
|
+
end
|
279
279
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
end
|
285
|
-
else
|
286
|
-
if resource.dirty_properties["isDefaultAccountStore"] != nil || resource.dirty_properties["isDefaultGroupStore"] != nil
|
287
|
-
clear_cache resource.application.href
|
288
|
-
end
|
280
|
+
def clear_application_cache_on_account_store_save resource
|
281
|
+
if resource.new?
|
282
|
+
if resource.default_account_store? == true || resource.default_group_store? == true
|
283
|
+
clear_cache resource.application.href
|
289
284
|
end
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
return if resource.nil?
|
294
|
-
form_data = resource.try(:form_data?)
|
295
|
-
|
296
|
-
if form_data
|
297
|
-
form_request_parse(resource)
|
298
|
-
else
|
299
|
-
MultiJson.dump(to_hash(resource))
|
285
|
+
else
|
286
|
+
if resource.dirty_properties["isDefaultAccountStore"] != nil || resource.dirty_properties["isDefaultGroupStore"] != nil
|
287
|
+
clear_cache resource.application.href
|
300
288
|
end
|
301
289
|
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def extract_body_from_resource(resource)
|
293
|
+
return if resource.nil?
|
294
|
+
form_data = resource.try(:form_data?)
|
302
295
|
|
303
|
-
|
304
|
-
|
296
|
+
if form_data
|
297
|
+
form_request_parse(resource)
|
298
|
+
else
|
299
|
+
MultiJson.dump(to_hash(resource))
|
305
300
|
end
|
301
|
+
end
|
306
302
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
ignore_camelcasing = resource_is_custom_data(resource, name)
|
311
|
-
property = resource.get_property name, ignore_camelcasing: ignore_camelcasing
|
303
|
+
def form_request_parse(resource)
|
304
|
+
URI.encode_www_form(resource.form_properties.to_a)
|
305
|
+
end
|
312
306
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
307
|
+
def to_hash(resource)
|
308
|
+
{}.tap do |properties|
|
309
|
+
resource.get_dirty_property_names.each do |name|
|
310
|
+
ignore_camelcasing = resource_is_custom_data(resource, name)
|
311
|
+
property = resource.get_property name, ignore_camelcasing: ignore_camelcasing
|
318
312
|
|
319
|
-
|
320
|
-
|
321
|
-
|
313
|
+
# Special use cases are with Custom Data, Provider and ProviderData, their hashes should not be simplified
|
314
|
+
# As of the implementation for MFA, Phone resource is added too
|
315
|
+
if property.is_a?(Hash) && !resource_nested_submittable(resource, name) && name != 'items' && name != 'phone'
|
316
|
+
property = to_simple_reference name, property
|
317
|
+
end
|
322
318
|
|
323
|
-
|
319
|
+
if name == 'items' && resource_is_saml_mapping_rules?(resource)
|
320
|
+
property = property.map { |item| item.transform_keys { |key| key.to_s.camelize(:lower).to_sym } }
|
324
321
|
end
|
322
|
+
|
323
|
+
properties.store name, property
|
325
324
|
end
|
326
325
|
end
|
326
|
+
end
|
327
327
|
|
328
|
-
|
329
|
-
|
328
|
+
def to_simple_reference(property_name, hash)
|
329
|
+
assert_true hash.key?(HREF_PROP_NAME), "Nested resource '#{property_name}' must have an 'href' property."
|
330
330
|
|
331
|
-
|
331
|
+
href = hash[HREF_PROP_NAME]
|
332
332
|
|
333
|
-
|
334
|
-
|
333
|
+
{ HREF_PROP_NAME => href }
|
334
|
+
end
|
335
335
|
|
336
|
-
|
337
|
-
|
338
|
-
|
336
|
+
def resource_nested_submittable(resource, name)
|
337
|
+
['provider', 'providerData', 'accountStore'].include?(name) ||
|
338
|
+
resource_is_custom_data(resource, name) ||
|
339
|
+
resource_is_application_web_config(resource, name)
|
340
|
+
end
|
339
341
|
|
340
|
-
|
341
|
-
|
342
|
-
|
342
|
+
def resource_is_custom_data(resource, name)
|
343
|
+
resource.is_a?(Stormpath::Resource::CustomData) || name == 'customData'
|
344
|
+
end
|
343
345
|
|
344
|
-
|
345
|
-
|
346
|
-
|
346
|
+
def resource_is_application_web_config(resource, name)
|
347
|
+
resource.is_a?(Stormpath::Resource::ApplicationWebConfig) &&
|
348
|
+
Stormpath::Resource::ApplicationWebConfig::ENDPOINTS.include?(name.underscore.to_sym)
|
349
|
+
end
|
347
350
|
|
351
|
+
def resource_is_saml_mapping_rules?(resource)
|
352
|
+
resource.is_a?(Stormpath::Provider::SamlMappingRules)
|
353
|
+
end
|
348
354
|
end
|