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

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