stormpath-sdk 1.0.0.beta.5 → 1.0.0.beta.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e9e44a0599b007cd69c76fd3ab6be4ed95685f5e
4
+ data.tar.gz: 6a627f9090aa67d81df6d94aa659a3c8697207cd
5
+ SHA512:
6
+ metadata.gz: 25e4af1d59e94e4c460f0a59d27a3bcad4d09516e8430a28e76ee7248d8077bfd1c2383a847a4eb266a8b9ace48073e74968296c9cf906ba0cfdfffdff55ea96
7
+ data.tar.gz: e538bee906bf915d706ccfb99d32a2dfd86c4bbf1c0dd51485690001964ebbc0dda8f4d9e5f94bc2e3959f5f0e11dfc27eedc4dd991d8fd6cf6a0ee43dc61462
data/.gitignore CHANGED
@@ -11,4 +11,6 @@ spec/fixtures/vcr_cassettes
11
11
  Guardfile
12
12
  tmp/*
13
13
  *.gem
14
- .bundle/
14
+ .bundle/
15
+ dump.rdb
16
+ .ruby-version
data/.travis.yml CHANGED
@@ -26,5 +26,8 @@ env:
26
26
  yvaGCsPr2h6rwtiMb8QHA4tMqHsoay0e9s7jyBtn6amgUaLsV2vdhQTWDuIU
27
27
  cksOE3PMIovYl9ANLb6KrhDWt7ue/fOxEALh0a5rAu50C/tNvgo=
28
28
 
29
+ language: ruby
30
+ rvm:
31
+ - 1.9.3
29
32
  services:
30
33
  - redis-server
data/CHANGES.md CHANGED
@@ -1,6 +1,16 @@
1
1
  stormpath-sdk-ruby Changelog
2
2
  ============================
3
3
 
4
+ Version 1.0.0.beta.6
5
+ --------------------
6
+
7
+ Released on July 7, 2014
8
+
9
+ - Fixed custom data deletion issue.
10
+ - Added resource pagination functionality.
11
+ - Fixed issue when searching by email.
12
+
13
+
4
14
  Version 1.0.0.beta.5
5
15
  --------------------
6
16
 
data/README.md CHANGED
@@ -495,8 +495,8 @@ The following environment variables need will then need to be set:
495
495
 
496
496
  ### Running
497
497
 
498
- Once properly configured, the tests can be run as the default
499
- <code>Rake<code> task:
498
+ Once properly configured, start the redis server with <code>redis-server</code> and the tests can be run as the default
499
+ <code>Rake</code> task:
500
500
 
501
501
  ```sh
502
502
  $ rake
data/lib/stormpath-sdk.rb CHANGED
@@ -6,6 +6,7 @@ require "open-uri"
6
6
  require "uri"
7
7
  require "uuidtools"
8
8
  require "yaml"
9
+ require 'active_support'
9
10
  require "active_support/core_ext"
10
11
  require 'active_support/core_ext/module/delegation'
11
12
  require 'active_support/core_ext/kernel/singleton_class'
@@ -55,18 +56,24 @@ module Stormpath
55
56
  autoload :CacheStats, 'stormpath-sdk/cache/cache_stats'
56
57
  autoload :MemoryStore, 'stormpath-sdk/cache/memory_store'
57
58
  autoload :RedisStore, 'stormpath-sdk/cache/redis_store'
59
+ autoload :DisabledCacheStore, 'stormpath-sdk/cache/disabled_cache_store'
58
60
  end
59
61
 
60
62
  module Authentication
63
+ autoload :UsernamePasswordRequest, "stormpath-sdk/auth/username_password_request"
64
+ autoload :BasicLoginAttempt, "stormpath-sdk/auth/basic_login_attempt"
65
+ autoload :AuthenticationResult, "stormpath-sdk/auth/authentication_result"
66
+ autoload :BasicAuthenticator, "stormpath-sdk/auth/basic_authenticator"
61
67
  end
62
- end
63
68
 
64
- require "stormpath-sdk/auth/username_password_request"
65
- require 'stormpath-sdk/http/utils'
66
- require "stormpath-sdk/http/request"
67
- require "stormpath-sdk/http/response"
68
- require "stormpath-sdk/http/authc/sauthc1_signer"
69
- require "stormpath-sdk/http/http_client_request_executor"
70
- require "stormpath-sdk/auth/basic_login_attempt"
71
- require "stormpath-sdk/auth/authentication_result"
72
- require "stormpath-sdk/auth/basic_authenticator"
69
+ module Http
70
+ autoload :Utils, "stormpath-sdk/http/utils"
71
+ autoload :Request, "stormpath-sdk/http/request"
72
+ autoload :Response, "stormpath-sdk/http/response"
73
+ autoload :HttpClientRequestExecutor, "stormpath-sdk/http/http_client_request_executor"
74
+
75
+ module Authc
76
+ autoload :Sauthc1Signer, "stormpath-sdk/http/authc/sauthc1_signer"
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,26 @@
1
+ module Stormpath
2
+ module Cache
3
+ class DisabledCacheStore
4
+ def initialize(opts = nil)
5
+ end
6
+
7
+ def get(key)
8
+ end
9
+
10
+ def put(key, entry)
11
+ entry
12
+ end
13
+
14
+ def delete(key)
15
+ end
16
+
17
+ def clear
18
+ {}
19
+ end
20
+
21
+ def size
22
+ 0
23
+ end
24
+ end
25
+ end
26
+ end
@@ -16,9 +16,9 @@
16
16
  require 'java_properties'
17
17
 
18
18
  module Stormpath
19
-
20
19
  class Client
21
20
  include Stormpath::Util::Assert
21
+ include Stormpath::Resource::Associations
22
22
 
23
23
  attr_reader :data_store, :application
24
24
 
@@ -38,9 +38,8 @@ module Stormpath
38
38
  options[:api_key_secret_property_name]
39
39
  end
40
40
 
41
- assert_not_nil api_key, "No API key has been provided. Please " +
42
- "pass an 'api_key' or 'api_key_file_location' to the " +
43
- "Stormpath::Client constructor."
41
+ assert_not_nil api_key, "No API key has been provided. Please pass an 'api_key' or " +
42
+ "'api_key_file_location' to the Stormpath::Client constructor."
44
43
 
45
44
  request_executor = Stormpath::Http::HttpClientRequestExecutor.new(api_key, proxy: options[:proxy])
46
45
  @data_store = Stormpath::DataStore.new(request_executor, cache_opts, self, base_url)
@@ -58,18 +57,13 @@ module Stormpath
58
57
  @data_source.cache_stats
59
58
  end
60
59
 
61
- include Stormpath::Resource::Associations
62
-
63
60
  has_many :tenants, href: '/tenants', can: :get
64
61
  has_many :applications, href: '/applications', can: [:get, :create], delegate: true
65
62
  has_many :directories, href: '/directories', can: [:get, :create], delegate: true
66
- has_many(:accounts, href: '/accounts', can: :get) do
63
+ has_many :accounts, href: '/accounts', can: :get do
67
64
  def verify_email_token(token)
68
65
  token_href = "#{href}/emailVerificationTokens/#{token}"
69
- token = Stormpath::Resource::EmailVerificationToken.new(
70
- token_href,
71
- client
72
- )
66
+ token = Stormpath::Resource::EmailVerificationToken.new token_href, client
73
67
  data_store.save token, Stormpath::Resource::Account
74
68
  end
75
69
  end
@@ -77,38 +71,32 @@ module Stormpath
77
71
  has_many :group_memberships, href: '/groupMemberships', can: [:get, :create]
78
72
  has_many :account_store_mappings, href: '/accountStoreMappings', can: [:get, :create]
79
73
 
80
-
81
74
  private
82
75
 
83
- def load_api_key_file(api_key_file_location, id_property_name, secret_property_name)
84
- begin
85
- api_key_properties = JavaProperties::Properties.new api_key_file_location
86
- rescue
87
- raise ArgumentError,
88
- "No API Key file could be found or loaded from '" +
89
- api_key_file_location +
90
- "'."
91
- end
76
+ def load_api_key_file api_key_file_location, id_property_name, secret_property_name
77
+ begin
78
+ api_key_properties = JavaProperties::Properties.new api_key_file_location
79
+ rescue
80
+ raise ArgumentError, "No API Key file could be found or loaded from '#{api_key_file_location}'."
81
+ end
92
82
 
93
- id_property_name ||= 'apiKey.id'
94
- secret_property_name ||= 'apiKey.secret'
83
+ id_property_name ||= 'apiKey.id'
84
+ secret_property_name ||= 'apiKey.secret'
95
85
 
96
- api_key_id = api_key_properties[id_property_name]
97
- assert_not_nil api_key_id,
98
- "No API id in properties. Please provide a 'apiKey.id' property in '" +
99
- api_key_file_location +
100
- "' or pass in an 'api_key_id_property_name' to the Stormpath::Client " +
101
- "constructor to specify an alternative property."
86
+ api_key_id = api_key_properties[id_property_name]
87
+ assert_not_nil api_key_id, api_key_warning_message(:id, api_key_file_location)
102
88
 
103
- api_key_secret = api_key_properties[secret_property_name]
104
- assert_not_nil api_key_secret,
105
- "No API secret in properties. Please provide a 'apiKey.secret' property in '" +
106
- api_key_file_location +
107
- "' or pass in an 'api_key_secret_property_name' to the Stormpath::Client " +
108
- "constructor to specify an alternative property."
89
+ api_key_secret = api_key_properties[secret_property_name]
90
+ assert_not_nil api_key_secret, api_key_warning_message(:secret, api_key_file_location)
109
91
 
110
- ApiKey.new api_key_id, api_key_secret
111
- end
92
+ ApiKey.new api_key_id, api_key_secret
93
+ end
94
+
95
+ def api_key_warning_message id_or_secret, api_key_file_location
96
+ "No API #{id_or_secret} in properties. Please provide a 'apiKey.#{id_or_secret}' property " +
97
+ "in '#{api_key_file_location}' or pass in an 'api_key_#{id_or_secret}_property_name' " +
98
+ "to the Stormpath::Client constructor to specify an alternative property."
99
+ end
112
100
 
113
101
  end
114
102
  end
@@ -19,6 +19,7 @@ class Stormpath::DataStore
19
19
 
20
20
  DEFAULT_SERVER_HOST = "api.stormpath.com"
21
21
  DEFAULT_API_VERSION = 1
22
+ DEFAULT_BASE_URL = "https://" + DEFAULT_SERVER_HOST + "/v" + DEFAULT_API_VERSION.to_s
22
23
  HREF_PROP_NAME = Stormpath::Resource::Base::HREF_PROP_NAME
23
24
 
24
25
  CACHE_REGIONS = %w( applications directories accounts groups groupMemberships accountMemberships tenants customData )
@@ -29,7 +30,7 @@ class Stormpath::DataStore
29
30
  assert_not_nil request_executor, "RequestExecutor cannot be null."
30
31
 
31
32
  @client = client
32
- @base_url = get_base_url(base_url)
33
+ @base_url = base_url || DEFAULT_BASE_URL
33
34
  @request_executor = request_executor
34
35
  initialize_cache cache_opts
35
36
  end
@@ -68,7 +69,6 @@ class Stormpath::DataStore
68
69
  def save(resource, clazz = nil)
69
70
  assert_not_nil resource, "resource argument cannot be null."
70
71
  assert_kind_of Stormpath::Resource::Base, resource, "resource argument must be instance of Stormpath::Resource::Base"
71
-
72
72
  href = resource.href
73
73
  assert_not_nil href, "href or resource.href cannot be null."
74
74
  assert_true href.length > 0, "save may only be called on objects that have already been persisted (i.e. they have an existing href)."
@@ -100,12 +100,7 @@ class Stormpath::DataStore
100
100
  end
101
101
 
102
102
  def qualify(href)
103
- if needs_to_be_fully_qualified(href)
104
- slash_added = href.start_with?('/') ? '' : '/'
105
- @base_url + slash_added + href
106
- else
107
- href
108
- end
103
+ needs_to_be_fully_qualified(href) ? @base_url + href : href
109
104
  end
110
105
 
111
106
  def execute_request(http_method, href, body=nil, query=nil)
@@ -121,37 +116,51 @@ class Stormpath::DataStore
121
116
 
122
117
  if response.error?
123
118
  error = Stormpath::Resource::Error.new result
124
- #puts "Error with request: #{http_method.upcase}: #{href}"
125
119
  raise Stormpath::Error.new error
126
120
  end
127
121
 
128
122
  if http_method == 'delete'
129
- cache = cache_for href
130
- cache.delete href if cache
123
+ clear_cache_on_delete(href)
131
124
  return nil
132
125
  end
133
126
 
134
- if result['href']
127
+ if result[HREF_PROP_NAME]
135
128
  cache_walk result
136
129
  else
137
130
  result
138
131
  end
139
132
  end
140
133
 
134
+ def clear_cache_on_delete href
135
+ if href =~ custom_data_delete_field_url_regex
136
+ href = href.split('/')[0..-2].join('/')
137
+ end
138
+ clear_cache href
139
+ end
140
+
141
+ def custom_data_delete_field_url_regex
142
+ /#{@base_url}\/(accounts|groups)\/\w+\/customData\/\w+[\/]{0,1}$/
143
+ end
144
+
145
+ def clear_cache(href)
146
+ cache = cache_for href
147
+ cache.delete href if cache
148
+ end
149
+
141
150
  def cache_walk(resource)
142
- assert_not_nil resource['href'], "resource must have 'href' property"
151
+ assert_not_nil resource[HREF_PROP_NAME], "resource must have 'href' property"
143
152
  items = resource['items']
144
153
 
145
154
  if items # collection resource
146
155
  resource['items'] = items.map do |item|
147
156
  cache_walk item
148
- { 'href' => item['href'] }
157
+ { HREF_PROP_NAME => item[HREF_PROP_NAME] }
149
158
  end
150
159
  else # single resource
151
160
  resource.each do |attr, value|
152
- if value.is_a? Hash and value['href']
161
+ if value.is_a? Hash and value[HREF_PROP_NAME]
153
162
  walked = cache_walk value
154
- resource[attr] = { 'href' => value['href'] } if value["href"]
163
+ resource[attr] = { HREF_PROP_NAME => value[HREF_PROP_NAME] }
155
164
  resource[attr]['items'] = walked['items'] if walked['items']
156
165
  end
157
166
  end
@@ -161,8 +170,8 @@ class Stormpath::DataStore
161
170
  end
162
171
 
163
172
  def cache(resource)
164
- cache = cache_for resource['href']
165
- cache.put resource['href'], resource if cache
173
+ cache = cache_for resource[HREF_PROP_NAME]
174
+ cache.put resource[HREF_PROP_NAME], resource if cache
166
175
  end
167
176
 
168
177
  def cache_for(href)
@@ -170,7 +179,7 @@ class Stormpath::DataStore
170
179
  end
171
180
 
172
181
  def region_for(href)
173
- return nil unless href
182
+ return nil if href.nil?
174
183
  if href.include? "/customData"
175
184
  region = href.split('/')[-1]
176
185
  else
@@ -183,7 +192,7 @@ class Stormpath::DataStore
183
192
  request.http_headers.store 'Accept', 'application/json'
184
193
  request.http_headers.store 'User-Agent', 'Stormpath-RubySDK/' + Stormpath::VERSION
185
194
 
186
- if !request.body.nil? and request.body.length > 0
195
+ if request.body and request.body.length > 0
187
196
  request.http_headers.store 'Content-Type', 'application/json'
188
197
  end
189
198
  end
@@ -195,19 +204,46 @@ class Stormpath::DataStore
195
204
 
196
205
  q_href = qualify href
197
206
 
198
- response = execute_request('post', q_href, MultiJson.dump(to_hash(resource)))
207
+ clear_cache_on_save(resource)
208
+
209
+ response = execute_request 'post', q_href, MultiJson.dump(to_hash(resource))
199
210
 
200
211
  instantiate return_type, response.to_hash
201
212
  end
202
213
 
203
- def get_base_url(base_url)
204
- base_url || "https://" + DEFAULT_SERVER_HOST + "/v" + DEFAULT_API_VERSION.to_s
214
+ def clear_cache_on_save(resource)
215
+ if resource.is_a? Stormpath::Resource::CustomDataStorage
216
+ clear_custom_data_cache_on_custom_data_storage_save(resource)
217
+ elsif resource.is_a? Stormpath::Resource::AccountStoreMapping
218
+ clear_application_cache_on_account_store_save(resource)
219
+ end
220
+ end
221
+
222
+
223
+ def clear_custom_data_cache_on_custom_data_storage_save resource
224
+ if resource.dirty_properties.has_key? "customData" and resource.new? == false
225
+ cached_href = resource.href + "/customData"
226
+ clear_cache cached_href
227
+ end
228
+ end
229
+
230
+ def clear_application_cache_on_account_store_save resource
231
+ if resource.new?
232
+ if resource.default_account_store? == true || resource.default_group_store? == true
233
+ clear_cache resource.application.href
234
+ end
235
+ else
236
+ if resource.dirty_properties["isDefaultAccountStore"] != nil || resource.dirty_properties["isDefaultGroupStore"] != nil
237
+ clear_cache resource.application.href
238
+ end
239
+ end
205
240
  end
206
241
 
207
242
  def to_hash(resource)
208
243
  Hash.new.tap do |properties|
209
244
  resource.get_dirty_property_names.each do |name|
210
- property = resource.get_property name
245
+ ignore_camelcasing = resource_not_custom_data(resource, name) ? false : true
246
+ property = resource.get_property name, ignore_camelcasing: ignore_camelcasing
211
247
 
212
248
  # Special use case is with Custom Data, it's hashes should not be simplified
213
249
  if property.kind_of?(Hash) and resource_not_custom_data resource, name
@@ -14,13 +14,9 @@
14
14
  # limitations under the License.
15
15
  #
16
16
  module Stormpath
17
-
18
17
  module Http
19
-
20
18
  module Authc
21
-
22
19
  class Sauthc1Signer
23
-
24
20
  include OpenSSL
25
21
  include UUIDTools
26
22
  include Stormpath::Http::Utils
@@ -45,7 +41,6 @@ module Stormpath
45
41
  end
46
42
 
47
43
  def sign_request request, api_key
48
-
49
44
  request.http_headers.delete(Sauthc1Signer::AUTHORIZATION_HEADER)
50
45
  request.http_headers.delete(Sauthc1Signer::STORMPATH_DATE_HEADER)
51
46
 
@@ -60,8 +55,8 @@ module Stormpath
60
55
  # SAuthc1 requires that we sign the Host header so we
61
56
  # have to have it in the request by the time we sign.
62
57
  host_header = uri.host
63
- if !default_port?(uri)
64
58
 
59
+ if !default_port?(uri)
65
60
  host_header << ":" << uri.port.to_s
66
61
  end
67
62
 
@@ -112,128 +107,96 @@ module Stormpath
112
107
 
113
108
 
114
109
  def to_hex data
115
-
116
110
  result = ''
117
- data.each_byte { |val|
118
111
 
112
+ data.each_byte do |val|
119
113
  hex = val.to_s(16)
120
114
 
121
115
  if hex.length == 1
122
-
123
116
  result << '0'
124
-
125
117
  elsif hex.length == 8
126
-
127
118
  hex = hex[0..6]
128
119
  end
129
120
 
130
121
  result << hex
131
-
132
- }
133
-
122
+ end
134
123
  result
135
-
136
124
  end
137
125
 
138
126
  protected
139
127
 
140
- def canonicalize_query_string request
141
- request.to_s_query_string true
142
- end
143
-
144
- def hash_text text
145
- Digest.digest DEFAULT_ALGORITHM, to_utf8(text)
146
- end
147
-
148
- def sign data, key, algorithm
149
-
150
- digest_data = to_utf8 data
151
-
152
- digest = Digest::Digest.new(algorithm)
153
-
154
- HMAC.digest(digest, key, digest_data)
155
-
156
- end
157
-
158
- def to_utf8 str
159
- #we ask for multi line UTF-8 text
160
- str.scan(/./mu).join
161
- end
162
-
163
- def get_request_payload request
164
- get_request_payload_without_query_params request
165
- end
166
-
167
- def get_request_payload_without_query_params request
168
-
169
- result = ''
170
-
171
- if !request.body.nil?
172
- result = request.body
128
+ def canonicalize_query_string request
129
+ request.to_s_query_string true
173
130
  end
174
131
 
175
- result
176
-
177
- end
178
-
179
- private
180
-
181
- def create_name_value_pair name, value
182
- name + '=' + value
183
- end
184
-
185
- def canonicalize_resource_path resource_path
186
-
187
- if resource_path.nil? or resource_path.empty?
188
- '/'
189
- else
190
- encode_url resource_path, true, true
132
+ def hash_text text
133
+ Digest.digest DEFAULT_ALGORITHM, to_utf8(text)
191
134
  end
192
- end
193
135
 
194
-
195
- def canonicalize_headers request
196
-
197
- sorted_headers = request.http_headers.keys.sort!
198
-
199
- result = ''
200
-
201
- sorted_headers.each do |header|
202
-
203
- result << header.downcase << ':' << request.http_headers[header].to_s
204
-
205
- result << NL
136
+ def sign data, key, algorithm
137
+ digest_data = to_utf8 data
138
+ digest = Digest.new(algorithm)
139
+ HMAC.digest(digest, key, digest_data)
206
140
  end
207
141
 
208
- result
142
+ def to_utf8 str
143
+ #we ask for multi line UTF-8 text
144
+ str.scan(/./mu).join
145
+ end
209
146
 
210
- end
147
+ def get_request_payload request
148
+ get_request_payload_without_query_params request
149
+ end
211
150
 
212
- def get_signed_headers request
151
+ def get_request_payload_without_query_params request
152
+ result = ''
153
+ if !request.body.nil?
154
+ result = request.body
155
+ end
156
+ result
157
+ end
213
158
 
214
- sorted_headers = request.http_headers.keys.sort!
159
+ private
215
160
 
216
- result = ''
217
- sorted_headers.each do |header|
161
+ def create_name_value_pair name, value
162
+ name + '=' + value
163
+ end
218
164
 
219
- if !result.empty?
220
- result << ';' << header
165
+ def canonicalize_resource_path resource_path
166
+ if resource_path.nil? or resource_path.empty?
167
+ '/'
221
168
  else
222
- result << header
169
+ encode_url resource_path, true, true
223
170
  end
224
-
225
-
226
171
  end
227
172
 
228
- result.downcase
229
-
230
- end
231
173
 
174
+ def canonicalize_headers request
175
+ sorted_headers = request.http_headers.keys.sort!
176
+ result = ''
232
177
 
233
- end
178
+ sorted_headers.each do |header|
179
+ result << header.downcase << ':' << request.http_headers[header].to_s
180
+ result << NL
181
+ end
182
+ result
183
+ end
234
184
 
235
- end
185
+ def get_signed_headers request
186
+ sorted_headers = request.http_headers.keys.sort!
187
+ result = ''
188
+ sorted_headers.each do |header|
189
+ if !result.empty?
190
+ result << ';' << header
191
+ else
192
+ result << header
193
+ end
194
+ end
195
+ result.downcase
196
+ end
236
197
 
237
- end
238
198
 
239
- end
199
+ end#Sauthc1Signer
200
+ end#Authc
201
+ end#Http
202
+ end#Stormpath