stormpath-sdk 0.2.0 → 0.3.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.
- data/CHANGES.md +31 -0
- data/README.md +3 -0
- data/lib/stormpath-sdk.rb +2 -0
- data/lib/stormpath-sdk/auth/username_password_request.rb +1 -1
- data/lib/stormpath-sdk/client/client_application.rb +38 -0
- data/lib/stormpath-sdk/client/client_application_builder.rb +351 -0
- data/lib/stormpath-sdk/client/client_builder.rb +14 -15
- data/lib/stormpath-sdk/ds/data_store.rb +39 -4
- data/lib/stormpath-sdk/ds/resource_factory.rb +1 -1
- data/lib/stormpath-sdk/resource/account.rb +5 -0
- data/lib/stormpath-sdk/resource/resource.rb +154 -15
- data/lib/stormpath-sdk/util/assert.rb +7 -0
- data/lib/stormpath-sdk/version.rb +2 -2
- data/test/client/client_application_builder_spec.rb +114 -0
- data/test/client/{clientbuilder_spec.rb → client_builder_spec.rb} +0 -0
- data/test/client/read_spec.rb +13 -0
- data/test/client/write_spec.rb +64 -9
- data/test/resource/resource_spec.rb +41 -0
- data/test/resource/test_resource.rb +28 -0
- metadata +15 -5
data/CHANGES.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
stormpath-sdk-ruby Changelog
|
2
|
+
====================
|
3
|
+
|
4
|
+
Version 0.3.0
|
5
|
+
-------------
|
6
|
+
|
7
|
+
Released on August 31, 2012
|
8
|
+
|
9
|
+
- The properties method is now protected, only available for the resources hierarchy. The properties on the data store are now obtained via Stormpath::Resource::Resource's get_property_names and get_property functions.
|
10
|
+
- The 'inspect' and 'to_s' methods were overridden in Stormpath::Resource::Resource to keep some properties (like password) from being displayed.
|
11
|
+
- Logic to retain non-persisted properties was added (dirty properties).
|
12
|
+
- A resource's property can now be removed by setting it to nil.
|
13
|
+
- The Stormpath::Client::ClientApplicationBuilder class was added and implemented to produce a Stormpath::Client::ClientApplication from a single URL with the credentials on it.
|
14
|
+
|
15
|
+
|
16
|
+
Version 0.2.0
|
17
|
+
-------------
|
18
|
+
|
19
|
+
Released on August 20, 2012
|
20
|
+
|
21
|
+
- Result of the Application authentication was changed from Account to AuthenticationResult.
|
22
|
+
- The password verification's method name for token creation on the Application class was changed to 'send_password_reset_email'.
|
23
|
+
- The 'verify_password_reset_token' method on the Application class now returns an Account instead of a PasswordResetToken.
|
24
|
+
- The API RDOC was updated for the previously modified implementations on the Application class.
|
25
|
+
|
26
|
+
Version 0.1.0
|
27
|
+
-------------
|
28
|
+
|
29
|
+
Released on July 27, 2012
|
30
|
+
|
31
|
+
- First release of the Stormpath Ruby SDK where all of the features available on the REST API by the release date were implemented.
|
data/README.md
CHANGED
data/lib/stormpath-sdk.rb
CHANGED
@@ -13,6 +13,8 @@ require "stormpath-sdk/client/api_key"
|
|
13
13
|
require "stormpath-sdk/client/client"
|
14
14
|
require "stormpath-sdk/util/hash"
|
15
15
|
require "stormpath-sdk/client/client_builder"
|
16
|
+
require "stormpath-sdk/client/client_application"
|
17
|
+
require "stormpath-sdk/client/client_application_builder"
|
16
18
|
require "stormpath-sdk/auth/username_password_request"
|
17
19
|
require "stormpath-sdk/resource/status"
|
18
20
|
require "stormpath-sdk/resource/utils"
|
@@ -21,7 +21,7 @@ module Stormpath
|
|
21
21
|
|
22
22
|
attr_reader :host
|
23
23
|
|
24
|
-
def initialize username, password, host
|
24
|
+
def initialize username, password, host = nil
|
25
25
|
@username = username
|
26
26
|
@password = (password != nil and password.length > 0) ? password.chars.to_a : "".chars.to_a
|
27
27
|
@host = host
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2012 Stormpath, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
module Stormpath
|
17
|
+
|
18
|
+
module Client
|
19
|
+
|
20
|
+
# A ClientApplication is a simple wrapper around a {@link Stormpath::Client::Client} and
|
21
|
+
# {@link Stormpath::Resource::Application} instance, returned from
|
22
|
+
# the {@code ClientApplicationBuilder}.{@link Stormpath::Client::ClientApplicationBuilder#build_application}
|
23
|
+
# method.
|
24
|
+
# @since 0.3.0
|
25
|
+
class ClientApplication
|
26
|
+
|
27
|
+
attr_reader :client, :application
|
28
|
+
|
29
|
+
def initialize client, application
|
30
|
+
@client = client
|
31
|
+
@application = application
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,351 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2012 Stormpath, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
module Stormpath
|
17
|
+
|
18
|
+
module Client
|
19
|
+
|
20
|
+
##
|
21
|
+
# A <a href="http://en.wikipedia.org/wiki/Builder_pattern">Builder design pattern</a> implementation similar to
|
22
|
+
# the {@link Stormpath::Client::ClientBuilder}, but focused on single-application interaction with Stormpath.
|
23
|
+
# <h2>Description</h2>
|
24
|
+
# The {@code ClientBuilder} produces a {@link Stormpath::Client::Client} instance useful for interacting with any aspect
|
25
|
+
# of an entire Stormpath Tenant's data space. However, a software application may only be interested in its own
|
26
|
+
# functionality and not the entire Stormpath Tenant data space.
|
27
|
+
# <p/>
|
28
|
+
# The {@code ClientApplicationBuilder} provides a means to more easily acquiring a single
|
29
|
+
# {@link Stormpath::Resource::Application} instance. From this {@code Application} instance, everything a particular
|
30
|
+
# Application needs to perform can be based off of this instance and the wider-scoped concerns of an entire Tenant can be ignored.
|
31
|
+
# <h2>Default Usage</h2>
|
32
|
+
# <pre>
|
33
|
+
# # this can be a file disk or url location as well:
|
34
|
+
# location = "/home/jsmith/.stormpath/apiKey.yml"
|
35
|
+
#
|
36
|
+
# app_href = "https://api.stormpath.com/v1/applications/YOUR_APP_UID_HERE"
|
37
|
+
#
|
38
|
+
# application = new ClientApplicationBuilder.new.
|
39
|
+
# set_api_key_file_location(location).
|
40
|
+
# <b>set_application_href(app_href)</b>.
|
41
|
+
# build.
|
42
|
+
# application
|
43
|
+
# </pre>
|
44
|
+
# <p/>
|
45
|
+
# After acquiring the {@code Application} instance, you can interact with it to login accounts, reset passwords,
|
46
|
+
# etc.
|
47
|
+
# <h2>Service Provider Usage with only an Application URL</h2>
|
48
|
+
# Some hosting service providers (e.g. like <a href="http://www.heroku.com">Heroku</a>) do not allow easy access to
|
49
|
+
# a configuration file and therefore it might be difficult to reference an API Key File. If you cannot reference an
|
50
|
+
# API Key File via the {@code YAML file} or {@code YAML object} or {@code url}
|
51
|
+
# {@link ClientBuilder#set_api_key_file_location(String) resource locations}, the Application HREF URL must contain the
|
52
|
+
# API Key embedded as the <em><a href="http://en.wikipedia.org/wiki/URI_scheme">user info</a></em> portion of the
|
53
|
+
# URL. For example:
|
54
|
+
# <p/>
|
55
|
+
# <pre>
|
56
|
+
# https://<b>apiKeyId:apiKeySecret@</b>api.stormpath.com/v1/applications/YOUR_APP_UID_HERE
|
57
|
+
# </pre>
|
58
|
+
# <p/>
|
59
|
+
# Notice this is just a normal Application HREF url with the <b>apiKeyId:apiKeySecret@</b> part added in.
|
60
|
+
# <p/>
|
61
|
+
# Example usage:
|
62
|
+
# <pre>
|
63
|
+
# appHref = "https://<b>apiKeyId:apiKeySecret@</b>api.stormpath.com/v1/applications/YOUR_APP_UID_HERE";
|
64
|
+
#
|
65
|
+
# application = new ClientApplicationBuilder.new.
|
66
|
+
# <b>set_application_href(appHref)</b>.
|
67
|
+
# build.
|
68
|
+
# application
|
69
|
+
# </pre>
|
70
|
+
# <p/>
|
71
|
+
# <b>WARNING: ONLY use the embedded API Key technique if you do not have access to {@code YAML file} or
|
72
|
+
# {@code YAML object} or {@code url} {@link ClientApplicationBuilder#set_api_key_file_location(String) resource locations}</b>.
|
73
|
+
# File based API Key storage is a more secure technique than embedding the key in the URL itself. Also, again,
|
74
|
+
# NEVER share your API Key Secret with <em>anyone</em> (not even co-workers).
|
75
|
+
# Stormpath staff will never ask for your API Key Secret.
|
76
|
+
#
|
77
|
+
# @see #set_api_key_file_location(String)
|
78
|
+
# @see #set_application_href(String)
|
79
|
+
# @since 0.3.0
|
80
|
+
#
|
81
|
+
class ClientApplicationBuilder
|
82
|
+
|
83
|
+
include Stormpath::Client
|
84
|
+
include Stormpath::Util::Assert
|
85
|
+
|
86
|
+
DOUBLE_SLASH = "//"
|
87
|
+
|
88
|
+
def initialize client_builder = ClientBuilder.new
|
89
|
+
|
90
|
+
assert_kind_of ClientBuilder, client_builder, 'client_builder must be kind of Stormpath::Client::ClientBuilder'
|
91
|
+
@client_builder = client_builder
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
# Allows usage of a YAML loadable object (IO object or the result of invoking Object.to_yaml)
|
96
|
+
# instead of loading a YAML file via {@link #set_api_key_file_location apiKeyFileLocation} configuration.
|
97
|
+
# <p/>
|
98
|
+
# The YAML contents and property name overrides function the same as described in the
|
99
|
+
# {@link #set_api_key_file_location setApiKeyFileLocation} RDoc.
|
100
|
+
#
|
101
|
+
# @param properties the YAML object to use to load the API Key ID and Secret.
|
102
|
+
# @return this ClientApplicationBuilder instance for method chaining.
|
103
|
+
def set_api_key_properties properties
|
104
|
+
|
105
|
+
@client_builder.set_api_key_properties properties
|
106
|
+
self
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
# Creates an API Key YAML object based on the specified File instead of loading a YAML
|
111
|
+
# file via {@link #set_api_key_file_location apiKeyFileLocation} configuration. This file argument
|
112
|
+
# needs to be an IO instance.
|
113
|
+
# <p/>
|
114
|
+
# The constructed YAML contents and property name overrides function the same as described in the
|
115
|
+
# {@link #set_api_key_file_location setApiKeyFileLocation} RDoc.
|
116
|
+
# @param file the file to use to construct a YAML object.
|
117
|
+
# @return this ClientApplicationBuilder instance for method chaining.
|
118
|
+
def set_api_key_file file
|
119
|
+
|
120
|
+
@client_builder.set_api_key_file file
|
121
|
+
self
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
# Sets the location of the YAML file to load containing the API Key (Id and secret) used by the
|
126
|
+
# Client to communicate with the Stormpath REST API.
|
127
|
+
# <p/>
|
128
|
+
# You may load files from the filesystem, or URLs just specifying the file location.
|
129
|
+
# <h3>File Contents</h3>
|
130
|
+
# <p/>
|
131
|
+
# When the file is loaded, the following name/value pairs are expected to be present by default:
|
132
|
+
# <table>
|
133
|
+
# <tr>
|
134
|
+
# <th>Key</th>
|
135
|
+
# <th>Value</th>
|
136
|
+
# </tr>
|
137
|
+
# <tr>
|
138
|
+
# <td>apiKey.id</td>
|
139
|
+
# <td>An individual account's API Key ID</td>
|
140
|
+
# </tr>
|
141
|
+
# <tr>
|
142
|
+
# <td>apiKey.secret</td>
|
143
|
+
# <td>The API Key Secret (password) that verifies the paired API Key ID.</td>
|
144
|
+
# </tr>
|
145
|
+
# </table>
|
146
|
+
# <p/>
|
147
|
+
# Assuming you were using these default property names, your {@code ClientApplicationBuilder} usage might look like the
|
148
|
+
# following:
|
149
|
+
# <pre>
|
150
|
+
# location = "/home/jsmith/.stormpath/apiKey.yml";
|
151
|
+
#
|
152
|
+
# application_href = 'https://<b>apiKeyId:apiKeySecret@</b>api.stormpath.com/v1/applications/YOUR_APP_UID_HERE'
|
153
|
+
#
|
154
|
+
# application = ClientApplicationBuilder.new.
|
155
|
+
# set_application_href(application_href).
|
156
|
+
# set_api_key_file_location(location).
|
157
|
+
# build.
|
158
|
+
# application
|
159
|
+
# </pre>
|
160
|
+
# <h3>Custom Property Names</h3>
|
161
|
+
# If you want to control the property names used in the file, you may configure them via
|
162
|
+
# {@link #set_api_key_id_property_name(String) set_api_key_id_property_name} and
|
163
|
+
# {@link #set_api_key_secret_property_name(String) set_api_key_secret_property_name}.
|
164
|
+
# <p/>
|
165
|
+
# For example, if you had a {@code /home/jsmith/.stormpath/apiKey.yml} file with the following
|
166
|
+
# name/value pairs:
|
167
|
+
# <pre>
|
168
|
+
# myStormpathApiKeyId = 'foo'
|
169
|
+
# myStormpathApiKeySecret = 'mySuperSecretValue'
|
170
|
+
# </pre>
|
171
|
+
# Your {@code ClientApplicationBuilder} usage would look like the following:
|
172
|
+
# <pre>
|
173
|
+
# location = "/home/jsmith/.stormpath/apiKey.yml";
|
174
|
+
#
|
175
|
+
# application = ClientApplicationBuilder.new.
|
176
|
+
# set_api_key_file_location(location).
|
177
|
+
# set_api_key_id_property_name("myStormpathApiKeyId").
|
178
|
+
# set_api_key_secret_property_name("myStormpathApiKeySecret").
|
179
|
+
# set_application_href(application_href).
|
180
|
+
# build.
|
181
|
+
# application
|
182
|
+
# </pre>
|
183
|
+
#
|
184
|
+
# @param location the file or url location of the API Key {@code .yml} file to load when
|
185
|
+
# constructing the API Key to use for communicating with the Stormpath REST API.
|
186
|
+
#
|
187
|
+
# @return this ClientApplicationBuilder instance for method chaining.
|
188
|
+
#/
|
189
|
+
def set_api_key_file_location location
|
190
|
+
|
191
|
+
@client_builder.set_api_key_file_location location
|
192
|
+
self
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
# Sets the name used to query for the API Key ID from a YAML instance. That is:
|
197
|
+
# <pre>
|
198
|
+
# apiKeyId = yml.access(<b>api_key_id_property_name</b>)
|
199
|
+
# </pre>
|
200
|
+
#
|
201
|
+
# The Hash#access method searches through the provided path and returns the found value.
|
202
|
+
#
|
203
|
+
# The <b>api_key_id_property_name</b> key can be as deep as needed, as long as it comes
|
204
|
+
# in the exact path order.
|
205
|
+
# Example: Having the file 'apiKey.yml' with the following content:
|
206
|
+
#
|
207
|
+
# stormpath:
|
208
|
+
# apiKey:
|
209
|
+
# id: myStormpathApiKeyId
|
210
|
+
#
|
211
|
+
# The method should be called as follows:
|
212
|
+
#
|
213
|
+
# ClientApplicationBuilder#set_api_key_id_property_name('stormpath', 'apiKey', 'id')
|
214
|
+
#
|
215
|
+
# @param api_key_id_property_name the name used to query for the API Key ID from a YAML instance.
|
216
|
+
# @return this ClientApplicationBuilder instance for method chaining.
|
217
|
+
def set_api_key_id_property_name *api_key_id_property_name
|
218
|
+
|
219
|
+
@client_builder.set_api_key_id_property_name *api_key_id_property_name
|
220
|
+
self
|
221
|
+
|
222
|
+
end
|
223
|
+
|
224
|
+
# Sets the name used to query for the API Key Secret from a YAML instance. That is:
|
225
|
+
# <pre>
|
226
|
+
# apiKeyId = yml.access(<b>api_key_secret_property_name</b>)
|
227
|
+
# </pre>
|
228
|
+
#
|
229
|
+
# The Hash#access method searches through the provided path and returns the found value.
|
230
|
+
#
|
231
|
+
# The <b>api_key_secret_property_name</b> key can be as deep as needed, as long as it comes
|
232
|
+
# in the exact path order.
|
233
|
+
# Example: Having the file 'apiKey.yml' with the following content:
|
234
|
+
#
|
235
|
+
# stormpath:
|
236
|
+
# apiKey:
|
237
|
+
# secret: myStormpathApiKeyId
|
238
|
+
#
|
239
|
+
# The method should be called as follows:
|
240
|
+
#
|
241
|
+
# ClientApplicationBuilder#set_api_key_id_property_name('stormpath', 'apiKey', 'secret')
|
242
|
+
#
|
243
|
+
# @param api_key_secret_property_name the name used to query for the API Key Secret from a YAML instance.
|
244
|
+
# @return this ClientApplicationBuilder instance for method chaining.
|
245
|
+
def set_api_key_secret_property_name *api_key_secret_property_name
|
246
|
+
|
247
|
+
@client_builder.set_api_key_secret_property_name *api_key_secret_property_name
|
248
|
+
self
|
249
|
+
|
250
|
+
end
|
251
|
+
|
252
|
+
##
|
253
|
+
# Sets the fully qualified Stormpath Application HREF (a URL) to use to acquire the Application instance when
|
254
|
+
# {@link #build_application} is called. See the Class-level RDoc for usage scenarios.
|
255
|
+
#
|
256
|
+
# @param applicationHref the fully qualified Stormpath Application HREF (a URL) to use to acquire the
|
257
|
+
# Application instance when {@link #build_application} is called.
|
258
|
+
# @return this ClientApplicationBuilder instance for method chaining.
|
259
|
+
def set_application_href application_href
|
260
|
+
|
261
|
+
@application_href = application_href
|
262
|
+
self
|
263
|
+
|
264
|
+
end
|
265
|
+
|
266
|
+
# Builds a Client and Application wrapper instance based on the configured
|
267
|
+
# {@link #set_application_href}. See the Class-level RDoc for usage scenarios.
|
268
|
+
#
|
269
|
+
# @return a Client and Application wrapper instance based on the configured {@link #set_application_href}.
|
270
|
+
def build
|
271
|
+
|
272
|
+
href = !@application_href.nil? ? @application_href.strip : nil
|
273
|
+
|
274
|
+
assert_false (href.nil? or href.empty?),
|
275
|
+
"'application_href' property must be specified when using this builder implementation."
|
276
|
+
|
277
|
+
|
278
|
+
cleaned_href = href
|
279
|
+
|
280
|
+
at_sigh_index = href.index '@'
|
281
|
+
|
282
|
+
if !at_sigh_index.nil?
|
283
|
+
|
284
|
+
parts = get_href_with_user_info href, at_sigh_index
|
285
|
+
|
286
|
+
cleaned_href = parts[0] + parts[2]
|
287
|
+
|
288
|
+
parts = parts[1].split ':', 2
|
289
|
+
|
290
|
+
api_key_properties = create_api_key_properties parts
|
291
|
+
|
292
|
+
set_api_key_properties api_key_properties
|
293
|
+
|
294
|
+
end #otherwise an apiKey File/YAML/etc for the API Key is required
|
295
|
+
|
296
|
+
client = build_client
|
297
|
+
|
298
|
+
application = client.data_store.get_resource cleaned_href, Application
|
299
|
+
|
300
|
+
ClientApplication.new client, application
|
301
|
+
|
302
|
+
end
|
303
|
+
|
304
|
+
protected
|
305
|
+
|
306
|
+
def build_client
|
307
|
+
@client_builder.build
|
308
|
+
end
|
309
|
+
|
310
|
+
def get_href_with_user_info href, at_sign_index
|
311
|
+
|
312
|
+
assert_kind_of String, href, 'href must be kind of String'
|
313
|
+
assert_kind_of Fixnum, at_sign_index, 'at_sign_index must be kind of Fixnum'
|
314
|
+
|
315
|
+
double_slash_index = href.index DOUBLE_SLASH
|
316
|
+
|
317
|
+
assert_not_nil double_slash_index, 'Invalid application href URL'
|
318
|
+
|
319
|
+
parts = Array.new 3
|
320
|
+
|
321
|
+
parts[0] = href[0..double_slash_index + 1] #up to and including the double slash
|
322
|
+
parts[1] = href[double_slash_index + DOUBLE_SLASH.length..at_sign_index -1] #raw user info
|
323
|
+
parts[2] = href[at_sign_index + 1..href.length - 1] #after the @ character
|
324
|
+
|
325
|
+
parts
|
326
|
+
|
327
|
+
end
|
328
|
+
|
329
|
+
def create_api_key_properties pair
|
330
|
+
|
331
|
+
assert_kind_of Array, pair, 'pair must be kind of Array'
|
332
|
+
|
333
|
+
assert_true (pair.length == 2), 'application_href userInfo segment must consist' +
|
334
|
+
' of the following format: apiKeyId:apiKeySecret'
|
335
|
+
|
336
|
+
properties = Hash.new
|
337
|
+
properties.store 'apiKey.id', url_decode(pair[0])
|
338
|
+
properties.store 'apiKey.secret', url_decode(pair[1])
|
339
|
+
|
340
|
+
properties.to_yaml
|
341
|
+
|
342
|
+
end
|
343
|
+
|
344
|
+
def url_decode url
|
345
|
+
URI.decode url
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
end
|
350
|
+
|
351
|
+
end
|
@@ -28,7 +28,7 @@ module Stormpath
|
|
28
28
|
# <pre>
|
29
29
|
# location = "/home/jsmith/.stormpath/apiKey.yml";
|
30
30
|
#
|
31
|
-
# client = ClientBuilder.new.set_api_key_file_location(location).build
|
31
|
+
# client = ClientBuilder.new.set_api_key_file_location(location).build
|
32
32
|
# </pre>
|
33
33
|
# <p/>
|
34
34
|
# You may load files from the filesystem or URLs by specifying the file location.
|
@@ -102,14 +102,14 @@ module Stormpath
|
|
102
102
|
# <pre>
|
103
103
|
# location = "/home/jsmith/.stormpath/apiKey.yml";
|
104
104
|
#
|
105
|
-
# client = ClientBuilder.new.set_api_key_file_location(location).build
|
105
|
+
# client = ClientBuilder.new.set_api_key_file_location(location).build
|
106
106
|
# </pre>
|
107
107
|
# <h3>Custom Property Names</h3>
|
108
108
|
# If you want to control the property names used in the file, you may configure them via
|
109
109
|
# {@link #set_api_key_id_property_name(String) set_api_key_id_property_name} and
|
110
110
|
# {@link #set_api_key_secret_property_name(String) set_api_key_secret_property_name}.
|
111
111
|
# <p/>
|
112
|
-
# For example, if you had a {@code /home/jsmith/.stormpath/apiKey.
|
112
|
+
# For example, if you had a {@code /home/jsmith/.stormpath/apiKey.yml} file with the following
|
113
113
|
# name/value pairs:
|
114
114
|
# <pre>
|
115
115
|
# myStormpathApiKeyId = 'foo'
|
@@ -133,9 +133,11 @@ module Stormpath
|
|
133
133
|
# @return the ClientBuilder instance for method chaining.
|
134
134
|
#/
|
135
135
|
def set_api_key_file_location location
|
136
|
+
|
136
137
|
assert_kind_of String, location, 'location must be kind of String'
|
137
138
|
@api_key_file_location = location
|
138
139
|
self
|
140
|
+
|
139
141
|
end
|
140
142
|
|
141
143
|
|
@@ -209,11 +211,9 @@ module Stormpath
|
|
209
211
|
|
210
212
|
file = get_available_file
|
211
213
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
"YAML loadable instance."
|
216
|
-
end
|
214
|
+
assert_not_nil file, "No API Key file could be found or loaded from a file location. Please " +
|
215
|
+
"configure the 'apiKeyFileLocation' property or alternatively configure a " +
|
216
|
+
"YAML loadable instance."
|
217
217
|
|
218
218
|
yaml_obj = YAML::load(file)
|
219
219
|
|
@@ -237,8 +237,10 @@ module Stormpath
|
|
237
237
|
end
|
238
238
|
|
239
239
|
def set_base_url base_url
|
240
|
+
|
240
241
|
@base_url = base_url
|
241
242
|
self
|
243
|
+
|
242
244
|
end
|
243
245
|
|
244
246
|
private
|
@@ -277,13 +279,10 @@ module Stormpath
|
|
277
279
|
prop_name_value,
|
278
280
|
separator)
|
279
281
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
"configure the " + masterName + "PropertyName value on the ClientBuilder to specify a " +
|
285
|
-
"custom property name."
|
286
|
-
end
|
282
|
+
assert_not_nil value, "There is no '" + prop_name.join(':') + "' property in the " +
|
283
|
+
"configured apiKey YAML. You can either specify that property or " +
|
284
|
+
"configure the #{masterName}_property_name value on the ClientBuilder to specify a " +
|
285
|
+
"custom property name."
|
287
286
|
|
288
287
|
value
|
289
288
|
|
@@ -36,7 +36,7 @@ module Stormpath
|
|
36
36
|
@resource_factory = ResourceFactory.new(self)
|
37
37
|
end
|
38
38
|
|
39
|
-
def instantiate(clazz, properties)
|
39
|
+
def instantiate(clazz, properties = {})
|
40
40
|
|
41
41
|
@resource_factory.instantiate(clazz, properties)
|
42
42
|
end
|
@@ -60,7 +60,7 @@ module Stormpath
|
|
60
60
|
|
61
61
|
if resource.kind_of? return_type
|
62
62
|
|
63
|
-
resource.set_properties returned_resource
|
63
|
+
resource.set_properties to_hash(returned_resource)
|
64
64
|
|
65
65
|
end
|
66
66
|
|
@@ -84,7 +84,7 @@ module Stormpath
|
|
84
84
|
return_value = save_resource href, resource, clazz
|
85
85
|
|
86
86
|
#ensure the caller's argument is updated with what is returned from the server:
|
87
|
-
resource.set_properties return_value
|
87
|
+
resource.set_properties to_hash(return_value)
|
88
88
|
|
89
89
|
return_value
|
90
90
|
|
@@ -156,7 +156,7 @@ module Stormpath
|
|
156
156
|
q_href = qualify q_href
|
157
157
|
end
|
158
158
|
|
159
|
-
response = execute_request('post', q_href, MultiJson.dump(resource
|
159
|
+
response = execute_request('post', q_href, MultiJson.dump(to_hash(resource)))
|
160
160
|
@resource_factory.instantiate(return_type, response.to_hash)
|
161
161
|
|
162
162
|
end
|
@@ -167,6 +167,41 @@ module Stormpath
|
|
167
167
|
"https://" + DEFAULT_SERVER_HOST + "/v" + DEFAULT_API_VERSION.to_s
|
168
168
|
end
|
169
169
|
|
170
|
+
def to_hash resource
|
171
|
+
|
172
|
+
property_names = resource.get_property_names
|
173
|
+
properties = Hash.new
|
174
|
+
|
175
|
+
property_names.each do |name|
|
176
|
+
|
177
|
+
property = resource.get_property name
|
178
|
+
|
179
|
+
if property.kind_of? Hash
|
180
|
+
|
181
|
+
property = to_simple_reference name, property
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
properties.store name, property
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
properties
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
def to_simple_reference property_name, hash
|
194
|
+
|
195
|
+
href_prop_name = Resource::Resource::HREF_PROP_NAME
|
196
|
+
assert_true (hash.kind_of? Hash and !hash.empty? and hash.has_key? href_prop_name), "Nested resource " +
|
197
|
+
"'#{property_name}' must have an 'href' property."
|
198
|
+
|
199
|
+
href = hash[href_prop_name]
|
200
|
+
|
201
|
+
{href_prop_name => href}
|
202
|
+
|
203
|
+
end
|
204
|
+
|
170
205
|
end
|
171
206
|
|
172
207
|
end
|
@@ -23,12 +23,13 @@ module Stormpath
|
|
23
23
|
|
24
24
|
HREF_PROP_NAME = "href"
|
25
25
|
|
26
|
-
def initialize data_store, properties
|
26
|
+
def initialize data_store, properties = {}
|
27
27
|
|
28
28
|
@data_store = data_store
|
29
29
|
@read_lock = Mutex.new
|
30
30
|
@write_lock = Mutex.new
|
31
31
|
@properties = Hash.new
|
32
|
+
@dirty_properties = Hash.new
|
32
33
|
set_properties properties
|
33
34
|
|
34
35
|
end
|
@@ -39,10 +40,15 @@ module Stormpath
|
|
39
40
|
|
40
41
|
begin
|
41
42
|
|
43
|
+
@properties.clear
|
44
|
+
@dirty_properties.clear
|
42
45
|
@dirty = false
|
43
46
|
|
44
47
|
if !properties.nil? and properties.is_a? Hash
|
45
48
|
@properties.replace properties
|
49
|
+
|
50
|
+
# Don't consider this resource materialized if it is only a reference. A reference is any object that
|
51
|
+
# has only one 'href' property.
|
46
52
|
href_only = @properties.size == 1 and @properties.has_key? HREF_PROP_NAME
|
47
53
|
@materialized = !href_only
|
48
54
|
|
@@ -61,8 +67,28 @@ module Stormpath
|
|
61
67
|
#not the href/id, must be a property that requires materialization:
|
62
68
|
if !is_new and !materialized
|
63
69
|
|
64
|
-
materialize
|
70
|
+
# only materialize if the property hasn't been set previously (no need to execute a server
|
71
|
+
# request since we have the most recent value already):
|
72
|
+
present = false
|
73
|
+
@read_lock.lock
|
74
|
+
|
75
|
+
begin
|
76
|
+
|
77
|
+
present = @dirty_properties.has_key? name
|
78
|
+
|
79
|
+
ensure
|
80
|
+
|
81
|
+
@read_lock.unlock
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
if !present
|
86
|
+
# exhausted present properties - we require a server call:
|
87
|
+
materialize
|
88
|
+
end
|
89
|
+
|
65
90
|
end
|
91
|
+
|
66
92
|
end
|
67
93
|
|
68
94
|
read_property name
|
@@ -83,7 +109,105 @@ module Stormpath
|
|
83
109
|
get_property HREF_PROP_NAME
|
84
110
|
end
|
85
111
|
|
86
|
-
|
112
|
+
def inspect
|
113
|
+
|
114
|
+
@read_lock.lock
|
115
|
+
|
116
|
+
str = ''
|
117
|
+
|
118
|
+
begin
|
119
|
+
|
120
|
+
counter = 2
|
121
|
+
@properties.each do |key, value|
|
122
|
+
|
123
|
+
if str.empty?
|
124
|
+
|
125
|
+
str = '#<' + class_name_with_id + ' @properties={'
|
126
|
+
|
127
|
+
else
|
128
|
+
|
129
|
+
if printable_property? key
|
130
|
+
|
131
|
+
str << "\"#{key}\"=>"
|
132
|
+
|
133
|
+
if value.kind_of? Hash and value.has_key? HREF_PROP_NAME
|
134
|
+
|
135
|
+
str << '{"' << HREF_PROP_NAME + '"=>"' + value[HREF_PROP_NAME] + '"}'
|
136
|
+
|
137
|
+
else
|
138
|
+
|
139
|
+
str << "\"#{value}\""
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
if counter < @properties.length
|
144
|
+
|
145
|
+
str << ', '
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
counter+= 1
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
ensure
|
158
|
+
|
159
|
+
@read_lock.unlock
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
if !str.empty?
|
164
|
+
str << '}>'
|
165
|
+
end
|
166
|
+
|
167
|
+
str
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
def to_s
|
172
|
+
'#<' + class_name_with_id + '>'
|
173
|
+
end
|
174
|
+
|
175
|
+
def to_yaml
|
176
|
+
|
177
|
+
yaml = '--- !ruby/object:' << self.class.name << "\n"
|
178
|
+
|
179
|
+
@read_lock.lock
|
180
|
+
|
181
|
+
begin
|
182
|
+
|
183
|
+
first_property = true
|
184
|
+
@properties.each do |key, value|
|
185
|
+
|
186
|
+
if printable_property? key
|
187
|
+
|
188
|
+
if first_property
|
189
|
+
|
190
|
+
yaml << " properties\n "
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
yaml << ' ' << key << ': ' << value << "\n"
|
195
|
+
|
196
|
+
first_property = false
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
ensure
|
203
|
+
|
204
|
+
@read_lock.unlock
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
yaml << "\n"
|
209
|
+
|
210
|
+
end
|
87
211
|
|
88
212
|
protected
|
89
213
|
|
@@ -126,18 +250,9 @@ module Stormpath
|
|
126
250
|
@write_lock.lock
|
127
251
|
|
128
252
|
begin
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
if !removed.nil?
|
134
|
-
@dirty = true
|
135
|
-
end
|
136
|
-
|
137
|
-
else
|
138
|
-
@properties.store name, value
|
139
|
-
@dirty = true
|
140
|
-
end
|
253
|
+
@properties.store name, value
|
254
|
+
@dirty_properties.store name, value
|
255
|
+
@dirty = true
|
141
256
|
ensure
|
142
257
|
@write_lock.unlock
|
143
258
|
end
|
@@ -153,12 +268,32 @@ module Stormpath
|
|
153
268
|
|
154
269
|
resource = @data_store.get_resource get_href, clazz
|
155
270
|
@properties.replace resource.properties
|
271
|
+
|
272
|
+
#retain dirty properties:
|
273
|
+
@properties.merge! @dirty_properties
|
274
|
+
|
156
275
|
@materialized = true
|
157
276
|
|
158
277
|
ensure
|
159
278
|
|
160
279
|
@write_lock.unlock
|
161
280
|
end
|
281
|
+
|
282
|
+
end
|
283
|
+
|
284
|
+
def properties
|
285
|
+
@properties
|
286
|
+
end
|
287
|
+
|
288
|
+
##
|
289
|
+
# Returns {@code true} if the internal property is safe to print in to_s or inspect, {@code false} otherwise.
|
290
|
+
#
|
291
|
+
# @param property_name The name of the property to check for safe printing
|
292
|
+
# @return {@code true} if the internal property is safe to print in to_s, {@code false} otherwise.
|
293
|
+
def printable_property? property_name
|
294
|
+
|
295
|
+
return true
|
296
|
+
|
162
297
|
end
|
163
298
|
|
164
299
|
private
|
@@ -182,6 +317,10 @@ module Stormpath
|
|
182
317
|
end
|
183
318
|
|
184
319
|
end
|
320
|
+
|
321
|
+
def class_name_with_id
|
322
|
+
self.class.name + ':0x' + ('%x' % (self.object_id << 1)).to_s
|
323
|
+
end
|
185
324
|
end
|
186
325
|
end
|
187
326
|
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require "stormpath-sdk"
|
2
|
+
|
3
|
+
include Stormpath::Client
|
4
|
+
|
5
|
+
describe "Client Application Builder Tests" do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
@client_file = 'test/client/client.yml'
|
9
|
+
@client_remote_file = 'http://localhost:8081/client.yml'
|
10
|
+
@application_href = 'http://localhost:8080/v1/applications/A0atUpZARYGApaN5f88O3A'
|
11
|
+
@http_prefix = 'http://'
|
12
|
+
@app_href_without_http = '@localhost:8080/v1/applications/A0atUpZARYGApaN5f88O3A'
|
13
|
+
@client_builder = ClientBuilder.new.set_base_url 'http://localhost:8080/v1'
|
14
|
+
@test_remote_file = false
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
it 'Builder should read default properties from YAML file location with application href' do
|
19
|
+
|
20
|
+
result = ClientApplicationBuilder.new(@client_builder).
|
21
|
+
set_api_key_file_location(@client_file).
|
22
|
+
set_application_href(@application_href).
|
23
|
+
build
|
24
|
+
|
25
|
+
result.should be_kind_of ClientApplication
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'Builder should create ClientApplication with data from application href with credentials' do
|
30
|
+
|
31
|
+
# getting the properties from file...just to avoid writing them directly
|
32
|
+
# in the 'properties' Hash
|
33
|
+
yml_obj = YAML::load(File.open @client_file)
|
34
|
+
api_key_id_keyword = 'apiKey.id'
|
35
|
+
api_key_secret_keyword = 'apiKey.secret'
|
36
|
+
|
37
|
+
# we create the client from this Hash instead of from a file
|
38
|
+
properties = {api_key_id_keyword => yml_obj[api_key_id_keyword],
|
39
|
+
api_key_secret_keyword => yml_obj[api_key_secret_keyword]}
|
40
|
+
|
41
|
+
application_href = @http_prefix +
|
42
|
+
properties[api_key_id_keyword] +
|
43
|
+
':' +
|
44
|
+
properties[api_key_secret_keyword] +
|
45
|
+
@app_href_without_http
|
46
|
+
|
47
|
+
result = ClientApplicationBuilder.new(@client_builder).
|
48
|
+
set_application_href(application_href).
|
49
|
+
build
|
50
|
+
|
51
|
+
result.should be_kind_of ClientApplication
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'Builder should read custom complex properties from YAML file locatio with application href' do
|
56
|
+
|
57
|
+
@client_builder = ClientBuilder.new.set_base_url 'http://localhost:8080/v1'
|
58
|
+
result = ClientApplicationBuilder.new(@client_builder).
|
59
|
+
set_api_key_file_location(@client_file).
|
60
|
+
set_api_key_id_property_name('stormpath', 'apiKey', 'id').
|
61
|
+
set_api_key_secret_property_name('stormpath', 'apiKey', 'secret').
|
62
|
+
set_application_href(@application_href).
|
63
|
+
build
|
64
|
+
|
65
|
+
result.should be_kind_of ClientApplication
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'Builder should read custom simple properties from YAML file locatio with application href' do
|
70
|
+
|
71
|
+
# getting the properties from file...just to avoid writing them directly
|
72
|
+
# in the 'properties' Hash
|
73
|
+
yml_obj = YAML::load(File.open @client_file)
|
74
|
+
api_key_id_keyword = 'different.apiKey.id'
|
75
|
+
api_key_secret_keyword = 'different.apiKey.secret'
|
76
|
+
|
77
|
+
# we create the client from this Hash instead of from a file
|
78
|
+
properties = {api_key_id_keyword => yml_obj[api_key_id_keyword],
|
79
|
+
api_key_secret_keyword => yml_obj[api_key_secret_keyword]}
|
80
|
+
|
81
|
+
result = ClientApplicationBuilder.new(@client_builder).
|
82
|
+
set_api_key_properties(properties.to_yaml).
|
83
|
+
set_api_key_id_property_name(api_key_id_keyword).
|
84
|
+
set_api_key_secret_property_name(api_key_secret_keyword).
|
85
|
+
set_application_href(@application_href).
|
86
|
+
build
|
87
|
+
|
88
|
+
result.should be_kind_of ClientApplication
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'Builder should throw exception when creating it with wrong argument' do
|
93
|
+
|
94
|
+
expect { ClientApplicationBuilder.new 'WRONG' }.to raise_error ArgumentError
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'Builder should throw exception when trying to build without application href' do
|
99
|
+
|
100
|
+
expect { ClientApplicationBuilder.new(@client_builder).build }.to raise_error ArgumentError
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'Builder should throw exception when trying to build with an invalid application href' do
|
105
|
+
|
106
|
+
expect { ClientApplicationBuilder.new(@client_builder).
|
107
|
+
set_api_key_file_location(@client_file).
|
108
|
+
set_application_href('id:secret@stormpath.com/v1').
|
109
|
+
build }.
|
110
|
+
to raise_error ArgumentError
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
File without changes
|
data/test/client/read_spec.rb
CHANGED
@@ -237,6 +237,19 @@ describe "READ Operations" do
|
|
237
237
|
|
238
238
|
end
|
239
239
|
|
240
|
+
it "dirty properties must be retained after materialization" do
|
241
|
+
|
242
|
+
account = @data_store.instantiate Account, {'href' => 'accounts/gJH4bh6QQKK0awRmwD72Cg'}
|
243
|
+
|
244
|
+
name = 'Name Before Materialization'
|
245
|
+
|
246
|
+
account.set_given_name name
|
247
|
+
|
248
|
+
account.get_surname.should be_kind_of String
|
249
|
+
|
250
|
+
account.get_given_name.should == name
|
251
|
+
end
|
252
|
+
|
240
253
|
end
|
241
254
|
|
242
255
|
|
data/test/client/write_spec.rb
CHANGED
@@ -10,10 +10,12 @@ describe "WRITE Operations" do
|
|
10
10
|
@data_store = @client.data_store
|
11
11
|
@create_account = false
|
12
12
|
@update_account = false
|
13
|
+
@remove_account_property = false
|
13
14
|
@update_application = false
|
14
15
|
@update_directory = false
|
15
16
|
@update_group = false
|
16
17
|
@create_application = false
|
18
|
+
@change_password = false
|
17
19
|
@verify_email = false
|
18
20
|
@send_password_reset_email = false
|
19
21
|
@verify_password_reset_token = false
|
@@ -25,10 +27,10 @@ describe "WRITE Operations" do
|
|
25
27
|
|
26
28
|
it "application should be able to authenticate" do
|
27
29
|
|
28
|
-
href = 'applications/
|
30
|
+
href = 'applications/A0atUpZARYGApaN5f88O3A'
|
29
31
|
application = @data_store.get_resource href, Application
|
30
32
|
|
31
|
-
result = application.authenticate_account UsernamePasswordRequest.new '
|
33
|
+
result = application.authenticate_account UsernamePasswordRequest.new 'kentucky', 'super_P4ss'
|
32
34
|
|
33
35
|
result.should be_kind_of AuthenticationResult
|
34
36
|
|
@@ -39,9 +41,9 @@ describe "WRITE Operations" do
|
|
39
41
|
|
40
42
|
begin
|
41
43
|
|
42
|
-
href = 'applications/
|
44
|
+
href = 'applications/A0atUpZARYGApaN5f88O3A'
|
43
45
|
application = @data_store.get_resource href, Application
|
44
|
-
result = application.authenticate_account UsernamePasswordRequest.new '
|
46
|
+
result = application.authenticate_account UsernamePasswordRequest.new 'kentucky', 'WRONG_PASS'
|
45
47
|
|
46
48
|
rescue ResourceError => re
|
47
49
|
p '** Authentication Error **'
|
@@ -59,17 +61,17 @@ describe "WRITE Operations" do
|
|
59
61
|
|
60
62
|
if (@create_account)
|
61
63
|
|
62
|
-
href = 'directories/
|
64
|
+
href = 'directories/_oIg8zU5QWyiz22DcVYVLg'
|
63
65
|
directory = @data_store.get_resource href, Directory
|
64
66
|
|
65
|
-
account = @data_store.instantiate Account
|
67
|
+
account = @data_store.instantiate Account
|
66
68
|
account.set_email 'rubysdk@email.com'
|
67
69
|
account.set_given_name 'Ruby'
|
68
70
|
account.set_password 'super_P4ss'
|
69
71
|
account.set_surname 'Sdk'
|
70
72
|
account.set_username 'rubysdk'
|
71
73
|
|
72
|
-
result = directory.create_account account
|
74
|
+
result = directory.create_account account, false
|
73
75
|
|
74
76
|
result.should be_kind_of Account
|
75
77
|
|
@@ -96,6 +98,30 @@ describe "WRITE Operations" do
|
|
96
98
|
|
97
99
|
end
|
98
100
|
|
101
|
+
it "account property should be updated/removed" do
|
102
|
+
|
103
|
+
if (@remove_account_property)
|
104
|
+
|
105
|
+
href = 'accounts/gJH4bh6QQKK0awRmwD72Cg'
|
106
|
+
account = @data_store.get_resource href, Account
|
107
|
+
|
108
|
+
mod_value = 'Modified at: ' + Time.now.to_s
|
109
|
+
account.set_middle_name mod_value
|
110
|
+
|
111
|
+
account.save
|
112
|
+
|
113
|
+
account.get_middle_name.should == mod_value
|
114
|
+
|
115
|
+
account.set_middle_name nil
|
116
|
+
|
117
|
+
account.save
|
118
|
+
|
119
|
+
account.get_middle_name.should == nil
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
99
125
|
it "application should be updated" do
|
100
126
|
|
101
127
|
if (@update_application)
|
@@ -156,7 +182,7 @@ describe "WRITE Operations" do
|
|
156
182
|
|
157
183
|
tenant = @client.current_tenant
|
158
184
|
|
159
|
-
application = @data_store.instantiate Application
|
185
|
+
application = @data_store.instantiate Application
|
160
186
|
application.set_name 'Test Application Creation'
|
161
187
|
application.set_description 'Test Application Description'
|
162
188
|
|
@@ -214,6 +240,35 @@ describe "WRITE Operations" do
|
|
214
240
|
|
215
241
|
end
|
216
242
|
|
243
|
+
it "password should be changed" do
|
244
|
+
|
245
|
+
if (@change_password)
|
246
|
+
|
247
|
+
href = 'applications/fzyWJ5V_SDORGPk4fT2jhA'
|
248
|
+
application = @data_store.get_resource href, Application
|
249
|
+
|
250
|
+
account = application.verify_password_reset_token 'TFMWt3lbQdWc7MNF48pJbw'
|
251
|
+
|
252
|
+
account.should be_kind_of Account
|
253
|
+
|
254
|
+
new_password = 'changed_P4ss'
|
255
|
+
account.set_password new_password
|
256
|
+
account.save
|
257
|
+
|
258
|
+
begin
|
259
|
+
|
260
|
+
application.authenticate_account UsernamePasswordRequest.new account.get_username, new_password
|
261
|
+
|
262
|
+
rescue ResourceError => re
|
263
|
+
|
264
|
+
false.should be true
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|
269
|
+
|
270
|
+
end
|
271
|
+
|
217
272
|
it "account should be created linked to a group" do
|
218
273
|
|
219
274
|
if (@create_account_with_group_membership)
|
@@ -224,7 +279,7 @@ describe "WRITE Operations" do
|
|
224
279
|
group_href = 'groups/mCidbrAcSF-VpkNfOVvJkQ'
|
225
280
|
group = @data_store.get_resource group_href, Group
|
226
281
|
|
227
|
-
account = @data_store.instantiate Account
|
282
|
+
account = @data_store.instantiate Account
|
228
283
|
account.set_email 'rubysdkwithgroup@email.com'
|
229
284
|
account.set_given_name 'Ruby'
|
230
285
|
account.set_password 'super_P4ss'
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "test/resource/test_resource"
|
2
|
+
|
3
|
+
describe "Resource Tests" do
|
4
|
+
|
5
|
+
it "non materialized resource get dirty property without materializing" do
|
6
|
+
|
7
|
+
props = {'href' => 'http://foo.com/test/123'}
|
8
|
+
data_store = Stormpath::DataStore::DataStore.new '', ''
|
9
|
+
|
10
|
+
test_resource = TestResource.new data_store, props
|
11
|
+
name = 'New Name'
|
12
|
+
test_resource.set_name name
|
13
|
+
|
14
|
+
begin
|
15
|
+
|
16
|
+
name.should == test_resource.get_name
|
17
|
+
|
18
|
+
rescue Exception => e
|
19
|
+
|
20
|
+
true.should be false
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
it "password property must not show up on inspect" do
|
27
|
+
|
28
|
+
props = {'href' => 'http://foo.com/test/123'}
|
29
|
+
data_store = Stormpath::DataStore::DataStore.new '', ''
|
30
|
+
|
31
|
+
test_resource = TestResource.new data_store, props
|
32
|
+
name = 'New Name'
|
33
|
+
test_resource.set_name name
|
34
|
+
|
35
|
+
test_resource.set_password 'my_password'
|
36
|
+
|
37
|
+
test_resource.inspect.should_not include 'password'
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class TestResource < Stormpath::Resource::Resource
|
2
|
+
|
3
|
+
def get_name
|
4
|
+
get_property 'name'
|
5
|
+
end
|
6
|
+
|
7
|
+
def set_name name
|
8
|
+
set_property 'name', name
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_description
|
12
|
+
get_property 'description'
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_description description
|
16
|
+
set_property 'description', description
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_password password
|
20
|
+
set_property 'password', password
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
def printable_property? property_name
|
25
|
+
'password' != property_name
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 3
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.3.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Elder Crisostomo
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2012-08-
|
17
|
+
date: 2012-08-31 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -138,6 +138,8 @@ extensions: []
|
|
138
138
|
extra_rdoc_files: []
|
139
139
|
|
140
140
|
files:
|
141
|
+
- .gitignore
|
142
|
+
- CHANGES.md
|
141
143
|
- Gemfile
|
142
144
|
- README.md
|
143
145
|
- Rakefile
|
@@ -148,6 +150,8 @@ files:
|
|
148
150
|
- lib/stormpath-sdk/auth/username_password_request.rb
|
149
151
|
- lib/stormpath-sdk/client/api_key.rb
|
150
152
|
- lib/stormpath-sdk/client/client.rb
|
153
|
+
- lib/stormpath-sdk/client/client_application.rb
|
154
|
+
- lib/stormpath-sdk/client/client_application_builder.rb
|
151
155
|
- lib/stormpath-sdk/client/client_builder.rb
|
152
156
|
- lib/stormpath-sdk/ds/data_store.rb
|
153
157
|
- lib/stormpath-sdk/ds/resource_factory.rb
|
@@ -181,9 +185,12 @@ files:
|
|
181
185
|
- lib/stormpath-sdk/version.rb
|
182
186
|
- stormpath-sdk.gemspec
|
183
187
|
- test/client/client.yml
|
184
|
-
- test/client/
|
188
|
+
- test/client/client_application_builder_spec.rb
|
189
|
+
- test/client/client_builder_spec.rb
|
185
190
|
- test/client/read_spec.rb
|
186
191
|
- test/client/write_spec.rb
|
192
|
+
- test/resource/resource_spec.rb
|
193
|
+
- test/resource/test_resource.rb
|
187
194
|
has_rdoc: true
|
188
195
|
homepage: https://github.com/stormpath/stormpath-sdk-ruby
|
189
196
|
licenses: []
|
@@ -219,6 +226,9 @@ signing_key:
|
|
219
226
|
specification_version: 3
|
220
227
|
summary: Stormpath SDK
|
221
228
|
test_files:
|
222
|
-
- test/client/
|
229
|
+
- test/client/client_application_builder_spec.rb
|
230
|
+
- test/client/client_builder_spec.rb
|
223
231
|
- test/client/read_spec.rb
|
224
232
|
- test/client/write_spec.rb
|
233
|
+
- test/resource/resource_spec.rb
|
234
|
+
- test/resource/test_resource.rb
|