stormpath-sdk 1.1.5 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|