stormpath-sdk 1.4.0 → 1.5.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.
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright 2014 Stormpath, Inc.
2
+ # Copyright 2016 Stormpath, Inc.
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -16,15 +16,14 @@
16
16
  module Stormpath
17
17
  module Provider
18
18
  class AccountRequest
19
+ attr_accessor :provider, :token_type, :token_value, :account_store
19
20
 
20
- attr_accessor :provider, :token_type, :token_value
21
-
22
- def initialize(provider, token_type, token_value)
21
+ def initialize(provider, token_type, token_value, account_store: {})
23
22
  @provider = provider
24
23
  @token_type = token_type
25
24
  @token_value = token_value
25
+ @account_store = account_store
26
26
  end
27
-
28
27
  end
29
28
  end
30
- end
29
+ end
@@ -17,27 +17,42 @@ module Stormpath
17
17
  module Provider
18
18
  class AccountResolver
19
19
  include Stormpath::Util::Assert
20
+ attr_reader :data_store, :parent_href, :request
20
21
 
21
- def initialize data_store
22
+ def initialize(data_store, parent_href, request)
22
23
  @data_store = data_store
24
+ @parent_href = parent_href
25
+ @request = request
26
+ assert_not_nil(parent_href, 'parent_href argument must be specified')
27
+ assert_kind_of(AccountRequest, request, "Only #{AccountRequest} instances are supported.")
23
28
  end
24
29
 
25
- def resolve_provider_account parent_href, request
26
- assert_not_nil parent_href, "parent_href argument must be specified"
27
- assert_kind_of AccountRequest, request, "Only #{AccountRequest} instances are supported."
30
+ def resolve_provider_account
31
+ attempt.provider_data = provider_data
32
+ data_store.create(href, attempt, Stormpath::Provider::AccountResult)
33
+ end
28
34
 
29
- attempt = @data_store.instantiate AccountAccess
35
+ def provider_data
36
+ @provider_data ||= {}.tap do |body|
37
+ body[request.token_type.to_s.camelize(:lower)] = request.token_value
38
+ body['providerId'] = request.provider
39
+ body['accountStore'] = request_account_store_hash if request.account_store.present?
40
+ end
41
+ end
30
42
 
31
- attempt.provider_data = {
32
- request.token_type.to_s.camelize(:lower) => request.token_value,
33
- "providerId" => request.provider
34
- }
43
+ private
35
44
 
36
- href = parent_href + '/accounts'
45
+ def attempt
46
+ @attempt ||= data_store.instantiate(AccountAccess)
47
+ end
37
48
 
38
- @data_store.create href, attempt, Stormpath::Provider::AccountResult
49
+ def href
50
+ "#{parent_href}/accounts"
39
51
  end
40
52
 
53
+ def request_account_store_hash
54
+ request.account_store.transform_keys { |key| key.to_s.camelize(:lower) }
55
+ end
41
56
  end
42
57
  end
43
- end
58
+ end
@@ -0,0 +1,18 @@
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::TwitterProvider < Stormpath::Provider::Provider
17
+ prop_reader :client_id, :client_secret
18
+ end
@@ -0,0 +1,18 @@
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::TwitterProviderData < Stormpath::Provider::ProviderData
17
+ prop_reader :access_token
18
+ end
@@ -0,0 +1,21 @@
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::Resource::AccountLinkingPolicy < Stormpath::Resource::Instance
17
+ prop_accessor :status, :automatic_provisioning, :matching_property
18
+ prop_reader :created_at, :modified_at
19
+
20
+ belongs_to :tenant
21
+ end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright 2012 Stormpath, Inc.
2
+ # Copyright 2016 Stormpath, Inc.
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@ class Stormpath::Resource::Application < Stormpath::Resource::Instance
20
20
 
21
21
  class LoadError < ArgumentError; end
22
22
 
23
- prop_accessor :name, :description, :authorized_callback_uris, :status
23
+ prop_accessor :name, :description, :authorized_callback_uris, :status, :authorized_origin_uris
24
24
  prop_reader :created_at, :modified_at
25
25
 
26
26
  belongs_to :tenant
@@ -36,6 +36,8 @@ class Stormpath::Resource::Application < Stormpath::Resource::Instance
36
36
  has_one :default_group_store_mapping, class_name: :accountStoreMapping
37
37
  has_one :custom_data
38
38
  has_one :o_auth_policy, class_name: :oauthPolicy
39
+ has_one :web_config, class_name: :applicationWebConfig
40
+ has_one :account_linking_policy
39
41
 
40
42
  alias_method :oauth_policy, :o_auth_policy
41
43
 
@@ -105,8 +107,8 @@ class Stormpath::Resource::Application < Stormpath::Resource::Instance
105
107
  Stormpath::Authentication::BasicAuthenticator.new(data_store).authenticate(href, request)
106
108
  end
107
109
 
108
- def get_provider_account request
109
- Stormpath::Provider::AccountResolver.new(data_store).resolve_provider_account(href, request)
110
+ def get_provider_account(request)
111
+ Stormpath::Provider::AccountResolver.new(data_store, href, request).resolve_provider_account
110
112
  end
111
113
 
112
114
  def authenticate_oauth(request)
@@ -151,7 +153,7 @@ class Stormpath::Resource::Application < Stormpath::Resource::Instance
151
153
  when Hash
152
154
  account_store
153
155
  else
154
- fail ArgumentError, 'Account store has to be passed either as an resource or a hash'
156
+ raise ArgumentError, 'Account store has to be passed either as an resource or a hash'
155
157
  end
156
158
  end
157
159
  end
@@ -0,0 +1,9 @@
1
+ class Stormpath::Resource::ApplicationWebConfig < Stormpath::Resource::Instance
2
+ ENDPOINTS = [:oauth2, :register, :login, :verify_email, :forgot_password, :change_password, :me].freeze
3
+ prop_accessor :dns_label, :status, *ENDPOINTS
4
+ prop_reader :domain_name, :created_at, :modified_at
5
+
6
+ has_one :signing_api_key, class_name: :api_key
7
+ belongs_to :application
8
+ belongs_to :tenant
9
+ end
@@ -14,7 +14,8 @@
14
14
  # limitations under the License.
15
15
  #
16
16
  class Stormpath::Resource::Field < Stormpath::Resource::Instance
17
- prop_reader :name, :required, :created_at, :modified_at
17
+ prop_accessor :required
18
+ prop_reader :name, :created_at, :modified_at
18
19
 
19
20
  belongs_to :schema
20
21
  end
@@ -2,7 +2,7 @@ class Stormpath::Resource::Organization < Stormpath::Resource::Instance
2
2
  include Stormpath::Resource::CustomDataStorage
3
3
 
4
4
  prop_accessor :name, :description, :name_key, :status, :account_store_mappings,
5
- :default_account_store_mapping, :default_group_store_mapping
5
+ :default_account_store_mapping, :default_group_store_mapping
6
6
 
7
7
  prop_reader :created_at, :modified_at
8
8
 
@@ -11,4 +11,5 @@ class Stormpath::Resource::Organization < Stormpath::Resource::Instance
11
11
  belongs_to :tenant
12
12
 
13
13
  has_one :custom_data
14
+ has_one :account_linking_policy
14
15
  end
@@ -14,6 +14,6 @@
14
14
  # limitations under the License.
15
15
  #
16
16
  module Stormpath
17
- VERSION = '1.4.0'
18
- VERSION_DATE = '2016-11-22'
17
+ VERSION = '1.5.0'
18
+ VERSION_DATE = '2017-01-24'
19
19
  end
@@ -1,25 +1,112 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "BasicAuthenticator" do
4
- context "given an instance of BasicAuthenticator" do
3
+ describe 'BasicAuthenticator', vcr: true do
4
+ let(:application) { test_api_client.applications.create(application_attrs) }
5
+ let(:directory) { test_api_client.directories.create(directory_attrs) }
6
+ let(:directory2) { test_api_client.directories.create(directory_attrs) }
7
+ let(:organization) { test_api_client.organizations.create(organization_attrs) }
8
+ let(:authenticator) do
9
+ Stormpath::Authentication::BasicAuthenticator.new(test_api_client.data_store)
10
+ end
11
+ let(:password) { 'F00barfoo' }
12
+ let(:invalid_password) { 'Wr00ngPassw0rd' }
13
+ let(:dir_account) do
14
+ directory.accounts.create(account_attrs(username: 'ruby_cilim_dir', password: password))
15
+ end
16
+ let(:org_account) do
17
+ organization.accounts.create(account_attrs(username: 'ruby_cilim_org', password: password))
18
+ end
19
+ let(:request) do
20
+ Stormpath::Authentication::UsernamePasswordRequest.new(account.username,
21
+ password,
22
+ account_store: account_store)
23
+ end
24
+ let(:authenticate) { authenticator.authenticate(application.href, request) }
25
+
26
+ before do
27
+ map_account_store(application, directory, 0, true, true)
28
+ map_account_store(application, organization, 1, false, false)
29
+ map_organization_store(directory, organization, true)
30
+ end
31
+
32
+ after do
33
+ application.delete
34
+ directory.delete
35
+ organization.delete
36
+ end
37
+
38
+ shared_examples 'an AuthenticationResult' do
39
+ it 'is an AuthenticationResult' do
40
+ expect(authenticate).to be_kind_of Stormpath::Authentication::AuthenticationResult
41
+ end
42
+
43
+ it 'has an account' do
44
+ expect(authenticate.account.email).to eq account.email
45
+ end
46
+ end
47
+
48
+ shared_examples 'an invalid username or password error' do
49
+ it 'raises a Stormpath::Error' do
50
+ expect { authenticate }.to raise_error(Stormpath::Error, 'Invalid username or password.')
51
+ end
52
+ end
5
53
 
6
- before do
7
- data_store = Stormpath::DataStore.new "", "", {}, ""
8
- allow(test_api_client).to receive(:data_store).and_return(data_store)
9
- auth_result = Stormpath::Authentication::AuthenticationResult.new({}, test_api_client)
10
- allow(data_store).to receive(:create).and_return(auth_result)
54
+ context 'authenticate without account store' do
55
+ let(:account) { dir_account }
56
+ let(:account_store) { nil }
11
57
 
12
- @basic_authenticator = Stormpath::Authentication::BasicAuthenticator.new data_store
58
+ context 'successful authentication' do
59
+ it_should_behave_like 'an AuthenticationResult'
13
60
  end
14
61
 
15
- context "when authenticating" do
16
- before do
17
- @response = @basic_authenticator.authenticate "foo/bar", Stormpath::Authentication::UsernamePasswordRequest.new("fake-username", "fake-password")
62
+ context 'wrong password' do
63
+ let(:request) do
64
+ Stormpath::Authentication::UsernamePasswordRequest.new(org_account.username,
65
+ invalid_password)
18
66
  end
19
67
 
20
- it "an AuthenticationResult is returned" do
21
- expect(@response).to be_a Stormpath::Authentication::AuthenticationResult
68
+ it_behaves_like 'an invalid username or password error'
69
+ end
70
+ end
71
+
72
+ context 'authenticate with account store' do
73
+ let(:account) { org_account }
74
+ let(:account_store) { organization }
75
+
76
+ context 'successful authentication' do
77
+ let(:request) do
78
+ Stormpath::Authentication::UsernamePasswordRequest.new(org_account.username,
79
+ password,
80
+ account_store: organization)
81
+ end
82
+
83
+ it_should_behave_like 'an AuthenticationResult'
84
+ end
85
+
86
+ context 'wrong password' do
87
+ let(:request) do
88
+ Stormpath::Authentication::UsernamePasswordRequest.new(org_account.username,
89
+ invalid_password,
90
+ account_store: organization)
22
91
  end
92
+
93
+ it_behaves_like 'an invalid username or password error'
94
+ end
95
+
96
+ context 'account not in account store' do
97
+ before { map_account_store(application, directory2, 1, false, false) }
98
+ after { directory2.delete }
99
+
100
+ let(:another_account) do
101
+ directory2.accounts.create(account_attrs(username: 'ruby-dir-acc', password: password))
102
+ end
103
+ let(:request) do
104
+ Stormpath::Authentication::UsernamePasswordRequest.new(another_account.username,
105
+ password,
106
+ account_store: organization)
107
+ end
108
+
109
+ it_behaves_like 'an invalid username or password error'
23
110
  end
24
111
  end
25
112
  end
@@ -1,24 +1,48 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "ProviderAccountResolver" do
4
- context "given an instance of ProviderAccountResolver" do
3
+ describe 'ProviderAccountResolver' do
4
+ context 'given an instance of ProviderAccountResolver' do
5
+ let(:data_store) { Stormpath::DataStore.new('', '', {}, '') }
6
+ let(:provider_account_resolver) do
7
+ Stormpath::Provider::AccountResolver.new(data_store, 'foo/bar', account_request)
8
+ end
9
+ let(:response) do
10
+ provider_account_resolver.resolve_provider_account
11
+ end
5
12
 
6
13
  before do
7
- data_store = Stormpath::DataStore.new "", "", {}, ""
8
14
  allow(test_api_client).to receive(:data_store).and_return(data_store)
9
15
  auth_result = Stormpath::Provider::AccountResult.new({}, test_api_client)
10
16
  allow(data_store).to receive(:create).and_return(auth_result)
11
-
12
- @provider_account_resolver = Stormpath::Provider::AccountResolver.new data_store
17
+ provider_account_resolver
13
18
  end
14
19
 
15
- context "when integrating" do
16
- before do
17
- @response = @provider_account_resolver.resolve_provider_account "foo/bar", Stormpath::Provider::AccountRequest.new(:facebook, :access_token, "some-token")
20
+ context 'when integrating' do
21
+ context 'without an account store' do
22
+ let(:account_request) do
23
+ Stormpath::Provider::AccountRequest.new(:facebook, :access_token, 'some-token')
24
+ end
25
+
26
+ it 'a ProviderResult is returned' do
27
+ expect(response).to be_a Stormpath::Provider::AccountResult
28
+ end
18
29
  end
19
30
 
20
- it "an ProviderResult is returned" do
21
- expect(@response).to be_a Stormpath::Provider::AccountResult
31
+ context 'with account store as a parameter' do
32
+ let(:account_request) do
33
+ Stormpath::Provider::AccountRequest.new(:facebook,
34
+ :access_token,
35
+ 'some-token',
36
+ account_store: { name_key: 'app1' })
37
+ end
38
+
39
+ it 'a ProviderResult is returned' do
40
+ expect(response).to be_a Stormpath::Provider::AccountResult
41
+ end
42
+
43
+ it 'should have account_store parameter' do
44
+ expect(provider_account_resolver.provider_data.keys).to include 'accountStore'
45
+ end
22
46
  end
23
47
  end
24
48
  end
@@ -41,7 +41,7 @@ describe Stormpath::Provider::Provider, :vcr do
41
41
  provider_clazz = "Stormpath::Provider::#{provider_id.capitalize}Provider".constantize
42
42
  expect(provider).to be_instance_of(provider_clazz)
43
43
 
44
- if provider_id == 'google' || provider_id == 'facebook'
44
+ if %w(google facebook twitter).include?(provider_id)
45
45
  expect(provider.client_id).to eq(client_id)
46
46
  expect(provider.client_secret).to eq(client_secret)
47
47
  end
@@ -52,7 +52,7 @@ describe Stormpath::Provider::Provider, :vcr do
52
52
  end
53
53
  end
54
54
 
55
- shared_examples 'a syncrhonizeable directory' do
55
+ shared_examples 'a synchronizable directory' do
56
56
  it 'should be able to store provider accounts' do
57
57
  account_store_mapping
58
58
 
@@ -118,7 +118,7 @@ describe Stormpath::Provider::Provider, :vcr do
118
118
  end
119
119
 
120
120
  it_behaves_like 'a provider directory'
121
- it_behaves_like 'a syncrhonizeable directory'
121
+ it_behaves_like 'a synchronizable directory'
122
122
  end
123
123
 
124
124
  describe 'create google directory with provider credentials' do
@@ -139,7 +139,7 @@ describe Stormpath::Provider::Provider, :vcr do
139
139
  end
140
140
 
141
141
  it_behaves_like 'a provider directory'
142
- it_behaves_like 'a syncrhonizeable directory'
142
+ it_behaves_like 'a synchronizable directory'
143
143
  end
144
144
 
145
145
  describe 'create linkedin directory with provider credentials' do
@@ -154,7 +154,7 @@ describe Stormpath::Provider::Provider, :vcr do
154
154
  end
155
155
 
156
156
  it_behaves_like 'a provider directory'
157
- it_behaves_like 'a syncrhonizeable directory'
157
+ it_behaves_like 'a synchronizable directory'
158
158
  end
159
159
 
160
160
  describe 'create github directory with provider credentials' do
@@ -169,6 +169,21 @@ describe Stormpath::Provider::Provider, :vcr do
169
169
  end
170
170
 
171
171
  it_behaves_like 'a provider directory'
172
- it_behaves_like 'a syncrhonizeable directory'
172
+ it_behaves_like 'a synchronizable directory'
173
+ end
174
+
175
+ describe 'create twitter directory with provider credentials' do
176
+ let(:name) { 'Twitter' }
177
+ let(:description) { 'Directory for testing Twitter directories.' }
178
+
179
+ let(:provider_id) { 'twitter' }
180
+ let(:client_id) { 'TWITTER_APP_ID' }
181
+ let(:client_secret) { 'TWITTER_APP_SECRET' }
182
+ let(:provider_info) do
183
+ { provider_id: provider_id, client_id: client_id, client_secret: client_secret }
184
+ end
185
+
186
+ it_behaves_like 'a provider directory'
187
+ it_behaves_like 'a synchronizable directory'
173
188
  end
174
189
  end