stormpath-sdk 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/CHANGES.md +11 -0
- data/README.md +234 -3
- data/Rakefile +3 -1
- data/lib/stormpath-sdk.rb +4 -0
- data/lib/stormpath-sdk/auth/basic_login_attempt.rb +4 -0
- data/lib/stormpath-sdk/auth/username_password_request.rb +0 -1
- data/lib/stormpath-sdk/client.rb +1 -1
- data/lib/stormpath-sdk/data_store.rb +17 -9
- data/lib/stormpath-sdk/provider/saml/saml_mapping_rules.rb +22 -0
- data/lib/stormpath-sdk/provider/saml/saml_provider.rb +20 -0
- data/lib/stormpath-sdk/provider/saml/saml_provider_data.rb +19 -0
- data/lib/stormpath-sdk/provider/saml/saml_provider_metadata.rb +19 -0
- data/lib/stormpath-sdk/resource/application.rb +22 -7
- data/lib/stormpath-sdk/resource/directory.rb +16 -0
- data/lib/stormpath-sdk/version.rb +2 -2
- data/spec/client_spec.rb +108 -13
- data/spec/fixtures/response/create_saml_directory.json +26 -0
- data/spec/fixtures/response/create_saml_directory_mapping_rules.json +12 -0
- data/spec/fixtures/response/get_saml_directory_provider.json +16 -0
- data/spec/fixtures/response/get_saml_directory_provider_metadata.json +12 -0
- data/spec/resource/application_spec.rb +378 -33
- data/spec/resource/directory_spec.rb +168 -0
- data/spec/spec_helper.rb +14 -1
- data/stormpath-sdk.gemspec +1 -0
- metadata +25 -3
@@ -0,0 +1,22 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2016 Stormpath, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
class Stormpath::Provider::SamlMappingRules < Stormpath::Provider::Provider
|
17
|
+
prop_reader :href, :created_at, :modified_at, :items
|
18
|
+
|
19
|
+
def set_options(options)
|
20
|
+
set_property :href, options[:href]
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2016 Stormpath, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
class Stormpath::Provider::SamlProvider < Stormpath::Provider::Provider
|
17
|
+
prop_reader :provider_id, :sso_login_url, :sso_logout_url,
|
18
|
+
:encoded_x509_signing_cert, :request_signature_algorithm,
|
19
|
+
:service_provider_metadata, :attribute_statement_mapping_rules
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2016 Stormpath, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
class Stormpath::Provider::SamlProviderData < Stormpath::Provider::ProviderData
|
17
|
+
prop_reader :href, :created_at, :modified_at, :provider_id, :sso_log_in_url,
|
18
|
+
:sso_lgout_url
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2016 Stormpath, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
class Stormpath::Provider::SamlProviderMetadata < Stormpath::Provider::ProviderData
|
17
|
+
prop_reader :href, :created_at, :modified_at, :entity_id, :x509_signing_cert,
|
18
|
+
:assertion_consumer_service_post_endpoint
|
19
|
+
end
|
@@ -21,7 +21,7 @@ class Stormpath::Resource::Application < Stormpath::Resource::Instance
|
|
21
21
|
|
22
22
|
class LoadError < Stormpath::Error; end
|
23
23
|
|
24
|
-
prop_accessor :name, :description
|
24
|
+
prop_accessor :name, :description, :authorized_callback_uris
|
25
25
|
|
26
26
|
belongs_to :tenant
|
27
27
|
|
@@ -91,8 +91,8 @@ class Stormpath::Resource::Application < Stormpath::Resource::Instance
|
|
91
91
|
id_site_result
|
92
92
|
end
|
93
93
|
|
94
|
-
def send_password_reset_email
|
95
|
-
password_reset_token = create_password_reset_token
|
94
|
+
def send_password_reset_email(email, account_store: nil)
|
95
|
+
password_reset_token = create_password_reset_token(email, account_store: account_store)
|
96
96
|
password_reset_token.account
|
97
97
|
end
|
98
98
|
|
@@ -109,9 +109,9 @@ class Stormpath::Resource::Application < Stormpath::Resource::Instance
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def authenticate_oauth(request)
|
112
|
-
Stormpath::Oauth::Authenticator.new(data_store).authenticate(href, request)
|
112
|
+
Stormpath::Oauth::Authenticator.new(data_store).authenticate(href, request)
|
113
113
|
end
|
114
|
-
|
114
|
+
|
115
115
|
private
|
116
116
|
|
117
117
|
def jwt_token_payload(options)
|
@@ -135,7 +135,22 @@ class Stormpath::Resource::Application < Stormpath::Resource::Instance
|
|
135
135
|
client.data_store.api_key.id
|
136
136
|
end
|
137
137
|
|
138
|
-
def create_password_reset_token
|
139
|
-
|
138
|
+
def create_password_reset_token(email, account_store: nil)
|
139
|
+
params = { email: email }
|
140
|
+
params[:account_store] = account_store_to_hash(account_store) if account_store
|
141
|
+
password_reset_tokens.create(params)
|
142
|
+
end
|
143
|
+
|
144
|
+
def account_store_to_hash(account_store)
|
145
|
+
case account_store
|
146
|
+
when Stormpath::Resource::Organization
|
147
|
+
{ name_key: account_store.name_key }
|
148
|
+
when Stormpath::Resource::Group, Stormpath::Resource::Directory
|
149
|
+
{ href: account_store.href }
|
150
|
+
when Hash
|
151
|
+
account_store
|
152
|
+
else
|
153
|
+
fail ArgumentError, 'Account store has to be passed either as an resource or a hash'
|
154
|
+
end
|
140
155
|
end
|
141
156
|
end
|
@@ -40,4 +40,20 @@ class Stormpath::Resource::Directory < Stormpath::Resource::Instance
|
|
40
40
|
provider = data_store.get_resource provider_href, clazz_proc
|
41
41
|
instance_variable_set "@_provider", provider
|
42
42
|
end
|
43
|
+
|
44
|
+
def provider_metadata
|
45
|
+
metadata_href = provider.service_provider_metadata["href"]
|
46
|
+
data_store.get_resource metadata_href, Stormpath::Provider::SamlProviderMetadata
|
47
|
+
end
|
48
|
+
|
49
|
+
def statement_mapping_rules
|
50
|
+
metadata_href = provider.attribute_statement_mapping_rules["href"]
|
51
|
+
data_store.get_resource metadata_href, Stormpath::Provider::SamlMappingRules
|
52
|
+
end
|
53
|
+
|
54
|
+
def create_attribute_mappings(mappings)
|
55
|
+
mappings.set_options(href: provider.attribute_statement_mapping_rules["href"])
|
56
|
+
data_store.create mappings.href, mappings, Stormpath::Provider::SamlMappingRules
|
57
|
+
end
|
43
58
|
end
|
59
|
+
|
data/spec/client_spec.rb
CHANGED
@@ -12,17 +12,20 @@ describe Stormpath::Client, :vcr do
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
let(:api_key_and_secret_properties) do
|
16
|
+
<<-properties
|
17
|
+
apiKey.id=#{test_api_key_id}
|
18
|
+
apiKey.secret=#{test_api_key_secret}
|
19
|
+
properties
|
20
|
+
end
|
21
|
+
|
15
22
|
context 'given a hash' do
|
16
23
|
context 'with an api key file location', 'that points to a remote file' do
|
17
24
|
let(:api_key_file_location) { 'http://fake.server.com/apiKey.properties' }
|
18
25
|
let(:client) { Stormpath::Client.new(api_key_file_location: api_key_file_location) }
|
19
26
|
|
20
27
|
before do
|
21
|
-
stub_request(:any, api_key_file_location).to_return(body
|
22
|
-
apiKey.id=#{test_api_key_id}
|
23
|
-
apiKey.secret=#{test_api_key_secret}
|
24
|
-
properties
|
25
|
-
)
|
28
|
+
stub_request(:any, api_key_file_location).to_return(body: api_key_and_secret_properties)
|
26
29
|
end
|
27
30
|
|
28
31
|
it_behaves_like 'a valid client'
|
@@ -224,11 +227,7 @@ properties
|
|
224
227
|
end
|
225
228
|
|
226
229
|
before do
|
227
|
-
stub_request(:any, api_key_file_location).to_return(body
|
228
|
-
apiKey.id=#{test_api_key_id}
|
229
|
-
apiKey.secret=#{test_api_key_secret}
|
230
|
-
properties
|
231
|
-
)
|
230
|
+
stub_request(:any, api_key_file_location).to_return(body: api_key_and_secret_properties)
|
232
231
|
data_store = client.instance_variable_get '@data_store'
|
233
232
|
cache_manager = data_store.cache_manager
|
234
233
|
@directories_cache = cache_manager.get_cache 'directories'
|
@@ -397,13 +396,11 @@ properties
|
|
397
396
|
expect(groups_cache_summary).to eq [2, 1, 0, 0, 2]
|
398
397
|
end
|
399
398
|
end
|
400
|
-
|
401
399
|
end
|
402
400
|
|
403
401
|
context 'search' do
|
404
|
-
|
405
402
|
let(:first_application_name) { random_application_name(1) }
|
406
|
-
let(:second_application_name
|
403
|
+
let(:second_application_name) { random_application_name(2) }
|
407
404
|
|
408
405
|
let!(:applications) do
|
409
406
|
[
|
@@ -628,6 +625,104 @@ properties
|
|
628
625
|
end
|
629
626
|
end
|
630
627
|
|
628
|
+
describe '#organization' do
|
629
|
+
context 'search' do
|
630
|
+
let(:organization_name) { random_organization_name }
|
631
|
+
|
632
|
+
let!(:organization) do
|
633
|
+
test_api_client.organizations.create(
|
634
|
+
name: organization_name,
|
635
|
+
name_key: "testorganization"
|
636
|
+
)
|
637
|
+
end
|
638
|
+
|
639
|
+
context 'by any attribute' do
|
640
|
+
let(:search_results) do
|
641
|
+
test_api_client.organizations.search(organization_name)
|
642
|
+
end
|
643
|
+
|
644
|
+
it 'returns the application' do
|
645
|
+
expect(search_results.count).to eq 1
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
context 'by an explicit attribute' do
|
650
|
+
let(:search_results) do
|
651
|
+
test_api_client.organizations.search(name: random_organization_name)
|
652
|
+
end
|
653
|
+
|
654
|
+
it 'returns the application' do
|
655
|
+
expect(search_results.count).to eq 1
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
after { organization.delete }
|
660
|
+
end
|
661
|
+
|
662
|
+
context 'given a collection' do
|
663
|
+
let(:organization) do
|
664
|
+
test_api_client.organizations.create(
|
665
|
+
name: random_organization_name,
|
666
|
+
name_key: random_name_key,
|
667
|
+
description: 'A test description'
|
668
|
+
)
|
669
|
+
end
|
670
|
+
|
671
|
+
it 'returns the collection' do
|
672
|
+
expect(test_api_client.organizations).to be_kind_of(Stormpath::Resource::Collection)
|
673
|
+
expect(test_api_client.organizations.count).to be >= 1
|
674
|
+
end
|
675
|
+
|
676
|
+
after { organization.delete }
|
677
|
+
end
|
678
|
+
|
679
|
+
context 'given a collection with a limit' do
|
680
|
+
let!(:organization_1) do
|
681
|
+
test_api_client.organizations.create name: random_organization_name(1), name_key: random_name_key(1)
|
682
|
+
end
|
683
|
+
|
684
|
+
let!(:organization_2) do
|
685
|
+
test_api_client.organizations.create name: random_organization_name(2), name_key: random_name_key(2)
|
686
|
+
end
|
687
|
+
|
688
|
+
after do
|
689
|
+
organization_1.delete
|
690
|
+
organization_2.delete
|
691
|
+
end
|
692
|
+
|
693
|
+
it 'should retrieve the number of organizations described with the limit' do
|
694
|
+
expect(test_api_client.organizations.count).to be >= 2
|
695
|
+
end
|
696
|
+
end
|
697
|
+
|
698
|
+
describe '.create' do
|
699
|
+
let(:organization_name) { random_organization_name }
|
700
|
+
|
701
|
+
let(:organization_attributes) do
|
702
|
+
{
|
703
|
+
name: organization_name,
|
704
|
+
name_key: random_name_key,
|
705
|
+
description: 'A test description'
|
706
|
+
}
|
707
|
+
end
|
708
|
+
|
709
|
+
let(:organization) do
|
710
|
+
test_api_client.organizations.create organization_attributes
|
711
|
+
end
|
712
|
+
|
713
|
+
it 'creates an organization' do
|
714
|
+
expect(organization).to be
|
715
|
+
expect(organization.name).to eq(organization_attributes[:name])
|
716
|
+
expect(organization.name_key).to eq(organization_attributes[:name_key])
|
717
|
+
expect(organization.description).to eq(organization_attributes[:description])
|
718
|
+
end
|
719
|
+
|
720
|
+
after do
|
721
|
+
organization.delete
|
722
|
+
end
|
723
|
+
end
|
724
|
+
end
|
725
|
+
|
631
726
|
describe "#organization_account_store_mappings" do
|
632
727
|
let(:organization) do
|
633
728
|
test_api_client.organizations.create name: 'test_organization',
|
@@ -0,0 +1,26 @@
|
|
1
|
+
{
|
2
|
+
"href":"https://api.stormpath.com/v1/directories/2uH3tJWHS4ZE5R7gcOzmGn",
|
3
|
+
"name":"test_directory_",
|
4
|
+
"description":"description_for_some_test_directory",
|
5
|
+
"status":"ENABLED",
|
6
|
+
"createdAt":"2016-02-05T11:48:28.970Z",
|
7
|
+
"modifiedAt":"2016-02-05T11:48:28.970Z",
|
8
|
+
"tenant":{"href":"https://api.stormpath.com/v1/tenants/3BoGKJZ6kwMlIqWCIYf8hr"},
|
9
|
+
"provider":{
|
10
|
+
"href":"https://api.stormpath.com/v1/directories/2uH3tJWHS4ZE5R7gcOzmGn/provider",
|
11
|
+
"provider_id": "saml",
|
12
|
+
"sso_login_url": "https://yourIdp.com/saml2/sso/login",
|
13
|
+
"sso_logout_url": "https://yourIdp.com/saml2/sso/logout",
|
14
|
+
"encoded_x509_signing_cert": "-----BEGIN CERTIFICATE-----\n...Certificate goes here...\n-----END CERTIFICATE-----",
|
15
|
+
"request_signature_algorithm": "RSA-SHA256"
|
16
|
+
},
|
17
|
+
"customData":{"href":"https://api.stormpath.com/v1/directories/2uH3tJWHS4ZE5R7gcOzmGn/customData"},
|
18
|
+
"passwordPolicy":{"href":"https://api.stormpath.com/v1/passwordPolicies/2uH3tJWHS4ZE5R7gcOzmGn"},
|
19
|
+
"accountCreationPolicy":{"href":"https://api.stormpath.com/v1/accountCreationPolicies/2uH3tJWHS4ZE5R7gcOzmGn"},
|
20
|
+
"accounts":{"href":"https://api.stormpath.com/v1/directories/2uH3tJWHS4ZE5R7gcOzmGn/accounts"},
|
21
|
+
"applicationMappings":{"href":"https://api.stormpath.com/v1/directories/2uH3tJWHS4ZE5R7gcOzmGn/applicationMappings"},
|
22
|
+
"applications":{"href":"https://api.stormpath.com/v1/directories/2uH3tJWHS4ZE5R7gcOzmGn/applications"},
|
23
|
+
"groups":{"href":"https://api.stormpath.com/v1/directories/2uH3tJWHS4ZE5R7gcOzmGn/groups"},
|
24
|
+
"organizations":{"href":"https://api.stormpath.com/v1/directories/2uH3tJWHS4ZE5R7gcOzmGn/organizations"},
|
25
|
+
"organizationMappings":{"href":"https://api.stormpath.com/v1/directories/2uH3tJWHS4ZE5R7gcOzmGn/organizationMappings"}
|
26
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
{
|
2
|
+
"href": "https://api.stormpath.com/v1/attributeStatementMappingRules/5Gd35dLZfFI1DB29xA6ZMe",
|
3
|
+
"createdAt": "2016-01-27T09:52:28.564Z",
|
4
|
+
"modifiedAt": "2016-02-29T12:58:50.496Z",
|
5
|
+
"items": [
|
6
|
+
{
|
7
|
+
"name": "uid4",
|
8
|
+
"name_format": "nil",
|
9
|
+
"account_attributes": ["username"]
|
10
|
+
}
|
11
|
+
]
|
12
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
{
|
2
|
+
"href": "https://api.stormpath.com/v1/directories/5GbnGg4HIqoFdlRjHndYQC/provider",
|
3
|
+
"createdAt": "2016-01-27T09:52:32.850Z",
|
4
|
+
"modifiedAt": "2016-01-27T09:52:32.850Z",
|
5
|
+
"providerId": "saml",
|
6
|
+
"ssoLoginUrl": "https://yourIdp.com/saml2/sso/login",
|
7
|
+
"ssoLogoutUrl": "https://yourIdp.com/saml2/sso/logout",
|
8
|
+
"encoded_x509_signing_cert": "-----BEGIN CERTIFICATE-----\n...Certificate goes here...\n-----END CERTIFICATE-----",
|
9
|
+
"requestSignatureAlgorithm": "RSA-SHA256",
|
10
|
+
"attributeStatementMappingRules": {
|
11
|
+
"href": "https://api.stormpath.com/v1/attributeStatementMappingRules/5Gd35dLZfFI1DB29xA6ZMe"
|
12
|
+
},
|
13
|
+
"serviceProviderMetadata": {
|
14
|
+
"href": "https://api.stormpath.com/v1/samlServiceProviderMetadatas/5LRVP0EMfrpHYijuqgCUAq"
|
15
|
+
}
|
16
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
{
|
2
|
+
"href": "https://api.stormpath.com/v1/samlServiceProviderMetadatas/5LRVP0EMfrpHYijuqgCUAq",
|
3
|
+
"createdAt": "2016-01-27T09:52:32.844Z",
|
4
|
+
"modifiedAt": "2016-01-27T09:52:32.844Z",
|
5
|
+
"entityId": "urn:stormpath:directory:5GbnGg4HIqoFdlRjHndYQC:provider:sp",
|
6
|
+
"assertionConsumerServicePostEndpoint": {
|
7
|
+
"href": "https://api.stormpath.com/v1/directories/5GbnGg4HIqoFdlRjHndYQC/saml/sso/post"
|
8
|
+
},
|
9
|
+
"x509SigningCert": {
|
10
|
+
"href": "https://api.stormpath.com/v1/x509certificates/5LR5SeoE66qXOAfB1lRqYK"
|
11
|
+
}
|
12
|
+
}
|
@@ -99,6 +99,18 @@ describe Stormpath::Resource::Application, :vcr do
|
|
99
99
|
|
100
100
|
end
|
101
101
|
|
102
|
+
describe 'edit authorized_callback_uris' do
|
103
|
+
let(:authorized_callback_uris) { ["https://myapplication.com/whatever/callback", "https://myapplication.com/whatever/callback2"] }
|
104
|
+
|
105
|
+
it 'changes authorized callback uris on application' do
|
106
|
+
application.authorized_callback_uris = authorized_callback_uris
|
107
|
+
response = application.save
|
108
|
+
|
109
|
+
expect(response).to eq application
|
110
|
+
#expect(application.authorized_callback_uris).to eq(authorized_callback_uris)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
102
114
|
|
103
115
|
describe '#create_account' do
|
104
116
|
let(:account) do
|
@@ -122,7 +134,7 @@ describe Stormpath::Resource::Application, :vcr do
|
|
122
134
|
|
123
135
|
context 'without registration workflow' do
|
124
136
|
it 'creates an account with workflow disabled' do
|
125
|
-
response = application.create_account account
|
137
|
+
response = application.create_account account
|
126
138
|
|
127
139
|
expect(response).to be_kind_of Stormpath::Resource::Account
|
128
140
|
expect(response.email).to eq(account.email)
|
@@ -243,14 +255,12 @@ describe Stormpath::Resource::Application, :vcr do
|
|
243
255
|
|
244
256
|
describe '#send_password_reset_email' do
|
245
257
|
context 'given an email' do
|
246
|
-
context 'of an
|
258
|
+
context 'of an existing account on the application' do
|
247
259
|
let(:account) { directory.accounts.create build_account }
|
248
260
|
|
249
261
|
let(:sent_to_account) { application.send_password_reset_email account.email }
|
250
262
|
|
251
|
-
after
|
252
|
-
account.delete if account
|
253
|
-
end
|
263
|
+
after { account.delete if account }
|
254
264
|
|
255
265
|
it 'sends a password reset request of the account' do
|
256
266
|
expect(sent_to_account).to be
|
@@ -259,6 +269,27 @@ describe Stormpath::Resource::Application, :vcr do
|
|
259
269
|
end
|
260
270
|
end
|
261
271
|
|
272
|
+
context 'of an existing account not mapped to the application' do
|
273
|
+
let(:account) { other_directory.accounts.create build_account }
|
274
|
+
|
275
|
+
let(:other_directory) do
|
276
|
+
test_api_client.directories.create(
|
277
|
+
name: random_directory_name('password_reset_account_store_href')
|
278
|
+
)
|
279
|
+
end
|
280
|
+
|
281
|
+
after do
|
282
|
+
account.delete
|
283
|
+
other_directory.delete
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'sends a password reset request of the account' do
|
287
|
+
expect do
|
288
|
+
application.send_password_reset_email account.email
|
289
|
+
end.to raise_error Stormpath::Error
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
262
293
|
context 'of a non exisitng account' do
|
263
294
|
it 'raises an exception' do
|
264
295
|
expect do
|
@@ -266,6 +297,224 @@ describe Stormpath::Resource::Application, :vcr do
|
|
266
297
|
end.to raise_error Stormpath::Error
|
267
298
|
end
|
268
299
|
end
|
300
|
+
|
301
|
+
context 'of an existing account on the application with an account store href' do
|
302
|
+
let(:account) { directory.accounts.create build_account }
|
303
|
+
|
304
|
+
let(:sent_to_account) do
|
305
|
+
application.send_password_reset_email(account.email, account_store: { href: directory.href })
|
306
|
+
end
|
307
|
+
|
308
|
+
after { account.delete if account }
|
309
|
+
|
310
|
+
it 'sends a password reset request of the account' do
|
311
|
+
expect(sent_to_account).to be
|
312
|
+
expect(sent_to_account).to be_kind_of Stormpath::Resource::Account
|
313
|
+
expect(sent_to_account.email).to eq(account.email)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
context 'of an existing account on the application with an account store resource object' do
|
318
|
+
let(:account) { directory.accounts.create build_account }
|
319
|
+
|
320
|
+
let(:sent_to_account) do
|
321
|
+
application.send_password_reset_email(account.email, account_store: directory)
|
322
|
+
end
|
323
|
+
|
324
|
+
after { account.delete if account }
|
325
|
+
|
326
|
+
it 'sends a password reset request of the account' do
|
327
|
+
expect(sent_to_account).to be
|
328
|
+
expect(sent_to_account).to be_kind_of Stormpath::Resource::Account
|
329
|
+
expect(sent_to_account.email).to eq(account.email)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
context 'of an existing account not mapped to the application with an account store href' do
|
334
|
+
let(:account) { directory.accounts.create build_account }
|
335
|
+
|
336
|
+
let(:other_directory) do
|
337
|
+
test_api_client.directories.create(
|
338
|
+
name: random_directory_name('password_reset_account_store_href'),
|
339
|
+
description: 'abc'
|
340
|
+
)
|
341
|
+
end
|
342
|
+
|
343
|
+
after do
|
344
|
+
account.delete
|
345
|
+
other_directory.delete
|
346
|
+
end
|
347
|
+
|
348
|
+
it 'sends a password reset request of the account' do
|
349
|
+
expect do
|
350
|
+
application.send_password_reset_email(account.email, account_store: { href: other_directory.href })
|
351
|
+
end.to raise_error Stormpath::Error
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
context 'of an existing account on the application with a non existant account store organization namekey' do
|
356
|
+
let(:account) { directory.accounts.create build_account }
|
357
|
+
|
358
|
+
after do
|
359
|
+
account.delete
|
360
|
+
end
|
361
|
+
|
362
|
+
it 'sends a password reset request of the account' do
|
363
|
+
expect do
|
364
|
+
application.send_password_reset_email(account.email, account_store: { name_key: "NoKey" })
|
365
|
+
end.to raise_error Stormpath::Error
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
context 'of an existing account on the application with a right account store organization namekey' do
|
370
|
+
let(:account) { account_directory.accounts.create build_account }
|
371
|
+
|
372
|
+
let(:account_directory) do
|
373
|
+
test_api_client.directories.create(
|
374
|
+
name: random_directory_name('password_reset_account_store_href')
|
375
|
+
)
|
376
|
+
end
|
377
|
+
|
378
|
+
let(:reloaded_account_directory) do
|
379
|
+
test_api_client.directories.get(account_directory.href)
|
380
|
+
end
|
381
|
+
|
382
|
+
let(:organization_name_key) { "#{random_string}-org-name-key" }
|
383
|
+
|
384
|
+
let(:organization) do
|
385
|
+
test_api_client.organizations.create(
|
386
|
+
name: "#{random_string}_organization_name",
|
387
|
+
name_key: organization_name_key
|
388
|
+
)
|
389
|
+
end
|
390
|
+
|
391
|
+
let(:sent_to_account) do
|
392
|
+
application.send_password_reset_email(account.email, account_store: { name_key: organization.name_key })
|
393
|
+
end
|
394
|
+
|
395
|
+
after do
|
396
|
+
account.delete
|
397
|
+
organization.delete
|
398
|
+
reloaded_account_directory.delete
|
399
|
+
end
|
400
|
+
|
401
|
+
before do
|
402
|
+
test_api_client.organization_account_store_mappings.create(
|
403
|
+
account_store: { href: account_directory.href },
|
404
|
+
organization: { href: organization.href }
|
405
|
+
)
|
406
|
+
|
407
|
+
test_api_client.account_store_mappings.create(application: application, account_store: organization)
|
408
|
+
end
|
409
|
+
|
410
|
+
it 'sends a password reset request of the account' do
|
411
|
+
expect(sent_to_account).to be
|
412
|
+
expect(sent_to_account).to be_kind_of Stormpath::Resource::Account
|
413
|
+
expect(sent_to_account.email).to eq(account.email)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
context 'of an existing account on the application with a right account store organization resource object' do
|
418
|
+
let(:account) { account_directory.accounts.create build_account }
|
419
|
+
|
420
|
+
let(:account_directory) do
|
421
|
+
test_api_client.directories.create(
|
422
|
+
name: random_directory_name('password_reset_account_store_href')
|
423
|
+
)
|
424
|
+
end
|
425
|
+
|
426
|
+
let(:reloaded_account_directory) do
|
427
|
+
test_api_client.directories.get(account_directory.href)
|
428
|
+
end
|
429
|
+
|
430
|
+
let(:organization_name_key) { "#{random_string}-org-name-key" }
|
431
|
+
|
432
|
+
let(:organization) do
|
433
|
+
test_api_client.organizations.create(
|
434
|
+
name: "#{random_string}_organization_name",
|
435
|
+
name_key: organization_name_key
|
436
|
+
)
|
437
|
+
end
|
438
|
+
|
439
|
+
let(:sent_to_account) do
|
440
|
+
application.send_password_reset_email(account.email, account_store: organization)
|
441
|
+
end
|
442
|
+
|
443
|
+
after do
|
444
|
+
account.delete
|
445
|
+
organization.delete
|
446
|
+
reloaded_account_directory.delete
|
447
|
+
end
|
448
|
+
|
449
|
+
before do
|
450
|
+
test_api_client.organization_account_store_mappings.create(
|
451
|
+
account_store: { href: account_directory.href },
|
452
|
+
organization: { href: organization.href }
|
453
|
+
)
|
454
|
+
|
455
|
+
test_api_client.account_store_mappings.create(application: application, account_store: organization)
|
456
|
+
end
|
457
|
+
|
458
|
+
it 'sends a password reset request of the account' do
|
459
|
+
expect(sent_to_account).to be
|
460
|
+
expect(sent_to_account).to be_kind_of Stormpath::Resource::Account
|
461
|
+
expect(sent_to_account.email).to eq(account.email)
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
context 'of an existing account on the application with a wrong account store organization namekey' do
|
466
|
+
let(:account) { account_directory.accounts.create build_account }
|
467
|
+
|
468
|
+
let(:account_directory) do
|
469
|
+
test_api_client.directories.create(
|
470
|
+
name: random_directory_name('password_reset_account_store_href')
|
471
|
+
)
|
472
|
+
end
|
473
|
+
|
474
|
+
let(:reloaded_account_directory) do
|
475
|
+
test_api_client.directories.get(account_directory.href)
|
476
|
+
end
|
477
|
+
|
478
|
+
let(:organization_name_key) { "#{random_string}-org-name-key" }
|
479
|
+
|
480
|
+
let(:other_organization_name_key) { "#{random_string}-other-org-name-key" }
|
481
|
+
|
482
|
+
let(:organization) do
|
483
|
+
test_api_client.organizations.create(
|
484
|
+
name: "#{random_string}_organization_name",
|
485
|
+
name_key: organization_name_key
|
486
|
+
)
|
487
|
+
end
|
488
|
+
|
489
|
+
let(:other_organization) do
|
490
|
+
test_api_client.organizations.create(
|
491
|
+
name: "#{random_string}_other_organization_name",
|
492
|
+
name_key: other_organization_name_key
|
493
|
+
)
|
494
|
+
end
|
495
|
+
|
496
|
+
after do
|
497
|
+
account.delete
|
498
|
+
organization.delete
|
499
|
+
other_organization.delete
|
500
|
+
reloaded_account_directory.delete
|
501
|
+
end
|
502
|
+
|
503
|
+
before do
|
504
|
+
test_api_client.organization_account_store_mappings.create(
|
505
|
+
account_store: { href: account_directory.href },
|
506
|
+
organization: { href: organization.href }
|
507
|
+
)
|
508
|
+
|
509
|
+
test_api_client.account_store_mappings.create(application: application, account_store: organization)
|
510
|
+
end
|
511
|
+
|
512
|
+
it 'sends a password reset request of the account' do
|
513
|
+
expect do
|
514
|
+
application.send_password_reset_email(account.email, account_store: { name_key: other_organization.name_key })
|
515
|
+
end.to raise_error Stormpath::Error
|
516
|
+
end
|
517
|
+
end
|
269
518
|
end
|
270
519
|
end
|
271
520
|
|
@@ -326,7 +575,7 @@ describe Stormpath::Resource::Application, :vcr do
|
|
326
575
|
end
|
327
576
|
|
328
577
|
it 'containes account data' do
|
329
|
-
expect(auth_request.account.href).to eq(account.href)
|
578
|
+
expect(auth_request.account.href).to eq(account.href)
|
330
579
|
end
|
331
580
|
end
|
332
581
|
|
@@ -338,35 +587,131 @@ describe Stormpath::Resource::Application, :vcr do
|
|
338
587
|
})
|
339
588
|
end
|
340
589
|
|
341
|
-
|
342
|
-
test_api_client.
|
343
|
-
|
590
|
+
def create_application_account_store_mapping(application, account_store)
|
591
|
+
test_api_client.account_store_mappings.create(
|
592
|
+
application: application,
|
593
|
+
account_store: account_store
|
594
|
+
)
|
344
595
|
end
|
345
596
|
|
346
|
-
let(:
|
347
|
-
|
348
|
-
|
349
|
-
"P@$$w0rd",
|
350
|
-
account_store: organization.name_key
|
351
|
-
)
|
597
|
+
let(:organization) do
|
598
|
+
test_api_client.organizations.create name: 'test_organization',
|
599
|
+
name_key: "testorganization"
|
352
600
|
end
|
353
601
|
|
354
602
|
let(:auth_request) { application.authenticate_account(username_password_request) }
|
355
603
|
|
356
604
|
before do
|
357
605
|
create_organization_account_store_mapping(organization, directory)
|
606
|
+
create_application_account_store_mapping(application, organization)
|
358
607
|
end
|
359
608
|
|
360
609
|
after do
|
361
610
|
organization.delete if organization
|
362
611
|
end
|
363
612
|
|
364
|
-
|
365
|
-
|
613
|
+
describe 'when sending the proper organization' do
|
614
|
+
describe 'using an organization name_key' do
|
615
|
+
let(:username_password_request) do
|
616
|
+
Stormpath::Authentication::UsernamePasswordRequest.new(
|
617
|
+
account.email, "P@$$w0rd",
|
618
|
+
account_store: { name_key: organization.name_key }
|
619
|
+
)
|
620
|
+
end
|
621
|
+
|
622
|
+
it 'returns login attempt response' do
|
623
|
+
expect(auth_request).to be_kind_of Stormpath::Authentication::AuthenticationResult
|
624
|
+
end
|
625
|
+
|
626
|
+
it 'containes account data' do
|
627
|
+
expect(auth_request.account.href).to eq(account.href)
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
describe 'using an organization href' do
|
632
|
+
let(:username_password_request) do
|
633
|
+
Stormpath::Authentication::UsernamePasswordRequest.new(
|
634
|
+
account.email, "P@$$w0rd",
|
635
|
+
account_store: { href: organization.href }
|
636
|
+
)
|
637
|
+
end
|
638
|
+
|
639
|
+
it 'returns login attempt response' do
|
640
|
+
expect(auth_request).to be_kind_of Stormpath::Authentication::AuthenticationResult
|
641
|
+
end
|
642
|
+
|
643
|
+
it 'containes account data' do
|
644
|
+
expect(auth_request.account.href).to eq(account.href)
|
645
|
+
end
|
646
|
+
end
|
647
|
+
|
648
|
+
describe 'using an organization object' do
|
649
|
+
let(:username_password_request) do
|
650
|
+
Stormpath::Authentication::UsernamePasswordRequest.new(
|
651
|
+
account.email, "P@$$w0rd",
|
652
|
+
account_store: organization
|
653
|
+
)
|
654
|
+
end
|
655
|
+
|
656
|
+
it 'returns login attempt response' do
|
657
|
+
expect(auth_request).to be_kind_of Stormpath::Authentication::AuthenticationResult
|
658
|
+
end
|
659
|
+
|
660
|
+
it 'containes account data' do
|
661
|
+
expect(auth_request.account.href).to eq(account.href)
|
662
|
+
end
|
663
|
+
end
|
366
664
|
end
|
367
665
|
|
368
|
-
|
369
|
-
|
666
|
+
describe 'when sending the wrong organization' do
|
667
|
+
describe 'using an organization name_key' do
|
668
|
+
let(:username_password_request) do
|
669
|
+
Stormpath::Authentication::UsernamePasswordRequest.new(
|
670
|
+
account.email, "P@$$w0rd",
|
671
|
+
account_store: { name_key: 'wrong-name-key' }
|
672
|
+
)
|
673
|
+
end
|
674
|
+
|
675
|
+
it 'raises an error' do
|
676
|
+
expect { auth_request }.to raise_error(Stormpath::Error)
|
677
|
+
end
|
678
|
+
end
|
679
|
+
|
680
|
+
describe 'using an organization href' do
|
681
|
+
let(:username_password_request) do
|
682
|
+
Stormpath::Authentication::UsernamePasswordRequest.new(
|
683
|
+
account.email, "P@$$w0rd",
|
684
|
+
account_store: { href: other_organization.href }
|
685
|
+
)
|
686
|
+
end
|
687
|
+
|
688
|
+
let(:other_organization) do
|
689
|
+
test_api_client.organizations.create name: 'other_organization',
|
690
|
+
name_key: "other-organization"
|
691
|
+
end
|
692
|
+
|
693
|
+
it 'raises an error' do
|
694
|
+
expect { auth_request }.to raise_error(Stormpath::Error)
|
695
|
+
end
|
696
|
+
end
|
697
|
+
|
698
|
+
describe 'using an organization object' do
|
699
|
+
let(:username_password_request) do
|
700
|
+
Stormpath::Authentication::UsernamePasswordRequest.new(
|
701
|
+
account.email, "P@$$w0rd",
|
702
|
+
account_store: other_organization
|
703
|
+
)
|
704
|
+
end
|
705
|
+
|
706
|
+
let(:other_organization) do
|
707
|
+
test_api_client.organizations.create name: 'other_organization',
|
708
|
+
name_key: "other-organization"
|
709
|
+
end
|
710
|
+
|
711
|
+
it 'raises an error' do
|
712
|
+
expect { auth_request }.to raise_error(Stormpath::Error)
|
713
|
+
end
|
714
|
+
end
|
370
715
|
end
|
371
716
|
end
|
372
717
|
|
@@ -381,10 +726,10 @@ describe Stormpath::Resource::Application, :vcr do
|
|
381
726
|
let(:auth_request) { application.authenticate_account(username_password_request) }
|
382
727
|
|
383
728
|
it 'returns stormpath error' do
|
384
|
-
expect {
|
385
|
-
auth_request
|
729
|
+
expect {
|
730
|
+
auth_request
|
386
731
|
}.to raise_error(Stormpath::Error)
|
387
|
-
end
|
732
|
+
end
|
388
733
|
end
|
389
734
|
end
|
390
735
|
|
@@ -506,7 +851,7 @@ describe Stormpath::Resource::Application, :vcr do
|
|
506
851
|
expect(error.message).to eq("The specified callback URI (cb_uri) is not valid")
|
507
852
|
expect(error.developer_message).to eq("The specified callback URI (cb_uri) is not valid. Make sure the "\
|
508
853
|
"callback URI specified in your ID Site configuration matches the value specified.")
|
509
|
-
end
|
854
|
+
end
|
510
855
|
end
|
511
856
|
end
|
512
857
|
end
|
@@ -632,7 +977,7 @@ describe Stormpath::Resource::Application, :vcr do
|
|
632
977
|
}, test_api_key_secret, 'HS256')
|
633
978
|
}
|
634
979
|
|
635
|
-
it 'should error with the stormpath error' do
|
980
|
+
it 'should error with the stormpath error' do
|
636
981
|
expect {
|
637
982
|
application.handle_id_site_callback(callback_uri_base + jwt_token)
|
638
983
|
}.to raise_error(Stormpath::Error)
|
@@ -676,7 +1021,7 @@ describe Stormpath::Resource::Application, :vcr do
|
|
676
1021
|
before do
|
677
1022
|
@site_result = application.handle_id_site_callback(callback_uri_base + jwt_token)
|
678
1023
|
end
|
679
|
-
|
1024
|
+
|
680
1025
|
it 'should return IdSiteResult object' do
|
681
1026
|
expect(@site_result).to be_kind_of(Stormpath::IdSite::IdSiteResult)
|
682
1027
|
end
|
@@ -691,7 +1036,7 @@ describe Stormpath::Resource::Application, :vcr do
|
|
691
1036
|
before do
|
692
1037
|
application.accounts.create account_data
|
693
1038
|
end
|
694
|
-
|
1039
|
+
|
695
1040
|
context 'generate access token' do
|
696
1041
|
let(:password_grant_request) { Stormpath::Oauth::PasswordGrantRequest.new account_data[:email], account_data[:password] }
|
697
1042
|
let(:authenticate_oauth) { application.authenticate_oauth(password_grant_request) }
|
@@ -741,7 +1086,7 @@ describe Stormpath::Resource::Application, :vcr do
|
|
741
1086
|
.and_return(Stormpath::Oauth::IdSiteGrant.new({}, application.client))
|
742
1087
|
|
743
1088
|
grant_request = Stormpath::Oauth::IdSiteGrantRequest.new jwt_token
|
744
|
-
response = application.authenticate_oauth(grant_request)
|
1089
|
+
response = application.authenticate_oauth(grant_request)
|
745
1090
|
|
746
1091
|
expect(response).to be(Stormpath::Resource::AccessToken)
|
747
1092
|
end
|
@@ -777,12 +1122,12 @@ describe Stormpath::Resource::Application, :vcr do
|
|
777
1122
|
end
|
778
1123
|
|
779
1124
|
it 'returens success on valid token' do
|
780
|
-
expect(authenticate_oauth.href).not_to be_empty
|
781
|
-
expect(authenticate_oauth.account).not_to be_empty
|
782
|
-
expect(authenticate_oauth.application).not_to be_empty
|
783
|
-
expect(authenticate_oauth.jwt).not_to be_empty
|
784
|
-
expect(authenticate_oauth.tenant).not_to be_empty
|
785
|
-
expect(authenticate_oauth.expanded_jwt).not_to be_empty
|
1125
|
+
expect(authenticate_oauth.href).not_to be_empty
|
1126
|
+
expect(authenticate_oauth.account).not_to be_empty
|
1127
|
+
expect(authenticate_oauth.application).not_to be_empty
|
1128
|
+
expect(authenticate_oauth.jwt).not_to be_empty
|
1129
|
+
expect(authenticate_oauth.tenant).not_to be_empty
|
1130
|
+
expect(authenticate_oauth.expanded_jwt).not_to be_empty
|
786
1131
|
end
|
787
1132
|
end
|
788
1133
|
|