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 +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
|