stormpath-sdk 1.0.0.beta.5 → 1.0.0.beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +3 -1
- data/.travis.yml +3 -0
- data/CHANGES.md +10 -0
- data/README.md +2 -2
- data/lib/stormpath-sdk.rb +17 -10
- data/lib/stormpath-sdk/cache/disabled_cache_store.rb +26 -0
- data/lib/stormpath-sdk/client.rb +25 -37
- data/lib/stormpath-sdk/data_store.rb +60 -24
- data/lib/stormpath-sdk/http/authc/sauthc1_signer.rb +58 -95
- data/lib/stormpath-sdk/http/utils.rb +6 -18
- data/lib/stormpath-sdk/resource/associations.rb +16 -16
- data/lib/stormpath-sdk/resource/base.rb +65 -58
- data/lib/stormpath-sdk/resource/collection.rb +41 -21
- data/lib/stormpath-sdk/resource/custom_data.rb +11 -5
- data/lib/stormpath-sdk/resource/custom_data_hash_methods.rb +2 -2
- data/lib/stormpath-sdk/resource/custom_data_storage.rb +1 -1
- data/lib/stormpath-sdk/version.rb +2 -2
- data/spec/client_spec.rb +20 -1
- data/spec/data_store_spec.rb +18 -2
- data/spec/resource/account_spec.rb +1 -1
- data/spec/resource/account_store_mapping_spec.rb +85 -14
- data/spec/resource/collection_spec.rb +201 -1
- data/spec/resource/custom_data_spec.rb +12 -185
- data/spec/resource/directory_spec.rb +2 -4
- data/spec/spec_helper.rb +8 -4
- data/spec/support/custom_data_storage_behavior.rb +391 -0
- data/spec/support/resource_factory.rb +1 -1
- data/support/api.rb +1 -1
- metadata +56 -97
- data/.ruby-version +0 -1
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
data/.travis.yml
CHANGED
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
|
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
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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
|
data/lib/stormpath-sdk/client.rb
CHANGED
@@ -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.
|
42
|
-
|
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
|
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
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
94
|
-
|
83
|
+
id_property_name ||= 'apiKey.id'
|
84
|
+
secret_property_name ||= 'apiKey.secret'
|
95
85
|
|
96
|
-
|
97
|
-
|
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
|
-
|
104
|
-
|
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
|
-
|
111
|
-
|
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 =
|
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
|
-
|
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
|
-
|
130
|
-
cache.delete href if cache
|
123
|
+
clear_cache_on_delete(href)
|
131
124
|
return nil
|
132
125
|
end
|
133
126
|
|
134
|
-
if result[
|
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[
|
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
|
-
{
|
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[
|
161
|
+
if value.is_a? Hash and value[HREF_PROP_NAME]
|
153
162
|
walked = cache_walk value
|
154
|
-
resource[attr] = {
|
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[
|
165
|
-
cache.put resource[
|
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
|
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
|
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
|
-
|
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
|
204
|
-
|
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
|
-
|
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
|
-
|
141
|
-
|
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
|
-
|
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
|
-
|
196
|
-
|
197
|
-
|
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
|
-
|
142
|
+
def to_utf8 str
|
143
|
+
#we ask for multi line UTF-8 text
|
144
|
+
str.scan(/./mu).join
|
145
|
+
end
|
209
146
|
|
210
|
-
|
147
|
+
def get_request_payload request
|
148
|
+
get_request_payload_without_query_params request
|
149
|
+
end
|
211
150
|
|
212
|
-
|
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
|
-
|
159
|
+
private
|
215
160
|
|
216
|
-
|
217
|
-
|
161
|
+
def create_name_value_pair name, value
|
162
|
+
name + '=' + value
|
163
|
+
end
|
218
164
|
|
219
|
-
|
220
|
-
|
165
|
+
def canonicalize_resource_path resource_path
|
166
|
+
if resource_path.nil? or resource_path.empty?
|
167
|
+
'/'
|
221
168
|
else
|
222
|
-
|
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
|
-
|
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
|
-
|
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
|