stormpath-sdk 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|