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.
- checksums.yaml +4 -4
- data/CHANGES.md +12 -0
- data/lib/stormpath-sdk.rb +4 -0
- data/lib/stormpath-sdk/data_store.rb +172 -166
- data/lib/stormpath-sdk/provider/account_request.rb +5 -6
- data/lib/stormpath-sdk/provider/account_resolver.rb +27 -12
- data/lib/stormpath-sdk/provider/twitter/twitter_provider.rb +18 -0
- data/lib/stormpath-sdk/provider/twitter/twitter_provider_data.rb +18 -0
- data/lib/stormpath-sdk/resource/account_linking_policy.rb +21 -0
- data/lib/stormpath-sdk/resource/application.rb +7 -5
- data/lib/stormpath-sdk/resource/application_web_config.rb +9 -0
- data/lib/stormpath-sdk/resource/field.rb +2 -1
- data/lib/stormpath-sdk/resource/organization.rb +2 -1
- data/lib/stormpath-sdk/version.rb +2 -2
- data/spec/auth/basic_authenticator_spec.rb +100 -13
- data/spec/provider/account_resolver_spec.rb +34 -10
- data/spec/provider/provider_spec.rb +21 -6
- data/spec/resource/account_linking_policy_spec.rb +31 -0
- data/spec/resource/application_spec.rb +44 -2
- data/spec/resource/application_web_config_spec.rb +65 -0
- data/spec/resource/collection_spec.rb +2 -2
- data/spec/resource/directory_spec.rb +7 -0
- data/spec/resource/organization_spec.rb +1 -0
- data/spec/resource/schema_spec.rb +10 -2
- data/spec/spec_helper.rb +1 -0
- data/spec/support/custom_data_save_period.rb +12 -0
- data/spec/support/mocked_provider_accounts.rb +30 -0
- metadata +9 -2
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright
|
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
|
-
|
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
|
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
|
26
|
-
|
27
|
-
|
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
|
-
|
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
|
-
|
32
|
-
request.token_type.to_s.camelize(:lower) => request.token_value,
|
33
|
-
"providerId" => request.provider
|
34
|
-
}
|
43
|
+
private
|
35
44
|
|
36
|
-
|
45
|
+
def attempt
|
46
|
+
@attempt ||= data_store.instantiate(AccountAccess)
|
47
|
+
end
|
37
48
|
|
38
|
-
|
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
|
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
|
109
|
-
Stormpath::Provider::AccountResolver.new(data_store
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
@@ -1,25 +1,112 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe
|
4
|
-
|
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
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
58
|
+
context 'successful authentication' do
|
59
|
+
it_should_behave_like 'an AuthenticationResult'
|
13
60
|
end
|
14
61
|
|
15
|
-
context
|
16
|
-
|
17
|
-
|
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
|
-
|
21
|
-
|
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
|
4
|
-
context
|
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
|
16
|
-
|
17
|
-
|
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
|
-
|
21
|
-
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|