stormpath-sdk 1.0.1 → 1.1.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.
@@ -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 email
95
- password_reset_token = create_password_reset_token email;
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 email
139
- password_reset_tokens.create email: email
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
+
@@ -14,6 +14,6 @@
14
14
  # limitations under the License.
15
15
  #
16
16
  module Stormpath
17
- VERSION = '1.0.1'
18
- VERSION_DATE = '2016-02-16'
17
+ VERSION = '1.1.0'
18
+ VERSION_DATE = '2016-05-11'
19
19
  end
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:<<properties
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:<<properties
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 ) { random_application_name(2) }
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 exisiting account on the application' do
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 do
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
- let(:organization) do
342
- test_api_client.organizations.create name: 'test_organization',
343
- name_key: "testorganization"
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(:username_password_request) do
347
- Stormpath::Authentication::UsernamePasswordRequest.new(
348
- account.email,
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
- it 'returns login attempt response' do
365
- expect(auth_request).to be_kind_of Stormpath::Authentication::AuthenticationResult
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
- it 'containes account data' do
369
- expect(auth_request.account.href).to eq(account.href)
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