stormpath-sdk 1.0.0.beta.4 → 1.0.0.beta.5

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.
Files changed (37) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGES.md +15 -0
  3. data/README.md +35 -3
  4. data/lib/stormpath-sdk.rb +5 -6
  5. data/lib/stormpath-sdk/auth/basic_authenticator.rb +2 -0
  6. data/lib/stormpath-sdk/auth/basic_login_attempt.rb +11 -0
  7. data/lib/stormpath-sdk/auth/username_password_request.rb +6 -12
  8. data/lib/stormpath-sdk/data_store.rb +118 -127
  9. data/lib/stormpath-sdk/http/http_client_request_executor.rb +10 -42
  10. data/lib/stormpath-sdk/resource/account.rb +13 -3
  11. data/lib/stormpath-sdk/resource/account_membership.rb +16 -0
  12. data/lib/stormpath-sdk/resource/account_status.rb +26 -0
  13. data/lib/stormpath-sdk/resource/account_store_mapping.rb +4 -2
  14. data/lib/stormpath-sdk/resource/application.rb +4 -2
  15. data/lib/stormpath-sdk/resource/associations.rb +7 -3
  16. data/lib/stormpath-sdk/resource/base.rb +21 -15
  17. data/lib/stormpath-sdk/resource/custom_data.rb +86 -0
  18. data/lib/stormpath-sdk/resource/custom_data_hash_methods.rb +33 -0
  19. data/lib/stormpath-sdk/resource/custom_data_storage.rb +39 -0
  20. data/lib/stormpath-sdk/resource/directory.rb +4 -4
  21. data/lib/stormpath-sdk/resource/expansion.rb +15 -0
  22. data/lib/stormpath-sdk/resource/group.rb +10 -0
  23. data/lib/stormpath-sdk/resource/status.rb +16 -5
  24. data/lib/stormpath-sdk/version.rb +2 -2
  25. data/spec/client_spec.rb +6 -1
  26. data/spec/data_store_spec.rb +7 -2
  27. data/spec/resource/account_spec.rb +73 -30
  28. data/spec/resource/account_store_mapping_spec.rb +20 -5
  29. data/spec/resource/application_spec.rb +135 -0
  30. data/spec/resource/custom_data_spec.rb +198 -0
  31. data/spec/resource/directory_spec.rb +192 -9
  32. data/spec/resource/group_membership_spec.rb +35 -0
  33. data/spec/resource/group_spec.rb +44 -26
  34. data/spec/resource/status_spec.rb +81 -0
  35. data/spec/resource/tenant_spec.rb +19 -0
  36. data/stormpath-sdk.gemspec +2 -2
  37. metadata +13 -3
@@ -0,0 +1,39 @@
1
+ #
2
+ # Copyright 2014 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
+ module Stormpath::Resource::CustomDataStorage
17
+ extend ActiveSupport::Concern
18
+
19
+ CUSTOM_DATA = "custom_data"
20
+
21
+ included do
22
+
23
+ def save
24
+ apply_custom_data_updates_if_necessary
25
+ super
26
+ end
27
+
28
+ def apply_custom_data_updates_if_necessary
29
+ if custom_data.send :has_removed_properties?
30
+ custom_data.send :delete_removed_properties
31
+ end
32
+ if custom_data.send :has_new_properties?
33
+ self.set_property CUSTOM_DATA, custom_data.properties
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -20,15 +20,15 @@ class Stormpath::Resource::Directory < Stormpath::Resource::Instance
20
20
 
21
21
  belongs_to :tenant
22
22
 
23
- has_many :accounts, can: :create
24
- has_many :groups, can: :create
23
+ has_many :accounts, can: [:get, :create]
24
+ has_many :groups, can: [:get, :create]
25
25
 
26
26
  def create_account account, registration_workflow_enabled=nil
27
27
  href = accounts.href
28
- unless registration_workflow_enabled.nil?
28
+ if registration_workflow_enabled == false
29
29
  href += "?registrationWorkflowEnabled=#{registration_workflow_enabled.to_s}"
30
30
  end
31
-
31
+ account.apply_custom_data_updates_if_necessary
32
32
  data_store.create href, account, Stormpath::Resource::Account
33
33
  end
34
34
  end
@@ -1,3 +1,18 @@
1
+ #
2
+ # Copyright 2013 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
+ #
1
16
  class Stormpath::Resource::Expansion
2
17
  attr_reader :query
3
18
 
@@ -15,6 +15,7 @@
15
15
  #
16
16
  class Stormpath::Resource::Group < Stormpath::Resource::Instance
17
17
  include Stormpath::Resource::Status
18
+ include Stormpath::Resource::CustomDataStorage
18
19
 
19
20
  prop_accessor :name, :description
20
21
 
@@ -22,8 +23,17 @@ class Stormpath::Resource::Group < Stormpath::Resource::Instance
22
23
  belongs_to :directory
23
24
 
24
25
  has_many :accounts
26
+ has_many :account_memberships
27
+
28
+ has_one :custom_data
25
29
 
26
30
  def add_account account
27
31
  client.group_memberships.create group: self, account: account
28
32
  end
33
+
34
+ def remove_account account
35
+ account_membership = account_memberships.find {|account_membership| account_membership.account.href == account.href }
36
+ account_membership.delete if account_membership
37
+ end
38
+
29
39
  end
@@ -1,3 +1,18 @@
1
+ #
2
+ # Copyright 2013 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
+ #
1
16
  module Stormpath::Resource::Status
2
17
 
3
18
  ENABLED = 'ENABLED'
@@ -11,11 +26,7 @@ module Stormpath::Resource::Status
11
26
 
12
27
  def status
13
28
  value = get_property STATUS
14
-
15
- if !value.nil?
16
- value = value.upcase
17
- end
18
-
29
+ value.upcase! if value
19
30
  value
20
31
  end
21
32
 
@@ -14,6 +14,6 @@
14
14
  # limitations under the License.
15
15
  #
16
16
  module Stormpath
17
- VERSION = '1.0.0.beta.4'
18
- VERSION_DATE = '2013-12-10'
17
+ VERSION = '1.0.0.beta.5'
18
+ VERSION_DATE = '2014-03-03'
19
19
  end
data/spec/client_spec.rb CHANGED
@@ -172,7 +172,12 @@ properties
172
172
  end
173
173
 
174
174
  context 'with a base url' do
175
- it 'creates a client that connects to that base'
175
+ context 'creates a client that connects to that base' do
176
+ let(:api_key) { Stormpath::ApiKey.new(test_api_key_id, test_api_key_secret) }
177
+ let(:client) { Stormpath::Client.new(api_key: api_key, base_url: "https://api.stormpath.com/v1") }
178
+
179
+ it_behaves_like 'a valid client'
180
+ end
176
181
  end
177
182
 
178
183
  context 'with an api key' do
@@ -11,13 +11,18 @@ describe Stormpath::DataStore do
11
11
 
12
12
  after do
13
13
  application_cache.clear
14
- end
14
+ end
15
15
 
16
16
  describe '.region_for' do
17
- let(:region) { data_store.send(:region_for, 'https://api.stormpath.com/v1/directories/4NykYrYH0OBiOOVOg8LXQ5') }
18
17
  it 'pulls resource name from href' do
18
+ region = data_store.send :region_for, 'https://api.stormpath.com/v1/directories/4NykYrYH0OBiOOVOg8LXQ5'
19
19
  expect(region).to eq('directories')
20
20
  end
21
+
22
+ it 'pulls resource name from href if its custom data also' do
23
+ region = data_store.send :region_for, 'https://api.stormpath.com/v1/accounts/7jWpcEVSgawKkAZp8XDIEw/customData'
24
+ expect(region).to eq('customData')
25
+ end
21
26
  end
22
27
 
23
28
  describe '#delete' do
@@ -1,20 +1,43 @@
1
1
  require 'spec_helper'
2
+ require 'pry-debugger'
2
3
 
3
4
  describe Stormpath::Resource::Account, :vcr do
5
+
4
6
  describe "instances" do
5
7
  let(:directory) { test_api_client.directories.create name: 'testDirectory' }
8
+
9
+ let(:given_name) { 'Ruby SDK' }
10
+ let(:middle_name) { 'Gruby' }
11
+ let(:surname) { 'SDK' }
12
+
6
13
  subject(:account) do
7
14
  directory.accounts.create email: 'test@example.com',
8
- givenName: 'Ruby SDK',
15
+ given_name: given_name,
9
16
  password: 'P@$$w0rd',
10
- surname: 'SDK',
17
+ middle_name: middle_name,
18
+ surname: surname,
11
19
  username: 'rubysdk'
12
20
  end
13
21
 
14
- it { should respond_to :given_name }
15
- it { should respond_to :username }
16
- it { should respond_to :surname }
17
- it { should respond_to :full_name }
22
+ [:given_name, :username, :middle_name, :surname, :email, :status].each do |property_accessor|
23
+ it { should respond_to property_accessor }
24
+ it { should respond_to "#{property_accessor}=" }
25
+ its(property_accessor) { should be_instance_of String }
26
+ end
27
+
28
+ it {should respond_to :full_name}
29
+ its(:full_name) { should be_instance_of String}
30
+ its(:full_name) { should eq("#{given_name} #{middle_name} #{surname}")}
31
+
32
+ it {should respond_to "password="}
33
+
34
+ its(:tenant) { should be_instance_of Stormpath::Resource::Tenant }
35
+ its(:directory) { should be_instance_of Stormpath::Resource::Directory }
36
+ its(:custom_data) { should be_instance_of Stormpath::Resource::CustomData }
37
+ its(:email_verification_token) { should be_instance_of Stormpath::Resource::EmailVerificationToken }
38
+
39
+ its(:groups) { should be_instance_of Stormpath::Resource::Collection }
40
+ its(:group_memberships) { should be_instance_of Stormpath::Resource::Collection }
18
41
 
19
42
  after do
20
43
  account.delete if account
@@ -23,31 +46,41 @@ describe Stormpath::Resource::Account, :vcr do
23
46
 
24
47
  end
25
48
 
26
- describe "#add_group" do
27
- context "given a group" do
28
- let(:directory) do
29
- test_api_client.directories.create name: 'testDirectory'
30
- end
31
-
32
- let(:group) do
33
- directory.groups.create name: 'testGroup'
34
- end
35
-
36
- let(:account) do
37
- directory.accounts.create email: 'test@example.com',
49
+ describe 'account_associations' do
50
+ let(:directory) { test_api_client.directories.create name: 'testDirectory' }
51
+
52
+ let(:account) do
53
+ directory.accounts.create email: 'test@example.com',
38
54
  givenName: 'Ruby SDK',
39
55
  password: 'P@$$w0rd',
40
56
  surname: 'SDK',
41
57
  username: 'rubysdk'
42
- end
58
+ end
43
59
 
44
- let(:reloaded_account) do
45
- test_api_client.accounts.get account.href
46
- end
60
+ it 'should belong_to directory' do
61
+ expect(account.directory).to eq(directory)
62
+ end
47
63
 
48
- before do
49
- account.add_group group
50
- end
64
+ it 'should belong_to tenant' do
65
+ expect(account.tenant).to be
66
+ expect(account.tenant).to eq(account.directory.tenant)
67
+ end
68
+
69
+ after do
70
+ account.delete if account
71
+ directory.delete if directory
72
+ end
73
+ end
74
+
75
+ describe "#add_or_remove_group" do
76
+ context "given a group" do
77
+ let(:directory) { test_api_client.directories.create name: 'testDirectory' }
78
+
79
+ let(:group) { directory.groups.create name: 'testGroup' }
80
+
81
+ let(:account) { directory.accounts.create({ email: 'rubysdk@example.com', given_name: 'Ruby SDK', password: 'P@$$w0rd', surname: 'SDK' }) }
82
+
83
+ before { account.add_group group }
51
84
 
52
85
  after do
53
86
  account.delete if account
@@ -56,12 +89,21 @@ describe Stormpath::Resource::Account, :vcr do
56
89
  end
57
90
 
58
91
  it 'adds the group to the account' do
59
- group_added = false
60
- reloaded_account.groups.each do |g|
61
- group_added = true if g.href == group.href
62
- end
63
- expect(group_added).to be_true
92
+ expect(account.groups).to include(group)
93
+ end
94
+
95
+ it 'has one group membership resource' do
96
+ expect(account.group_memberships).to have(1).item
97
+ end
98
+
99
+ it 'adds and removes the group from the account' do
100
+ expect(account.groups).to include(group)
101
+
102
+ account.remove_group group
103
+
104
+ expect(account.groups).not_to include(group)
64
105
  end
106
+
65
107
  end
66
108
  end
67
109
 
@@ -93,4 +135,5 @@ describe Stormpath::Resource::Account, :vcr do
93
135
  end
94
136
  end
95
137
  end
138
+
96
139
  end
@@ -24,11 +24,26 @@ describe Stormpath::Resource::AccountStoreMapping, :vcr do
24
24
  describe "instances" do
25
25
  subject(:account_store_mapping) {create_account_store_mapping(application,directory)}
26
26
 
27
- it { should respond_to(:account_store) }
28
- it { should respond_to(:list_index) }
29
- it { should respond_to(:is_default_group_store) }
30
- it { should respond_to(:is_default_account_store) }
31
- it { should respond_to(:application) }
27
+ [:list_index, :is_default_account_store, :is_default_group_store, :default_account_store, :default_group_store ].each do |prop_accessor|
28
+ it { should respond_to prop_accessor }
29
+ it { should respond_to "#{prop_accessor}=" }
30
+ end
31
+
32
+ [:default_account_store?, :default_group_store?].each do |prop_getter|
33
+ it { should respond_to prop_getter }
34
+ end
35
+
36
+ its(:list_index) { should be_instance_of Fixnum }
37
+
38
+ [:default_account_store, :default_group_store].each do |default_store_method|
39
+ [default_store_method, "is_#{default_store_method}", "#{default_store_method}?"].each do |specific_store_method|
40
+ its(specific_store_method) {should satisfy {|attribute| [TrueClass, FalseClass].include? attribute.class }}
41
+ end
42
+ end
43
+
44
+ its(:account_store) { should satisfy {|prop_reader| [Stormpath::Resource::Directory, Stormpath::Resource::Group].include? prop_reader.class }}
45
+
46
+ its(:application) { should be_instance_of Stormpath::Resource::Application }
32
47
  end
33
48
 
34
49
 
@@ -4,6 +4,29 @@ describe Stormpath::Resource::Application, :vcr do
4
4
  let(:application) { test_application }
5
5
  let(:directory) { test_directory }
6
6
 
7
+ describe "instances should respond to attribute property methods" do
8
+ subject(:application) { test_application }
9
+
10
+ it { should be_instance_of Stormpath::Resource::Application }
11
+
12
+ [:name, :description, :status].each do |property_accessor|
13
+ it { should respond_to property_accessor }
14
+ it { should respond_to "#{property_accessor}="}
15
+ its(property_accessor) { should be_instance_of String }
16
+ end
17
+
18
+ its(:tenant) { should be_instance_of Stormpath::Resource::Tenant }
19
+ its(:default_account_store_mapping) { should be_instance_of Stormpath::Resource::AccountStoreMapping }
20
+ its(:default_group_store_mapping) { should be_instance_of Stormpath::Resource::AccountStoreMapping }
21
+
22
+ its(:groups) { should be_instance_of Stormpath::Resource::Collection }
23
+ its(:accounts) { should be_instance_of Stormpath::Resource::Collection }
24
+ its(:password_reset_tokens) { should be_instance_of Stormpath::Resource::Collection }
25
+ its(:account_store_mappings) { should be_instance_of Stormpath::Resource::Collection }
26
+
27
+
28
+ end
29
+
7
30
  describe '.load' do
8
31
  let(:url) do
9
32
  uri = URI(application.href)
@@ -26,6 +49,44 @@ describe Stormpath::Resource::Application, :vcr do
26
49
  end
27
50
  end
28
51
 
52
+ describe 'application_associations' do
53
+
54
+ context '#accounts' do
55
+ let(:account) { application.accounts.create build_account}
56
+
57
+ after do
58
+ account.delete if account
59
+ end
60
+
61
+ it 'should be able to create an account' do
62
+ expect(application.accounts).to include(account)
63
+ expect(application.default_account_store_mapping.account_store.accounts).to include(account)
64
+ end
65
+
66
+ it 'should be able to create and fetch the account' do
67
+ expect(application.accounts.get account.href).to be
68
+ end
69
+ end
70
+
71
+ context '#groups' do
72
+ let(:group) { application.groups.create name: "test_group"}
73
+
74
+ after do
75
+ group.delete if group
76
+ end
77
+
78
+ it 'should be able to create a group' do
79
+ expect(application.groups).to include(group)
80
+ expect(application.default_group_store_mapping.account_store.groups).to include(group)
81
+ end
82
+
83
+ it 'should be able to create and fetch a group' do
84
+ expect(application.groups.get group.href).to be
85
+ end
86
+ end
87
+
88
+ end
89
+
29
90
  describe '#authenticate_account' do
30
91
  let(:account) do
31
92
  directory.accounts.create build_account(password: 'P@$$w0rd')
@@ -63,6 +124,80 @@ describe Stormpath::Resource::Application, :vcr do
63
124
  end
64
125
  end
65
126
 
127
+ describe '#authenticate_account_with_an_account_store_specified' do
128
+ let(:password) {'P@$$w0rd' }
129
+
130
+ let(:authentication_result) { application.authenticate_account login_request }
131
+
132
+ after do
133
+ account.delete if account
134
+ end
135
+
136
+ context 'given a proper directory' do
137
+ let(:account) { directory.accounts.create build_account(password: 'P@$$w0rd') }
138
+
139
+ let(:login_request) do
140
+ Stormpath::Authentication::UsernamePasswordRequest.new account.username, password, account_store: directory
141
+ end
142
+
143
+ it 'should return an authentication result' do
144
+ expect(authentication_result).to be
145
+ expect(authentication_result.account).to be
146
+ expect(authentication_result.account).to be_kind_of Stormpath::Resource::Account
147
+ expect(authentication_result.account.email).to eq(account.email)
148
+ end
149
+ end
150
+
151
+ context 'given a wrong directory' do
152
+ let(:new_directory) { test_api_client.directories.create name: 'test_account_store'}
153
+
154
+ let(:account) { new_directory.accounts.create build_account(password: 'P@$$w0rd') }
155
+
156
+ let(:login_request) do
157
+ Stormpath::Authentication::UsernamePasswordRequest.new account.username, password, account_store: directory
158
+ end
159
+
160
+ after do
161
+ new_directory.delete if new_directory
162
+ end
163
+
164
+ it 'raises an error' do
165
+ expect { authentication_result }.to raise_error Stormpath::Error
166
+ end
167
+ end
168
+
169
+ context 'given a group' do
170
+ let(:group) {directory.groups.create name: "test_group"}
171
+
172
+ let(:account) { directory.accounts.create build_account(password: 'P@$$w0rd') }
173
+
174
+ let(:login_request) do
175
+ Stormpath::Authentication::UsernamePasswordRequest.new account.username, password, account_store: group
176
+ end
177
+
178
+ before do
179
+ test_api_client.account_store_mappings.create({ application: application, account_store: group })
180
+ end
181
+
182
+ after do
183
+ group.delete if group
184
+ end
185
+
186
+ it 'and assigning the account to it, should return a authentication result' do
187
+ group.add_account account
188
+ expect(authentication_result).to be
189
+ expect(authentication_result.account).to be
190
+ expect(authentication_result.account).to be_kind_of Stormpath::Resource::Account
191
+ expect(authentication_result.account.email).to eq(account.email)
192
+ end
193
+
194
+ it 'but not assigning the account to, it should raise an error' do
195
+ expect { authentication_result }.to raise_error Stormpath::Error
196
+ end
197
+ end
198
+
199
+ end
200
+
66
201
  describe '#send_password_reset_email' do
67
202
  context 'given an email' do
68
203
  context 'of an exisiting account on the application' do