stormpath-sdk 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|