stormpath-sdk 0.4.0 → 1.0.0.beta

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.
Files changed (89) hide show
  1. data/.gitignore +6 -0
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +27 -0
  5. data/CHANGES.md +21 -1
  6. data/Gemfile +1 -2
  7. data/README.md +457 -11
  8. data/Rakefile +15 -1
  9. data/lib/stormpath-sdk.rb +52 -33
  10. data/lib/stormpath-sdk/{resource/group_list.rb → api_key.rb} +5 -9
  11. data/lib/stormpath-sdk/auth/authentication_result.rb +3 -13
  12. data/lib/stormpath-sdk/auth/basic_authenticator.rb +5 -11
  13. data/lib/stormpath-sdk/auth/basic_login_attempt.rb +6 -8
  14. data/lib/stormpath-sdk/auth/username_password_request.rb +2 -5
  15. data/lib/stormpath-sdk/cache/cache.rb +54 -0
  16. data/lib/stormpath-sdk/cache/cache_entry.rb +33 -0
  17. data/lib/stormpath-sdk/cache/cache_manager.rb +22 -0
  18. data/lib/stormpath-sdk/cache/cache_stats.rb +35 -0
  19. data/lib/stormpath-sdk/cache/memory_store.rb +29 -0
  20. data/lib/stormpath-sdk/cache/redis_store.rb +32 -0
  21. data/lib/stormpath-sdk/client.rb +111 -0
  22. data/lib/stormpath-sdk/data_store.rb +241 -0
  23. data/lib/stormpath-sdk/{client/api_key.rb → error.rb} +16 -10
  24. data/lib/stormpath-sdk/{util → ext}/hash.rb +1 -2
  25. data/lib/stormpath-sdk/http/authc/sauthc1_signer.rb +8 -4
  26. data/lib/stormpath-sdk/http/http_client_request_executor.rb +8 -7
  27. data/lib/stormpath-sdk/http/request.rb +4 -8
  28. data/lib/stormpath-sdk/{util/request_utils.rb → http/utils.rb} +17 -38
  29. data/lib/stormpath-sdk/resource/account.rb +12 -108
  30. data/lib/stormpath-sdk/resource/application.rb +35 -171
  31. data/lib/stormpath-sdk/resource/associations.rb +97 -0
  32. data/lib/stormpath-sdk/resource/base.rb +256 -0
  33. data/lib/stormpath-sdk/resource/collection.rb +94 -0
  34. data/lib/stormpath-sdk/resource/directory.rb +11 -68
  35. data/lib/stormpath-sdk/resource/email_verification_token.rb +3 -9
  36. data/lib/stormpath-sdk/resource/error.rb +4 -38
  37. data/lib/stormpath-sdk/resource/expansion.rb +28 -0
  38. data/lib/stormpath-sdk/resource/group.rb +8 -66
  39. data/lib/stormpath-sdk/resource/group_membership.rb +4 -55
  40. data/lib/stormpath-sdk/resource/{application_list.rb → instance.rb} +7 -13
  41. data/lib/stormpath-sdk/resource/password_reset_token.rb +5 -23
  42. data/lib/stormpath-sdk/resource/status.rb +22 -28
  43. data/lib/stormpath-sdk/resource/tenant.rb +5 -52
  44. data/lib/stormpath-sdk/resource/utils.rb +43 -13
  45. data/lib/stormpath-sdk/util/assert.rb +5 -15
  46. data/lib/stormpath-sdk/version.rb +3 -3
  47. data/spec/api_key_spec.rb +19 -0
  48. data/spec/auth/basic_authenticator_spec.rb +25 -0
  49. data/spec/auth/sauthc1_signer_spec.rb +42 -0
  50. data/spec/cache/cache_entry_spec.rb +157 -0
  51. data/spec/cache/cache_spec.rb +89 -0
  52. data/spec/cache/cache_stats_spec.rb +106 -0
  53. data/spec/client_spec.rb +538 -0
  54. data/spec/data_store_spec.rb +130 -0
  55. data/spec/resource/account_spec.rb +74 -0
  56. data/spec/resource/application_spec.rb +148 -0
  57. data/spec/resource/base_spec.rb +114 -0
  58. data/spec/resource/collection_spec.rb +169 -0
  59. data/spec/resource/directory_spec.rb +30 -0
  60. data/spec/resource/expansion_spec.rb +100 -0
  61. data/spec/resource/group_spec.rb +49 -0
  62. data/spec/spec_helper.rb +135 -0
  63. data/spec/support/resource_factory.rb +48 -0
  64. data/spec/support/resource_matchers.rb +27 -0
  65. data/spec/support/test_cache_stores.rb +9 -0
  66. data/spec/support/test_request_executor.rb +11 -0
  67. data/stormpath-sdk.gemspec +14 -4
  68. data/support/api.rb +55 -0
  69. metadata +214 -44
  70. data/lib/stormpath-sdk/client/client.rb +0 -38
  71. data/lib/stormpath-sdk/client/client_application.rb +0 -38
  72. data/lib/stormpath-sdk/client/client_application_builder.rb +0 -351
  73. data/lib/stormpath-sdk/client/client_builder.rb +0 -305
  74. data/lib/stormpath-sdk/ds/data_store.rb +0 -210
  75. data/lib/stormpath-sdk/ds/resource_factory.rb +0 -37
  76. data/lib/stormpath-sdk/resource/account_list.rb +0 -32
  77. data/lib/stormpath-sdk/resource/collection_resource.rb +0 -91
  78. data/lib/stormpath-sdk/resource/directory_list.rb +0 -30
  79. data/lib/stormpath-sdk/resource/group_membership_list.rb +0 -32
  80. data/lib/stormpath-sdk/resource/instance_resource.rb +0 -28
  81. data/lib/stormpath-sdk/resource/resource.rb +0 -327
  82. data/lib/stormpath-sdk/resource/resource_error.rb +0 -47
  83. data/test/client/client.yml +0 -16
  84. data/test/client/client_application_builder_spec.rb +0 -114
  85. data/test/client/client_builder_spec.rb +0 -176
  86. data/test/client/read_spec.rb +0 -254
  87. data/test/client/write_spec.rb +0 -420
  88. data/test/resource/resource_spec.rb +0 -41
  89. data/test/resource/test_resource.rb +0 -28
@@ -1,38 +0,0 @@
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
- class Client
21
-
22
- attr_reader :data_store
23
-
24
- def initialize(api_key, *base_url)
25
- request_executor = Stormpath::Http::HttpClientRequestExecutor.new(api_key)
26
- @data_store = Stormpath::DataStore::DataStore.new(request_executor, *base_url)
27
- end
28
-
29
-
30
- def current_tenant
31
- @data_store.get_resource("/tenants/current", Stormpath::Resource::Tenant)
32
- end
33
- end
34
- end
35
-
36
-
37
- end
38
-
@@ -1,38 +0,0 @@
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
@@ -1,351 +0,0 @@
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, Stormpath::Resource::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
@@ -1,305 +0,0 @@
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 <a href="http://en.wikipedia.org/wiki/Builder_pattern">Builder design pattern</a> implementation used to
21
- # construct {@link Client} instances.
22
- # <p/>
23
- # The {@code ClientBuilder} is especially useful for constructing Client instances with Stormpath API Key
24
- # information loaded from an external {@code .yml} file (or YAML instance) to ensure the API Key secret
25
- # (password) does not reside in plaintext in code.
26
- # <p/>
27
- # Example usage:
28
- # <pre>
29
- # location = "/home/jsmith/.stormpath/apiKey.yml";
30
- #
31
- # client = ClientBuilder.new.set_api_key_file_location(location).build
32
- # </pre>
33
- # <p/>
34
- # You may load files from the filesystem or URLs by specifying the file location.
35
- # See {@link #set_api_key_file_location(location)} for more information.
36
- #
37
- # @see #set_api_key_file_location(location)
38
- class ClientBuilder
39
-
40
- include Stormpath::Client
41
- include Stormpath::Util::Assert
42
-
43
- def initialize
44
- @api_key_id_property_name = "apiKey.id"
45
- @api_key_secret_property_name = "apiKey.secret"
46
- end
47
-
48
- # Allows usage of a YAML loadable object (IO object or the result of invoking Object.to_yaml)
49
- # instead of loading a YAML file via {@link #set_api_key_file_location apiKeyFileLocation} configuration.
50
- # <p/>
51
- # The YAML contents and property name overrides function the same as described in the
52
- # {@link #set_api_key_file_location setApiKeyFileLocation} RDoc.
53
- #
54
- # @param properties the YAML object to use to load the API Key ID and Secret.
55
- # @return the ClientBuilder instance for method chaining.
56
- def set_api_key_properties properties
57
-
58
- @api_key_properties = properties
59
- self
60
-
61
- end
62
-
63
- # Creates an API Key YAML object based on the specified File instead of loading a YAML
64
- # file via {@link #set_api_key_file_location apiKeyFileLocation} configuration. This file argument
65
- # needs to be an IO instance.
66
- # <p/>
67
- # The constructed YAML contents and property name overrides function the same as described in the
68
- # {@link #set_api_key_file_location setApiKeyFileLocation} RDoc.
69
- # @param file the file to use to construct a YAML object.
70
- # @return the ClientBuilder instance for method chaining.
71
- def set_api_key_file file
72
- assert_kind_of IO, file, 'file must be kind of IO'
73
- @api_key_file = file
74
- self
75
- end
76
-
77
-
78
- # Sets the location of the YAML file to load containing the API Key (Id and secret) used by the
79
- # Client to communicate with the Stormpath REST API.
80
- # <p/>
81
- # You may load files from the filesystem, or URLs just specifying the file location.
82
- # <h3>File Contents</h3>
83
- # <p/>
84
- # When the file is loaded, the following name/value pairs are expected to be present by default:
85
- # <table>
86
- # <tr>
87
- # <th>Key</th>
88
- # <th>Value</th>
89
- # </tr>
90
- # <tr>
91
- # <td>apiKey.id</td>
92
- # <td>An individual account's API Key ID</td>
93
- # </tr>
94
- # <tr>
95
- # <td>apiKey.secret</td>
96
- # <td>The API Key Secret (password) that verifies the paired API Key ID.</td>
97
- # </tr>
98
- # </table>
99
- # <p/>
100
- # Assuming you were using these default property names, your {@code ClientBuilder} usage might look like the
101
- # following:
102
- # <pre>
103
- # location = "/home/jsmith/.stormpath/apiKey.yml";
104
- #
105
- # client = ClientBuilder.new.set_api_key_file_location(location).build
106
- # </pre>
107
- # <h3>Custom Property Names</h3>
108
- # If you want to control the property names used in the file, you may configure them via
109
- # {@link #set_api_key_id_property_name(String) set_api_key_id_property_name} and
110
- # {@link #set_api_key_secret_property_name(String) set_api_key_secret_property_name}.
111
- # <p/>
112
- # For example, if you had a {@code /home/jsmith/.stormpath/apiKey.yml} file with the following
113
- # name/value pairs:
114
- # <pre>
115
- # myStormpathApiKeyId = 'foo'
116
- # myStormpathApiKeySecret = 'mySuperSecretValue'
117
- # </pre>
118
- # Your {@code ClientBuilder} usage would look like the following:
119
- # <pre>
120
- # location = "/home/jsmith/.stormpath/apiKey.yml";
121
- #
122
- # client =
123
- # ClientBuilder.new.
124
- # set_api_key_file_location(location).
125
- # set_api_key_id_property_name("myStormpathApiKeyId").
126
- # set_api_key_secret_property_name("myStormpathApiKeySecret").
127
- # build
128
- # </pre>
129
- #
130
- # @param location the file or url location of the API Key {@code .yml} file to load when
131
- # constructing the API Key to use for communicating with the Stormpath REST API.
132
- #
133
- # @return the ClientBuilder instance for method chaining.
134
- #/
135
- def set_api_key_file_location location
136
-
137
- assert_kind_of String, location, 'location must be kind of String'
138
- @api_key_file_location = location
139
- self
140
-
141
- end
142
-
143
-
144
- # Sets the name used to query for the API Key ID from a YAML instance. That is:
145
- # <pre>
146
- # apiKeyId = yml.access(<b>api_key_id_property_name</b>)
147
- # </pre>
148
- #
149
- # The Hash#access method searches through the provided path and returns the found value.
150
- #
151
- # The <b>api_key_id_property_name</b> key can be as deep as needed, as long as it comes
152
- # in the exact path order.
153
- # Example: Having the file 'apiKey.yml' with the following content:
154
- #
155
- # stormpath:
156
- # apiKey:
157
- # id: myStormpathApiKeyId
158
- #
159
- # The method should be called as follows:
160
- #
161
- # ClientBuilder#set_api_key_id_property_name('stormpath', 'apiKey', 'id')
162
- #
163
- # @param api_key_id_property_name the name used to query for the API Key ID from a YAML instance.
164
- # @return the ClientBuilder instance for method chaining.
165
- def set_api_key_id_property_name *api_key_id_property_name
166
-
167
- @api_key_id_property_name = *api_key_id_property_name
168
- self
169
-
170
- end
171
-
172
-
173
- # Sets the name used to query for the API Key Secret from a YAML instance. That is:
174
- # <pre>
175
- # apiKeyId = yml.access(<b>api_key_secret_property_name</b>)
176
- # </pre>
177
- #
178
- # The Hash#access method searches through the provided path and returns the found value.
179
- #
180
- # The <b>api_key_secret_property_name</b> key can be as deep as needed, as long as it comes
181
- # in the exact path order.
182
- # Example: Having the file 'apiKey.yml' with the following content:
183
- #
184
- # stormpath:
185
- # apiKey:
186
- # secret: myStormpathApiKeyId
187
- #
188
- # The method should be called as follows:
189
- #
190
- # ClientBuilder#set_api_key_id_property_name('stormpath', 'apiKey', 'secret')
191
- #
192
- # @param api_key_secret_property_name the name used to query for the API Key Secret from a YAML instance.
193
- # @return the ClientBuilder instance for method chaining.
194
- def set_api_key_secret_property_name *api_key_secret_property_name
195
-
196
- @api_key_secret_property_name = *api_key_secret_property_name
197
- self
198
-
199
- end
200
-
201
- # Constructs a new {@link Client} instance based on the ClientBuilder's current configuration state.
202
- #
203
- # @return a new {@link Client} instance based on the ClientBuilder's current configuration state.
204
- #
205
- def build
206
-
207
- if @api_key_properties.nil? or (@api_key_properties.respond_to? 'empty?' and @api_key_properties.empty?)
208
-
209
-
210
- #need to load the properties file
211
-
212
- file = get_available_file
213
-
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
-
218
- yaml_obj = YAML::load(file)
219
-
220
- else
221
-
222
- yaml_obj = YAML::load(@api_key_properties)
223
-
224
- end
225
-
226
- api_key_id = get_required_property_value yaml_obj, 'api_key_id', @api_key_id_property_name
227
-
228
- api_key_secret = get_required_property_value yaml_obj, 'api_key_secret', @api_key_secret_property_name
229
-
230
- assert_not_nil api_key_id, 'api_key_id must not be nil when acquiring it from the YAML object'
231
- assert_not_nil api_key_secret, 'api_key_secret must not be nil when acquiring it from the YAML object'
232
-
233
- api_key = ApiKey.new api_key_id, api_key_secret
234
-
235
- Client.new api_key, @base_url
236
-
237
- end
238
-
239
- def set_base_url base_url
240
-
241
- @base_url = base_url
242
- self
243
-
244
- end
245
-
246
- private
247
-
248
-
249
- def get_property_value yml, prop_name, separator
250
-
251
- value = yml.access(prop_name, separator)
252
-
253
- if !value.nil?
254
-
255
- if value.kind_of? String
256
-
257
- value = value.strip
258
-
259
- end
260
-
261
- if value.empty?
262
- value = nil
263
- end
264
-
265
- end
266
-
267
- value
268
-
269
- end
270
-
271
- def get_required_property_value yml, masterName, *prop_name
272
-
273
-
274
- prop_name_value = prop_name[0]
275
-
276
- separator = '--YAMLKeysSeparator--'
277
- value = get_property_value(yml, prop_name_value.respond_to?('join') ?
278
- prop_name[0].join(separator) :
279
- prop_name_value,
280
- separator)
281
-
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."
286
-
287
- value
288
-
289
- end
290
-
291
- def get_available_file
292
-
293
- if @api_key_file
294
- return @api_key_file
295
- end
296
-
297
- open(@api_key_file_location) { |f| f.read }
298
-
299
- end
300
-
301
- end
302
-
303
- end
304
-
305
- end