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.
@@ -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