stormpath-sdk 1.1.5 → 1.2.0
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 +4 -4
- data/.gitignore +0 -0
- data/.ruby-gemset +0 -0
- data/.travis.yml +1 -0
- data/CHANGES.md +20 -0
- data/Gemfile +0 -0
- data/README.md +78 -2
- data/Rakefile +0 -0
- data/lib/stormpath-sdk/api_key.rb +0 -0
- data/lib/stormpath-sdk/auth/authentication_result.rb +0 -0
- data/lib/stormpath-sdk/auth/basic_authenticator.rb +0 -0
- data/lib/stormpath-sdk/auth/basic_login_attempt.rb +0 -0
- data/lib/stormpath-sdk/auth/http_basic_authentication.rb +47 -0
- data/lib/stormpath-sdk/auth/http_bearer_authentication.rb +27 -0
- data/lib/stormpath-sdk/auth/username_password_request.rb +0 -0
- data/lib/stormpath-sdk/cache/cache.rb +0 -0
- data/lib/stormpath-sdk/cache/cache_entry.rb +0 -0
- data/lib/stormpath-sdk/cache/cache_manager.rb +0 -0
- data/lib/stormpath-sdk/cache/cache_stats.rb +0 -0
- data/lib/stormpath-sdk/cache/disabled_cache_store.rb +0 -0
- data/lib/stormpath-sdk/cache/memcached_store.rb +37 -0
- data/lib/stormpath-sdk/cache/memory_store.rb +0 -0
- data/lib/stormpath-sdk/cache/redis_store.rb +0 -0
- data/lib/stormpath-sdk/client.rb +0 -0
- data/lib/stormpath-sdk/data_store.rb +1 -0
- data/lib/stormpath-sdk/error.rb +5 -5
- data/lib/stormpath-sdk/http/authc/sauthc1_signer.rb +0 -0
- data/lib/stormpath-sdk/http/http_client_request_executor.rb +2 -3
- data/lib/stormpath-sdk/http/request.rb +12 -10
- data/lib/stormpath-sdk/http/response.rb +0 -0
- data/lib/stormpath-sdk/http/utils.rb +8 -5
- data/lib/stormpath-sdk/id_site/id_site_result.rb +0 -0
- data/lib/stormpath-sdk/oauth/access_token_authentication_result.rb +0 -0
- data/lib/stormpath-sdk/oauth/authenticator.rb +2 -1
- data/lib/stormpath-sdk/oauth/error.rb +12 -8
- data/lib/stormpath-sdk/oauth/id_site_grant_request.rb +0 -0
- data/lib/stormpath-sdk/oauth/local_access_token_verification.rb +45 -0
- data/lib/stormpath-sdk/oauth/password_grant.rb +9 -7
- data/lib/stormpath-sdk/oauth/password_grant_request.rb +3 -2
- data/lib/stormpath-sdk/oauth/refresh_grant_request.rb +0 -0
- data/lib/stormpath-sdk/oauth/remote_access_token_verification.rb +28 -0
- data/lib/stormpath-sdk/oauth/social_grant.rb +27 -0
- data/lib/stormpath-sdk/oauth/social_grant_request.rb +14 -0
- data/lib/stormpath-sdk/oauth/stormpath_grant_request.rb +3 -2
- data/lib/stormpath-sdk/oauth/verify_access_token.rb +11 -6
- data/lib/stormpath-sdk/oauth/{verify_token.rb → verify_token_result.rb} +1 -1
- data/lib/stormpath-sdk/provider/account_access.rb +0 -0
- data/lib/stormpath-sdk/provider/account_request.rb +0 -0
- data/lib/stormpath-sdk/provider/account_resolver.rb +0 -0
- data/lib/stormpath-sdk/provider/account_result.rb +0 -0
- data/lib/stormpath-sdk/provider/facebook/facebook_provider.rb +0 -0
- data/lib/stormpath-sdk/provider/facebook/facebook_provider_data.rb +0 -0
- data/lib/stormpath-sdk/provider/github/github_provider.rb +0 -0
- data/lib/stormpath-sdk/provider/github/github_provider_data.rb +0 -0
- data/lib/stormpath-sdk/provider/google/google_provider.rb +0 -0
- data/lib/stormpath-sdk/provider/google/google_provider_data.rb +0 -1
- data/lib/stormpath-sdk/provider/linkedin/linkedin_provider.rb +0 -0
- data/lib/stormpath-sdk/provider/linkedin/linkedin_provider_data.rb +0 -0
- data/lib/stormpath-sdk/provider/provider.rb +0 -0
- data/lib/stormpath-sdk/provider/provider_data.rb +0 -0
- data/lib/stormpath-sdk/provider/saml/saml_mapping_rules.rb +0 -0
- data/lib/stormpath-sdk/provider/saml/saml_provider.rb +0 -0
- data/lib/stormpath-sdk/provider/saml/saml_provider_data.rb +0 -0
- data/lib/stormpath-sdk/provider/saml/saml_provider_metadata.rb +0 -0
- data/lib/stormpath-sdk/provider/stormpath/stormpath_provider.rb +0 -0
- data/lib/stormpath-sdk/provider/stormpath/stormpath_provider_data.rb +0 -0
- data/lib/stormpath-sdk/resource/access_token.rb +0 -0
- data/lib/stormpath-sdk/resource/account_creation_policy.rb +3 -1
- data/lib/stormpath-sdk/resource/account_membership.rb +0 -0
- data/lib/stormpath-sdk/resource/account_overrides.rb +0 -0
- data/lib/stormpath-sdk/resource/account_store.rb +7 -8
- data/lib/stormpath-sdk/resource/account_store_mapping.rb +0 -0
- data/lib/stormpath-sdk/resource/application.rb +5 -5
- data/lib/stormpath-sdk/resource/base.rb +0 -0
- data/lib/stormpath-sdk/resource/collection.rb +0 -0
- data/lib/stormpath-sdk/resource/custom_data.rb +0 -0
- data/lib/stormpath-sdk/resource/custom_data_hash_methods.rb +0 -0
- data/lib/stormpath-sdk/resource/custom_data_storage.rb +0 -0
- data/lib/stormpath-sdk/resource/directory.rb +1 -0
- data/lib/stormpath-sdk/resource/email_template.rb +0 -0
- data/lib/stormpath-sdk/resource/email_verification_token.rb +0 -0
- data/lib/stormpath-sdk/resource/error.rb +2 -3
- data/lib/stormpath-sdk/resource/expansion.rb +0 -0
- data/lib/stormpath-sdk/resource/group.rb +0 -0
- data/lib/stormpath-sdk/resource/group_membership.rb +0 -0
- data/lib/stormpath-sdk/resource/instance.rb +0 -0
- data/lib/stormpath-sdk/resource/oauth_policy.rb +0 -0
- data/lib/stormpath-sdk/resource/organization.rb +1 -1
- data/lib/stormpath-sdk/resource/organization_account_store_mapping.rb +0 -0
- data/lib/stormpath-sdk/resource/password_policy.rb +0 -0
- data/lib/stormpath-sdk/resource/password_reset_token.rb +0 -0
- data/lib/stormpath-sdk/resource/password_strength.rb +0 -0
- data/lib/stormpath-sdk/resource/refresh_token.rb +0 -0
- data/lib/stormpath-sdk/resource/tenant.rb +0 -0
- data/lib/stormpath-sdk/resource/utils.rb +0 -0
- data/lib/stormpath-sdk/resource/verification_email.rb +0 -0
- data/lib/stormpath-sdk/util/assert.rb +0 -0
- data/lib/stormpath-sdk/util/uri_builder.rb +38 -0
- data/lib/stormpath-sdk/version.rb +2 -2
- data/lib/stormpath-sdk.rb +47 -39
- data/spec/api_key_spec.rb +0 -0
- data/spec/auth/basic_authenticator_spec.rb +0 -0
- data/spec/auth/http_basic_authentication_spec.rb +86 -0
- data/spec/auth/http_bearer_authentication_spec.rb +86 -0
- data/spec/auth/sauthc1_signer_spec.rb +0 -0
- data/spec/cache/cache_entry_spec.rb +0 -0
- data/spec/cache/cache_spec.rb +0 -0
- data/spec/cache/cache_stats_spec.rb +0 -0
- data/spec/client_spec.rb +0 -0
- data/spec/data_store_spec.rb +40 -16
- data/spec/fixtures/response/create_saml_directory.json +0 -0
- data/spec/fixtures/response/create_saml_directory_mapping_rules.json +0 -0
- data/spec/fixtures/response/get_saml_directory_provider.json +0 -0
- data/spec/fixtures/response/get_saml_directory_provider_metadata.json +0 -0
- data/spec/oauth/access_token_authentication_result_spec.rb +8 -0
- data/spec/provider/account_resolver_spec.rb +0 -0
- data/spec/provider/provider_spec.rb +0 -0
- data/spec/resource/account_creation_policy_spec.rb +125 -2
- data/spec/resource/account_store_mapping_spec.rb +0 -0
- data/spec/resource/account_store_spec.rb +40 -13
- data/spec/resource/application_spec.rb +268 -51
- data/spec/resource/base_spec.rb +0 -0
- data/spec/resource/collection_spec.rb +60 -2
- data/spec/resource/custom_data_spec.rb +0 -0
- data/spec/resource/directory_spec.rb +82 -1
- data/spec/resource/email_template_spec.rb +0 -0
- data/spec/resource/expansion_spec.rb +0 -0
- data/spec/resource/group_membership_spec.rb +0 -0
- data/spec/resource/group_spec.rb +0 -0
- data/spec/resource/organization_spec.rb +37 -8
- data/spec/resource/password_policy_spec.rb +0 -0
- data/spec/resource/password_strength_spec.rb +0 -0
- data/spec/resource/status_spec.rb +0 -0
- data/spec/resource/tenant_spec.rb +0 -0
- data/spec/spec_helper.rb +5 -6
- data/spec/support/custom_data_storage_behavior.rb +0 -0
- data/spec/support/mocked_provider_accounts.rb +129 -117
- data/spec/support/resource_factory.rb +0 -0
- data/spec/support/resource_matchers.rb +7 -0
- data/spec/support/test_cache_stores.rb +0 -0
- data/spec/support/test_request_executor.rb +0 -0
- data/spec/util/uri_builder_spec.rb +47 -0
- data/stormpath-sdk.gemspec +1 -0
- data/support/api.rb +0 -0
- metadata +29 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 23386924f0b6cb041d80e4900d5cba99cc93da80
|
|
4
|
+
data.tar.gz: 7e9d14180ef6f5e6fadfcb11836cf4e3ceca7ba5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 15039329aa8f769f5b73bd763e2bb29df905a26f06782f7dcaac8cc17a5140f5244e2fb42d66d19afb4613d4dc833536c1e55994bc1e545e003a8252a858ffea
|
|
7
|
+
data.tar.gz: be5240dbe085d0566b3a1e1fb4a8cc39c0b566d7b7958fa655b373834a7c98be4f4885d7cb74547e9f4158cccc595540d04bcf4859033d840e8186caa8638e5f
|
data/.gitignore
CHANGED
|
File without changes
|
data/.ruby-gemset
CHANGED
|
File without changes
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
stormpath-sdk-ruby Changelog
|
|
2
2
|
============================
|
|
3
3
|
|
|
4
|
+
Version 1.2.0
|
|
5
|
+
-------------
|
|
6
|
+
|
|
7
|
+
Released on October 27, 2016
|
|
8
|
+
|
|
9
|
+
- Add memcached store as option for the cache store
|
|
10
|
+
- Implement http basic and bearer access token validation
|
|
11
|
+
- Add get and create method on organizations accounts collection
|
|
12
|
+
- Implement option to verify access_token locally and adjust current interface for it
|
|
13
|
+
- Fix bug with searching accounts by custom data attributes
|
|
14
|
+
- Fix bug when loading application that has a forward slash in client_id or client_secret
|
|
15
|
+
- Add organizations endpoint on directory
|
|
16
|
+
- Add option to exchange stormpath_token for an access_token with the registered status
|
|
17
|
+
- Add support for organizationNameKey for oauth token exchange
|
|
18
|
+
- Create social grant request as a new type of grant requests
|
|
19
|
+
- Add request id to error resources
|
|
20
|
+
- Support blacklisting/whitelisting domains in account creation policies for directories
|
|
21
|
+
- Add 'Organization' as a valid type of account store
|
|
22
|
+
|
|
23
|
+
|
|
4
24
|
Version 1.1.5
|
|
5
25
|
-------------
|
|
6
26
|
|
data/Gemfile
CHANGED
|
File without changes
|
data/README.md
CHANGED
|
@@ -10,7 +10,7 @@ application.
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
12
12
|
```sh
|
|
13
|
-
$ gem install stormpath-sdk
|
|
13
|
+
$ gem install stormpath-sdk
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
## Provision Your Stormpath Account
|
|
@@ -193,6 +193,25 @@ in the hash of values passed on Client initialization:
|
|
|
193
193
|
client = application.client
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
+
To change the base_url for the Enterprise product, pass the following option to `Stormpath::Client.new()` :
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
client = Stormpath::Client.new(
|
|
200
|
+
api_key_file_location: '/some/path/to/apiKey.properties',
|
|
201
|
+
base_url: 'https://enterprise.stormpath.io/v1'
|
|
202
|
+
)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
* By passing a composite application url to `Application.load`:
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
composite_url = "http://#{api_key_id}:#{api_key_secret}@api.stormpath.com/v1/applications/#{application_id}"
|
|
209
|
+
|
|
210
|
+
application = Stormpath::Resource::Application.load composite_url
|
|
211
|
+
client = application.client
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
|
|
196
215
|
### Accessing Resources
|
|
197
216
|
|
|
198
217
|
Most of the work you do with Stormpath is done through the applications
|
|
@@ -378,6 +397,22 @@ Again, with all these methods, You will want your application to link to an inte
|
|
|
378
397
|
> NOTE:
|
|
379
398
|
> A JWT will expire after 60 seconds of creation.
|
|
380
399
|
|
|
400
|
+
#### Fetch Stormpath Access Token with username and password
|
|
401
|
+
Stormpath can generate a brand new Access Token using the password grant type: User's credentials.
|
|
402
|
+
|
|
403
|
+
To fetch the oauth token use the following snippet
|
|
404
|
+
```ruby
|
|
405
|
+
grant_request = Stormpath::Oauth::PasswordGrantRequest.new(email, password)
|
|
406
|
+
response = application.authenticate_oauth(grant_request)
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Just like with logging-in a user, it is possible to generate a token against a particular Application’s Account Store or Organization. To do so, specify the Account Store’s href or Organization’s nameKey as a parameter in the request:
|
|
410
|
+
|
|
411
|
+
```ruby
|
|
412
|
+
grant_request = Stormpath::Oauth::PasswordGrantRequest.new(email, password, organization_name_key: 'my-stormpath-organization')
|
|
413
|
+
response = application.authenticate_oauth(grant_request)
|
|
414
|
+
```
|
|
415
|
+
|
|
381
416
|
#### Exchange ID Site token for a Stormpath Access Token
|
|
382
417
|
After the user has been authenticated via ID Site, a developer may want to control their authorization with an OAuth 2.0 Token.
|
|
383
418
|
This is done by passing the JWT similar to the way we passed the user’s credentials as described in [Generating an OAuth 2.0 Access Token][generate-oauth-access-token].
|
|
@@ -414,6 +449,45 @@ puts authentication_result.access_token
|
|
|
414
449
|
puts authentication_result.refresh_token
|
|
415
450
|
```
|
|
416
451
|
|
|
452
|
+
### Exchange ID site token for a Stormpath Access Token
|
|
453
|
+
|
|
454
|
+
As a developer, I want to authenticate the user on ID Site but get an access token that I can store on the client to use to access my API.
|
|
455
|
+
The oauth token endpoint will validate that:
|
|
456
|
+
* the JWT is not tampered
|
|
457
|
+
* has not expired
|
|
458
|
+
* the account is still associated with the application and will return an access token
|
|
459
|
+
* the status claim is either AUTHENTICATED or REGISTERED
|
|
460
|
+
|
|
461
|
+
If you want to create a stormpath grant request with status <code>authenticated</code> you need to pass the account, application and api key id:
|
|
462
|
+
|
|
463
|
+
```ruby
|
|
464
|
+
stormpath_grant_request = Stormpath::Oauth::StormpathGrantRequest.new(
|
|
465
|
+
account,
|
|
466
|
+
application,
|
|
467
|
+
api_key_id
|
|
468
|
+
)
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
If you have the status attribute set to <code>registered</code> then create the request like so:
|
|
472
|
+
|
|
473
|
+
```ruby
|
|
474
|
+
stormpath_grant_request = Stormpath::Oauth::StormpathGrantRequest.new(
|
|
475
|
+
account,
|
|
476
|
+
application,
|
|
477
|
+
api_key_id,
|
|
478
|
+
:registered
|
|
479
|
+
)
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
And lastly authenticate with the created request instance:
|
|
483
|
+
|
|
484
|
+
```ruby
|
|
485
|
+
authentication_result = application.authenticate_oauth(stormpath_grant_request)
|
|
486
|
+
|
|
487
|
+
puts authentication_result.access_token
|
|
488
|
+
puts authentication_result.refresh_token
|
|
489
|
+
```
|
|
490
|
+
|
|
417
491
|
### Registering Accounts
|
|
418
492
|
|
|
419
493
|
Accounts are created on a directory instance. They can be created in two
|
|
@@ -478,8 +552,9 @@ end
|
|
|
478
552
|
If you are moving from an existing user repository to Stormpath, you may have existing password hashes that you want to reuse to provide a seamless upgrade path for your end users.
|
|
479
553
|
More info about this feature can be found [here][mcf-hash-password-doc]
|
|
480
554
|
|
|
481
|
-
Example of creating an account with existing SHA-512 password hash. For details on other hashing algorithms
|
|
555
|
+
Example of creating an account with existing SHA-512 password hash. For details on other hashing algorithms check the [documentation][stormpath-hash-algorithm]
|
|
482
556
|
|
|
557
|
+
```ruby
|
|
483
558
|
directory.accounts.create({
|
|
484
559
|
username: "jlucpicard",
|
|
485
560
|
email: "captain@enterprise.com",
|
|
@@ -487,6 +562,7 @@ directory.accounts.create({
|
|
|
487
562
|
surname: "Picard",
|
|
488
563
|
password: "$stormpath2$SHA-512$1$ZFhBRmpFSnEwVEx2ekhKS0JTMDJBNTNmcg==$Q+sGFg9e+pe9QsUdfnbJUMDtrQNf27ezTnnGllBVkQpMRc9bqH6WkyE3y0svD/7cBk8uJW9Wb3dolWwDtDLFjg=="
|
|
489
564
|
}, password_format: 'mcf')
|
|
565
|
+
```
|
|
490
566
|
|
|
491
567
|
### Authentication
|
|
492
568
|
|
data/Rakefile
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Stormpath
|
|
2
|
+
module Authentication
|
|
3
|
+
class HttpBasicAuthentication
|
|
4
|
+
BASIC_PATTERN = /^Basic /
|
|
5
|
+
attr_reader :application, :authorization_header
|
|
6
|
+
|
|
7
|
+
def initialize(application, authorization_header)
|
|
8
|
+
@application = application
|
|
9
|
+
@authorization_header = authorization_header
|
|
10
|
+
raise Stormpath::Error if authorization_header.nil?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def authenticate!
|
|
14
|
+
raise Stormpath::Error if fetched_api_key.nil?
|
|
15
|
+
raise Stormpath::Error if fetched_api_key.secret != api_key_secret
|
|
16
|
+
fetched_api_key
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def fetched_api_key
|
|
22
|
+
@fetched_api_key ||= application.api_keys.search(id: api_key_id).first
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def api_key_id
|
|
26
|
+
decoded_authorization_header.first
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def api_key_secret
|
|
30
|
+
decoded_authorization_header.last
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def decoded_authorization_header
|
|
34
|
+
@decoded_authorization_header ||= begin
|
|
35
|
+
api_key_and_secret = Base64.decode64(basic_authorization_header).split(':')
|
|
36
|
+
raise Stormpath::Error if api_key_and_secret.count != 2
|
|
37
|
+
api_key_and_secret
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def basic_authorization_header
|
|
42
|
+
raise Stormpath::Error unless authorization_header =~ BASIC_PATTERN
|
|
43
|
+
authorization_header.gsub(BASIC_PATTERN, '')
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Stormpath
|
|
2
|
+
module Authentication
|
|
3
|
+
class HttpBearerAuthentication
|
|
4
|
+
BEARER_PATTERN = /^Bearer /
|
|
5
|
+
attr_reader :application, :authorization_header, :local
|
|
6
|
+
|
|
7
|
+
def initialize(application, authorization_header, options = {})
|
|
8
|
+
@application = application
|
|
9
|
+
@authorization_header = authorization_header
|
|
10
|
+
@local = options[:local] || false
|
|
11
|
+
raise Stormpath::Error if authorization_header.nil?
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def authenticate!
|
|
15
|
+
Stormpath::Oauth::VerifyAccessToken.new(application, local: local)
|
|
16
|
+
.verify(bearer_access_token)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def bearer_access_token
|
|
22
|
+
raise Stormpath::Error unless authorization_header =~ BEARER_PATTERN
|
|
23
|
+
authorization_header.gsub(BEARER_PATTERN, '')
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'memcached'
|
|
2
|
+
|
|
3
|
+
module Stormpath
|
|
4
|
+
module Cache
|
|
5
|
+
class MemcachedStore
|
|
6
|
+
def initialize(opts = {})
|
|
7
|
+
options = nil if opts.blank?
|
|
8
|
+
@memcached = Memcached.new(options)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def get(key)
|
|
12
|
+
begin
|
|
13
|
+
entry = @memcached.get(key)
|
|
14
|
+
entry && Stormpath::Cache::CacheEntry.from_h(MultiJson.load(entry))
|
|
15
|
+
rescue Memcached::NotFound
|
|
16
|
+
nil
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def put(key, entry)
|
|
21
|
+
@memcached.set(key, MultiJson.dump(entry.to_h))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def delete(key)
|
|
25
|
+
@memcached.delete(key)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def clear
|
|
29
|
+
@memcached.flush
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def size
|
|
33
|
+
@memcached.stats[:curr_items]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
File without changes
|
|
File without changes
|
data/lib/stormpath-sdk/client.rb
CHANGED
|
File without changes
|
|
@@ -63,6 +63,7 @@ class Stormpath::DataStore
|
|
|
63
63
|
def create(parent_href, resource, return_type, options = {})
|
|
64
64
|
#TODO assuming there is no ? in url
|
|
65
65
|
parent_href = "#{parent_href}?#{URI.encode_www_form(options)}" unless options.empty?
|
|
66
|
+
|
|
66
67
|
save_resource(parent_href, resource, return_type).tap do |returned_resource|
|
|
67
68
|
if resource.kind_of? return_type
|
|
68
69
|
resource.set_properties returned_resource.properties
|
data/lib/stormpath-sdk/error.rb
CHANGED
|
@@ -15,15 +15,15 @@
|
|
|
15
15
|
#
|
|
16
16
|
module Stormpath
|
|
17
17
|
class Error < RuntimeError
|
|
18
|
+
attr_reader :status, :code, :developer_message, :more_info, :request_id
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def initialize error = NilError.new
|
|
20
|
+
def initialize(error = NilError.new)
|
|
22
21
|
super error.message
|
|
23
22
|
@status = error.status
|
|
24
23
|
@code = error.code
|
|
25
24
|
@developer_message = error.developer_message
|
|
26
25
|
@more_info = error.more_info
|
|
26
|
+
@request_id = error.request_id
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
private
|
|
@@ -34,7 +34,7 @@ module Stormpath
|
|
|
34
34
|
def code; -1 end
|
|
35
35
|
def developer_message; end
|
|
36
36
|
def more_info; end
|
|
37
|
+
def request_id; end
|
|
37
38
|
end
|
|
38
|
-
|
|
39
39
|
end
|
|
40
|
-
end
|
|
40
|
+
end
|
|
File without changes
|
|
@@ -36,8 +36,8 @@ module Stormpath
|
|
|
36
36
|
else
|
|
37
37
|
request.href
|
|
38
38
|
end
|
|
39
|
-
|
|
40
|
-
if request.http_headers["Content-Type"] == "application/x-www-form-urlencoded"
|
|
39
|
+
|
|
40
|
+
if request.http_headers["Content-Type"] == "application/x-www-form-urlencoded"
|
|
41
41
|
@http_client.set_auth(request.href, request.api_key.id, request.api_key.secret)
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -60,4 +60,3 @@ module Stormpath
|
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
|
-
|
|
@@ -21,12 +21,11 @@ module Stormpath
|
|
|
21
21
|
attr_accessor :http_method, :href, :query_string, :http_headers, :body, :api_key
|
|
22
22
|
|
|
23
23
|
def initialize(http_method, href, query_string, http_headers, body, api_key)
|
|
24
|
-
|
|
25
24
|
splitted = href.split '?'
|
|
26
25
|
|
|
27
26
|
@query_string = query_string || {}
|
|
28
27
|
|
|
29
|
-
if splitted
|
|
28
|
+
if splitted && splitted.length > 1
|
|
30
29
|
@href = splitted[0]
|
|
31
30
|
query_string_str = splitted[1]
|
|
32
31
|
query_string_arr = query_string_str.split '&'
|
|
@@ -43,33 +42,36 @@ module Stormpath
|
|
|
43
42
|
@body = body
|
|
44
43
|
@api_key = api_key
|
|
45
44
|
|
|
46
|
-
if body
|
|
47
|
-
@http_headers.store 'Content-Length', @body.bytesize
|
|
48
|
-
end
|
|
49
|
-
|
|
45
|
+
@http_headers.store 'Content-Length', @body.bytesize if body
|
|
50
46
|
end
|
|
51
47
|
|
|
52
48
|
def resource_uri
|
|
53
49
|
URI href
|
|
54
50
|
end
|
|
55
51
|
|
|
56
|
-
def to_s_query_string
|
|
52
|
+
def to_s_query_string(canonical)
|
|
57
53
|
result = ''
|
|
58
54
|
|
|
59
55
|
unless @query_string.empty?
|
|
60
|
-
Hash[@query_string.
|
|
61
|
-
|
|
56
|
+
Hash[@query_string.sort_by(&:to_s)].each do |key, value|
|
|
62
57
|
enc_key = encode_url key, false, canonical
|
|
63
58
|
enc_value = encode_url value, false, canonical
|
|
64
59
|
|
|
65
60
|
result << '&' unless result.empty?
|
|
66
|
-
result <<
|
|
61
|
+
result << camelize(enc_key) << '=' << enc_value
|
|
67
62
|
end
|
|
68
63
|
end
|
|
69
64
|
|
|
70
65
|
result
|
|
71
66
|
end
|
|
72
67
|
|
|
68
|
+
def camelize(key)
|
|
69
|
+
custom_data_params?(key) ? key : key.camelize(:lower)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def custom_data_params?(key)
|
|
73
|
+
key.starts_with?('customData.')
|
|
74
|
+
end
|
|
73
75
|
end
|
|
74
76
|
end
|
|
75
77
|
end
|
|
File without changes
|
|
@@ -16,24 +16,27 @@
|
|
|
16
16
|
module Stormpath
|
|
17
17
|
module Http
|
|
18
18
|
module Utils
|
|
19
|
-
|
|
20
19
|
def default_port?(uri)
|
|
21
20
|
scheme = uri.scheme.downcase
|
|
22
21
|
port = uri.port
|
|
23
|
-
port <= 0 || (port == 80 && scheme.eql?(
|
|
22
|
+
port <= 0 || (port == 80 && scheme.eql?('http')) || (port == 443 && scheme.eql?('https'))
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
def encode_url(value, path, canonical)
|
|
27
|
-
|
|
26
|
+
value = value.to_s
|
|
27
|
+
return encoded_chars?(value) ? URI.encode(URI.decode(value)) : URI.encode(value) if path
|
|
28
28
|
|
|
29
29
|
CGI.escape(value.to_s).tap do |encoded|
|
|
30
|
-
str_map = {'+' => '%20', '%7E' => '~' }
|
|
30
|
+
str_map = { '+' => '%20', '%7E' => '~' }
|
|
31
31
|
str_map.each do |key, str_value|
|
|
32
32
|
encoded.gsub!(key, str_value) if encoded.include? key
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
def encoded_chars?(string)
|
|
38
|
+
string.include?('%2E')
|
|
39
|
+
end
|
|
37
40
|
end
|
|
38
41
|
end
|
|
39
|
-
end
|
|
42
|
+
end
|
|
File without changes
|
|
File without changes
|
|
@@ -23,7 +23,8 @@ module Stormpath
|
|
|
23
23
|
refresh_token: RefreshToken,
|
|
24
24
|
id_site_token: IdSiteGrant,
|
|
25
25
|
stormpath_token: StormpathTokenGrant,
|
|
26
|
-
client_credentials: ClientCredentialsGrant
|
|
26
|
+
client_credentials: ClientCredentialsGrant,
|
|
27
|
+
stormpath_social: SocialGrant
|
|
27
28
|
}.freeze
|
|
28
29
|
end
|
|
29
30
|
end
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
module Stormpath
|
|
2
2
|
module Oauth
|
|
3
3
|
class Error < Stormpath::Error
|
|
4
|
-
attr_accessor :status, :code, :message, :developer_message, :more_info
|
|
4
|
+
attr_accessor :status, :code, :message, :developer_message, :more_info, :request_id
|
|
5
5
|
|
|
6
6
|
def initialize(type)
|
|
7
7
|
@status = errors[type][:status]
|
|
8
8
|
@code = errors[type][:code]
|
|
9
9
|
@message = errors[type][:message]
|
|
10
10
|
@developer_message = errors[type][:developer_message]
|
|
11
|
+
@request_id = errors[type][:request_id]
|
|
11
12
|
super(self)
|
|
12
13
|
end
|
|
13
14
|
|
|
@@ -18,21 +19,24 @@ module Stormpath
|
|
|
18
19
|
jwt_cb_uri_incorrect: {
|
|
19
20
|
status: 400,
|
|
20
21
|
code: 400,
|
|
21
|
-
message:
|
|
22
|
-
developer_message:
|
|
23
|
-
|
|
22
|
+
message: 'The specified callback URI (cb_uri) is not valid',
|
|
23
|
+
developer_message: 'The specified callback URI (cb_uri) is not valid. Make '\
|
|
24
|
+
'sure the callback URI specified in your ID Site configuration matches the value specified.',
|
|
25
|
+
request_id: 'Oauth error UUID'
|
|
24
26
|
},
|
|
25
27
|
jwt_expired: {
|
|
26
28
|
status: 400,
|
|
27
29
|
code: 10011,
|
|
28
|
-
message:
|
|
29
|
-
developer_message:
|
|
30
|
+
message: 'Token is invalid',
|
|
31
|
+
developer_message: 'Token is no longer valid because it has expired',
|
|
32
|
+
request_id: 'Oauth error UUID'
|
|
30
33
|
},
|
|
31
34
|
jwt_invalid: {
|
|
32
35
|
status: 400,
|
|
33
36
|
code: 10012,
|
|
34
|
-
message:
|
|
35
|
-
developer_message:
|
|
37
|
+
message: 'Token is invalid',
|
|
38
|
+
developer_message: 'Token is invalid because the issued at time (iat) is after the current time',
|
|
39
|
+
request_id: 'Oauth error UUID'
|
|
36
40
|
}
|
|
37
41
|
}
|
|
38
42
|
end
|
|
File without changes
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Stormpath
|
|
2
|
+
module Oauth
|
|
3
|
+
class LocalAccessTokenVerification
|
|
4
|
+
attr_reader :application, :access_token
|
|
5
|
+
|
|
6
|
+
def initialize(application, access_token)
|
|
7
|
+
@application = application
|
|
8
|
+
@access_token = access_token
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def verify
|
|
12
|
+
validate_jwt_is_an_access_token
|
|
13
|
+
validate_jwt_has_a_valid_issuer
|
|
14
|
+
LocalAccessTokenVerificationResult.new(application, decoded_jwt)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def decoded_jwt
|
|
20
|
+
begin
|
|
21
|
+
@decoded_jwt ||= JWT.decode(access_token, application.client.data_store.api_key.secret)
|
|
22
|
+
rescue JWT::ExpiredSignature
|
|
23
|
+
raise Stormpath::Oauth::Error, :jwt_expired
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def validate_jwt_is_an_access_token
|
|
28
|
+
return if decoded_jwt.second['stt'] == 'access'
|
|
29
|
+
raise ArgumentError, 'Token is not an access token'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def validate_jwt_has_a_valid_issuer
|
|
33
|
+
return if decoded_jwt.first['iss'] == application.href
|
|
34
|
+
raise ArgumentError, 'Token issuer is invalid'
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class LocalAccessTokenVerificationResult
|
|
39
|
+
attr_reader :account
|
|
40
|
+
def initialize(application, decoded_jwt)
|
|
41
|
+
@account = application.client.accounts.get(decoded_jwt.first['sub'])
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
module Stormpath
|
|
2
2
|
module Oauth
|
|
3
3
|
class PasswordGrant < Stormpath::Resource::Base
|
|
4
|
-
prop_accessor :grant_type, :username, :password
|
|
4
|
+
prop_accessor :grant_type, :username, :password, :organization_name_key
|
|
5
5
|
|
|
6
6
|
def form_properties
|
|
7
|
-
{
|
|
8
|
-
grant_type
|
|
9
|
-
username
|
|
10
|
-
password
|
|
11
|
-
|
|
7
|
+
{}.tap do |form|
|
|
8
|
+
form[:grant_type] = grant_type
|
|
9
|
+
form[:username] = username
|
|
10
|
+
form[:password] = password
|
|
11
|
+
form[:organizationNameKey] = organization_name_key if organization_name_key.present?
|
|
12
|
+
end
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def set_options(request)
|
|
16
|
+
set_property :grant_type, request.grant_type
|
|
15
17
|
set_property :username, request.username
|
|
16
18
|
set_property :password, request.password
|
|
17
|
-
set_property :
|
|
19
|
+
set_property :organization_name_key, request.organization_name_key
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def form_data?
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
module Stormpath
|
|
2
2
|
module Oauth
|
|
3
3
|
class PasswordGrantRequest
|
|
4
|
-
attr_accessor :grant_type, :username, :password
|
|
4
|
+
attr_accessor :grant_type, :username, :password, :organization_name_key
|
|
5
5
|
|
|
6
|
-
def initialize(username, password)
|
|
6
|
+
def initialize(username, password, options = {})
|
|
7
7
|
@username = username
|
|
8
8
|
@password = password
|
|
9
9
|
@grant_type = "password"
|
|
10
|
+
@organization_name_key = options[:organization_name_key]
|
|
10
11
|
end
|
|
11
12
|
end
|
|
12
13
|
end
|
|
File without changes
|