devise_g5_authenticatable 0.1.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 +7 -0
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +25 -0
- data/Gemfile +23 -0
- data/LICENSE +20 -0
- data/README.md +243 -0
- data/Rakefile +20 -0
- data/app/controllers/devise_g5_authenticatable/registrations_controller.rb +5 -0
- data/app/controllers/devise_g5_authenticatable/sessions_controller.rb +58 -0
- data/circle.yml +4 -0
- data/config/initializers/devise_g5_authenticatable.rb +3 -0
- data/config/locales/en.yml +6 -0
- data/devise_g5_authenticatable.gemspec +24 -0
- data/lib/devise_g5_authenticatable.rb +16 -0
- data/lib/devise_g5_authenticatable/controllers/helpers.rb +37 -0
- data/lib/devise_g5_authenticatable/controllers/url_helpers.rb +13 -0
- data/lib/devise_g5_authenticatable/engine.rb +11 -0
- data/lib/devise_g5_authenticatable/g5.rb +4 -0
- data/lib/devise_g5_authenticatable/g5/auth_password_validator.rb +30 -0
- data/lib/devise_g5_authenticatable/g5/auth_user_creator.rb +48 -0
- data/lib/devise_g5_authenticatable/g5/auth_user_updater.rb +43 -0
- data/lib/devise_g5_authenticatable/g5/user_exporter.rb +61 -0
- data/lib/devise_g5_authenticatable/models/g5_authenticatable.rb +99 -0
- data/lib/devise_g5_authenticatable/models/protected_attributes.rb +16 -0
- data/lib/devise_g5_authenticatable/omniauth.rb +9 -0
- data/lib/devise_g5_authenticatable/routes.rb +58 -0
- data/lib/devise_g5_authenticatable/version.rb +3 -0
- data/lib/tasks/g5/export_users.rake +13 -0
- data/spec/controllers/helpers_spec.rb +295 -0
- data/spec/controllers/sessions_controller_spec.rb +256 -0
- data/spec/controllers/url_helpers_spec.rb +332 -0
- data/spec/dummy/.gitignore +15 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/images/rails.png +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/javascripts/custom_sessions.js +2 -0
- data/spec/dummy/app/assets/javascripts/home.js +2 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/assets/stylesheets/custom_sessions.css +4 -0
- data/spec/dummy/app/assets/stylesheets/home.css +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/custom_registrations_controllers.rb +2 -0
- data/spec/dummy/app/controllers/custom_sessions_controller.rb +2 -0
- data/spec/dummy/app/controllers/home_controller.rb +4 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/helpers/custom_sessions_helper.rb +2 -0
- data/spec/dummy/app/helpers/home_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/admin.rb +3 -0
- data/spec/dummy/app/models/user.rb +10 -0
- data/spec/dummy/app/views/anonymous/new.html.erb +0 -0
- data/spec/dummy/app/views/home/index.html.erb +1 -0
- data/spec/dummy/app/views/layouts/application.html.erb +16 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +64 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml.ci +6 -0
- data/spec/dummy/config/database.yml.sample +13 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +39 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/devise.rb +259 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/devise.en.yml +60 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +70 -0
- data/spec/dummy/db/migrate/20131230235849_devise_create_users.rb +42 -0
- data/spec/dummy/db/migrate/20140102213131_drop_database_authenticatable.rb +16 -0
- data/spec/dummy/db/migrate/20140103032308_drop_recoverable.rb +16 -0
- data/spec/dummy/db/migrate/20140103042329_drop_rememberable.rb +13 -0
- data/spec/dummy/db/migrate/20140103174810_add_omniauth_columns_to_users.rb +18 -0
- data/spec/dummy/db/migrate/20140103191601_add_email_back_to_user.rb +8 -0
- data/spec/dummy/db/migrate/20140113202948_devise_create_admins.rb +42 -0
- data/spec/dummy/db/migrate/20140113233821_add_provider_and_uid_to_admins.rb +8 -0
- data/spec/dummy/db/schema.rb +50 -0
- data/spec/dummy/db/seeds.rb +7 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/lib/tasks/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/robots.txt +5 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/vendor/assets/javascripts/.gitkeep +0 -0
- data/spec/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/dummy/vendor/plugins/.gitkeep +0 -0
- data/spec/factories/admin.rb +10 -0
- data/spec/factories/user.rb +10 -0
- data/spec/features/edit_registration_spec.rb +109 -0
- data/spec/features/registration_spec.rb +99 -0
- data/spec/features/sign_in_spec.rb +91 -0
- data/spec/features/sign_out_spec.rb +7 -0
- data/spec/g5/auth_password_validator_spec.rb +81 -0
- data/spec/g5/auth_user_creator_spec.rb +100 -0
- data/spec/g5/auth_user_updater_spec.rb +113 -0
- data/spec/g5/user_exporter_spec.rb +105 -0
- data/spec/models/g5_authenticatable_spec.rb +540 -0
- data/spec/models/protected_attributes_spec.rb +17 -0
- data/spec/routing/registrations_routing_spec.rb +107 -0
- data/spec/routing/sessions_routing_spec.rb +111 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/support/devise.rb +3 -0
- data/spec/support/omniauth.rb +3 -0
- data/spec/support/shared_contexts/oauth_error.rb +9 -0
- data/spec/support/shared_contexts/rake.rb +21 -0
- data/spec/support/shared_examples/registration_error.rb +15 -0
- data/spec/support/user_feature_methods.rb +26 -0
- data/spec/tasks/export_users_spec.rb +90 -0
- metadata +293 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Devise::G5::AuthUserCreator do
|
|
4
|
+
let(:creator) { described_class.new(model) }
|
|
5
|
+
|
|
6
|
+
describe '#create' do
|
|
7
|
+
subject(:create) { creator.create }
|
|
8
|
+
|
|
9
|
+
let(:model) do
|
|
10
|
+
build_stubbed(:user, password: password,
|
|
11
|
+
password_confirmation: password_confirmation,
|
|
12
|
+
updated_by: updated_by)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
let(:updated_by) {}
|
|
16
|
+
let(:password) { 'new password' }
|
|
17
|
+
let(:password_confirmation) { 'new password confirmation' }
|
|
18
|
+
|
|
19
|
+
let(:auth_client) { double(:g5_authentication_client, create_user: auth_user) }
|
|
20
|
+
let(:auth_user) { double(:auth_user, id: uid, email: model.email) }
|
|
21
|
+
let(:uid) { 'remote-auth-user-42' }
|
|
22
|
+
before do
|
|
23
|
+
allow(G5AuthenticationClient::Client).to receive(:new).and_return(auth_client)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context 'when the new model has no uid' do
|
|
27
|
+
before { model.uid = nil }
|
|
28
|
+
|
|
29
|
+
context 'when updated by an existing user' do
|
|
30
|
+
let(:updated_by) { build_stubbed(:user) }
|
|
31
|
+
|
|
32
|
+
before { create }
|
|
33
|
+
|
|
34
|
+
it 'should use the token for updated_by user to call g5 auth' do
|
|
35
|
+
expect(G5AuthenticationClient::Client).to have_received(:new).
|
|
36
|
+
with(access_token: updated_by.g5_access_token)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'should create a new auth user with the correct email' do
|
|
40
|
+
expect(auth_client).to have_received(:create_user).
|
|
41
|
+
with(hash_including(email: model.email))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'should create a new auth user with the correct password' do
|
|
45
|
+
expect(auth_client).to have_received(:create_user).
|
|
46
|
+
with(hash_including(password: password))
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'should create a new auth user with the correct password confirmation' do
|
|
50
|
+
expect(auth_client).to have_received(:create_user).
|
|
51
|
+
with(hash_including(password_confirmation: password_confirmation))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'should reset the password' do
|
|
55
|
+
expect(model.password).to be_nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'should reset the password_confirmation' do
|
|
59
|
+
expect(model.password_confirmation).to be_nil
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context 'when auth service returns an error' do
|
|
64
|
+
before do
|
|
65
|
+
allow(auth_client).to receive(:create_user).and_raise('Error!')
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'should raise an exception' do
|
|
69
|
+
expect { create }.to raise_error('Error!')
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context 'when not updated by an existing user' do
|
|
74
|
+
before { create }
|
|
75
|
+
|
|
76
|
+
it 'should use the user token to call g5 auth' do
|
|
77
|
+
expect(G5AuthenticationClient::Client).to have_received(:new).
|
|
78
|
+
with(access_token: model.g5_access_token)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
context 'when new model already has a uid' do
|
|
84
|
+
before { model.uid = 'remote-user-42' }
|
|
85
|
+
before { create }
|
|
86
|
+
|
|
87
|
+
it 'should not create a user' do
|
|
88
|
+
expect(auth_client).to_not have_received(:create_user)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'should not reset the password' do
|
|
92
|
+
expect(model.password).to_not be_blank
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it 'should not reset the password_confirmation' do
|
|
96
|
+
expect(model.password_confirmation).to_not be_blank
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Devise::G5::AuthUserUpdater do
|
|
4
|
+
let(:updater) { described_class.new(model) }
|
|
5
|
+
|
|
6
|
+
let(:auth_client) { double(:g5_authentication_client, update_user: auth_user) }
|
|
7
|
+
let(:auth_user) { double(:auth_user, id: model.uid, email: model.email) }
|
|
8
|
+
before do
|
|
9
|
+
allow(G5AuthenticationClient::Client).to receive(:new).and_return(auth_client)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
let(:model) { create(:user, updated_by: updated_by) }
|
|
13
|
+
let(:updated_by) {}
|
|
14
|
+
|
|
15
|
+
describe '#update' do
|
|
16
|
+
subject(:update) { updater.update }
|
|
17
|
+
|
|
18
|
+
context 'when email and password are unchanged' do
|
|
19
|
+
before { model.password = nil }
|
|
20
|
+
before { update }
|
|
21
|
+
|
|
22
|
+
it 'should not update the auth service' do
|
|
23
|
+
expect(auth_client).to_not have_received(:update_user)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context 'when email has changed' do
|
|
28
|
+
before { model.email = updated_email }
|
|
29
|
+
let(:updated_email) { 'updated.email@test.host' }
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
context 'when user has been updated by another user' do
|
|
33
|
+
let(:updated_by) { create(:user) }
|
|
34
|
+
|
|
35
|
+
context 'when auth user update is successful' do
|
|
36
|
+
before { update }
|
|
37
|
+
|
|
38
|
+
it 'should use the token for updated_by to call g5 auth' do
|
|
39
|
+
expect(G5AuthenticationClient::Client).to have_received(:new).
|
|
40
|
+
with(access_token: updated_by.g5_access_token)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'should update the email' do
|
|
44
|
+
expect(auth_client).to have_received(:update_user).
|
|
45
|
+
with(hash_including(email: updated_email))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'should reset the password' do
|
|
49
|
+
expect(model.password).to be_nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'should reset the password confirmation' do
|
|
53
|
+
expect(model.password_confirmation).to be_nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'should return the updated user' do
|
|
57
|
+
expect(update).to eq(auth_user)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context 'when auth service returns an error' do
|
|
62
|
+
before do
|
|
63
|
+
allow(auth_client).to receive(:update_user).and_raise('Error!')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'should raise an exception' do
|
|
67
|
+
expect { update }.to raise_error
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context 'when user has not been updated by another user' do
|
|
73
|
+
before { update }
|
|
74
|
+
|
|
75
|
+
it 'should use the user token to call g5 auth' do
|
|
76
|
+
expect(G5AuthenticationClient::Client).to have_received(:new).
|
|
77
|
+
with(access_token: model.g5_access_token)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
context 'when password is set' do
|
|
83
|
+
before do
|
|
84
|
+
model.password = updated_password
|
|
85
|
+
model.password_confirmation = updated_password_confirmation
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
let(:updated_password) { 'my_new_secret' }
|
|
89
|
+
let(:updated_password_confirmation) { 'not a match' }
|
|
90
|
+
|
|
91
|
+
before { update }
|
|
92
|
+
|
|
93
|
+
it 'should update the password' do
|
|
94
|
+
expect(auth_client).to have_received(:update_user).
|
|
95
|
+
with(hash_including(password: updated_password))
|
|
96
|
+
update
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'should update the password_confirmation' do
|
|
100
|
+
expect(auth_client).to have_received(:update_user).
|
|
101
|
+
with(hash_including(password_confirmation: updated_password_confirmation))
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it 'should reset the password' do
|
|
105
|
+
expect(model.password).to be_nil
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it 'should reset the password confirmation' do
|
|
109
|
+
expect(model.password_confirmation).to be_nil
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe G5::UserExporter do
|
|
4
|
+
let(:exporter) { G5::UserExporter.new(options) }
|
|
5
|
+
|
|
6
|
+
let(:options) do
|
|
7
|
+
{client_id: 'my_client_id',
|
|
8
|
+
client_secret: 'soopersekrit',
|
|
9
|
+
redirect_uri: 'https://app.host/my/callback',
|
|
10
|
+
endpoint: 'https://auth.host',
|
|
11
|
+
authorization_code: 'abc123'}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe '#export' do
|
|
15
|
+
subject(:export) { exporter.export }
|
|
16
|
+
|
|
17
|
+
let(:uid) { 'abc123yabbadabbadoo' }
|
|
18
|
+
let(:email) { 'fred@flintstone.com' }
|
|
19
|
+
let(:encrypted_password) { 'asdfklja;jtiohtsdgnmesmdnfsmdnfweurth34t' }
|
|
20
|
+
|
|
21
|
+
let(:local_user) do
|
|
22
|
+
double(:local_user, :id => 42,
|
|
23
|
+
:email => email,
|
|
24
|
+
:encrypted_password => encrypted_password,
|
|
25
|
+
:uid= => nil,
|
|
26
|
+
:provider= => nil,
|
|
27
|
+
:save => true)
|
|
28
|
+
end
|
|
29
|
+
before { allow(User).to receive(:all).and_return([local_user]) }
|
|
30
|
+
|
|
31
|
+
let(:auth_user) { double(:auth_user, id: uid, email: email) }
|
|
32
|
+
let(:auth_client) { double(:auth_client, create_user: auth_user) }
|
|
33
|
+
before do
|
|
34
|
+
allow(G5AuthenticationClient::Client).to receive(:new).and_return(auth_client)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'should initialize the auth client with the correct client_id' do
|
|
38
|
+
expect(G5AuthenticationClient::Client).to receive(:new).
|
|
39
|
+
with(hash_including(client_id: options[:client_id])).
|
|
40
|
+
and_return(auth_client)
|
|
41
|
+
export
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'should initialize the auth client with the correct client_secret' do
|
|
45
|
+
expect(G5AuthenticationClient::Client).to receive(:new).
|
|
46
|
+
with(hash_including(client_secret: options[:client_secret])).
|
|
47
|
+
and_return(auth_client)
|
|
48
|
+
export
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'should initialize the auth client with the correct redirect_uri' do
|
|
52
|
+
expect(G5AuthenticationClient::Client).to receive(:new).
|
|
53
|
+
with(hash_including(redirect_uri: options[:redirect_uri])).
|
|
54
|
+
and_return(auth_client)
|
|
55
|
+
export
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'should initialize the auth client with the correct endpoint' do
|
|
59
|
+
expect(G5AuthenticationClient::Client).to receive(:new).
|
|
60
|
+
with(hash_including(endpoint: options[:endpoint])).
|
|
61
|
+
and_return(auth_client)
|
|
62
|
+
export
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'should initialize the auth client with the correct authorization code' do
|
|
66
|
+
expect(G5AuthenticationClient::Client).to receive(:new).
|
|
67
|
+
with(hash_including(authorization_code: options[:authorization_code])).
|
|
68
|
+
and_return(auth_client)
|
|
69
|
+
export
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'should create the auth user with the correct email' do
|
|
73
|
+
expect(auth_client).to receive(:create_user).
|
|
74
|
+
with(hash_including(email: email)).
|
|
75
|
+
and_return(auth_user)
|
|
76
|
+
export
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'should create the auth user with the correct default password' do
|
|
80
|
+
expect(auth_client).to receive(:create_user).
|
|
81
|
+
with(hash_including(password: encrypted_password)).
|
|
82
|
+
and_return(auth_user)
|
|
83
|
+
export
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'should set the uid on the local user' do
|
|
87
|
+
expect(local_user).to receive(:uid=).with(uid)
|
|
88
|
+
export
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'should set the provider on the local user' do
|
|
92
|
+
expect(local_user).to receive(:provider=).with('g5')
|
|
93
|
+
export
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'should save the local user' do
|
|
97
|
+
expect(local_user).to receive(:save).and_return(true)
|
|
98
|
+
export
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it 'should return the SQL update statement with the encrypted password' do
|
|
102
|
+
expect(export).to match(/update users set encrypted_password='#{encrypted_password}' where id=#{uid};/i)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Devise::Models::G5Authenticatable do
|
|
4
|
+
subject { model }
|
|
5
|
+
|
|
6
|
+
let(:model_class) { User }
|
|
7
|
+
let(:model) { model_class.new(attributes) }
|
|
8
|
+
let(:attributes) { Hash.new }
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
describe '#save!' do
|
|
12
|
+
subject(:save) { model.save! }
|
|
13
|
+
|
|
14
|
+
context 'when model is new' do
|
|
15
|
+
let(:attributes) do
|
|
16
|
+
{email: email,
|
|
17
|
+
password: password,
|
|
18
|
+
password_confirmation: password_confirmation,
|
|
19
|
+
provider: provider,
|
|
20
|
+
uid: uid,
|
|
21
|
+
current_password: current_password,
|
|
22
|
+
updated_by: updated_by}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
let(:email) { 'test.email@test.host' }
|
|
26
|
+
let(:password) { 'my_secret' }
|
|
27
|
+
let(:password_confirmation) { password }
|
|
28
|
+
let(:current_password) { 'my_current_password' }
|
|
29
|
+
let(:provider) {}
|
|
30
|
+
let(:uid) {}
|
|
31
|
+
let(:updated_by) { model_class.new }
|
|
32
|
+
|
|
33
|
+
let(:auth_user_creator) { double(:auth_user_creator, create: auth_user) }
|
|
34
|
+
let(:auth_user) { double(:auth_user, id: auth_id) }
|
|
35
|
+
let(:auth_id) { 1 }
|
|
36
|
+
|
|
37
|
+
before do
|
|
38
|
+
allow(Devise::G5::AuthUserCreator).to receive(:new).and_return(auth_user_creator)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context 'when model is valid' do
|
|
42
|
+
before { save }
|
|
43
|
+
|
|
44
|
+
it 'should persist the email' do
|
|
45
|
+
expect(model_class.find(model.id).email).to eq(email)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'should not persist the password' do
|
|
49
|
+
expect(model_class.find(model.id).password).to be_nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'should not persist the password_confirmation' do
|
|
53
|
+
expect(model_class.find(model.id).password_confirmation).to be_nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'should not persist the current_password' do
|
|
57
|
+
expect(model_class.find(model.id).current_password).to be_nil
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'should not persist updated by' do
|
|
61
|
+
expect(model_class.find(model.id).updated_by).to be_nil
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'should initialize a service class for creating auth users' do
|
|
65
|
+
expect(Devise::G5::AuthUserCreator).to have_received(:new).with(model)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'should create an auth user' do
|
|
69
|
+
expect(auth_user_creator).to have_received(:create)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context 'when uid is an integer' do
|
|
74
|
+
let(:uid) { 42 }
|
|
75
|
+
|
|
76
|
+
it 'should not raise an error' do
|
|
77
|
+
expect { save }.to_not raise_error
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context 'when there is an error creating the auth user' do
|
|
82
|
+
before do
|
|
83
|
+
allow(auth_user_creator).to receive(:create).and_raise(error)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
context 'with OAuth2::Error' do
|
|
87
|
+
let(:error) { OAuth2::Error.new(response) }
|
|
88
|
+
let(:response) do
|
|
89
|
+
double(:response, :parsed => error_hash,
|
|
90
|
+
:body => error_body,
|
|
91
|
+
:error= => nil)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
let(:error_hash) do
|
|
95
|
+
{ 'error' => error_code,
|
|
96
|
+
'error_description' => error_description }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
let(:error_code) { "Email can't be blank" }
|
|
100
|
+
let(:error_description) { 'Validation failed' }
|
|
101
|
+
let(:error_body) { 'problems' }
|
|
102
|
+
|
|
103
|
+
it 'should raise a RecordNotSaved error with the OAuth error code' do
|
|
104
|
+
expect { save }. to raise_error(ActiveRecord::RecordNotSaved, error_code)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
context 'with some other error' do
|
|
109
|
+
let(:error) { StandardError.new(error_message) }
|
|
110
|
+
let(:error_message) { 'problems' }
|
|
111
|
+
|
|
112
|
+
it 'should raise a RecordNotSaved error' do
|
|
113
|
+
expect { save }.to raise_error(ActiveRecord::RecordNotSaved, error_message)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
context 'when model is updated' do
|
|
120
|
+
let(:model) { create(:user) }
|
|
121
|
+
|
|
122
|
+
let(:auth_user_updater) { double(:user_updater, update: auth_user) }
|
|
123
|
+
let(:auth_user) { double(:auth_user, id: auth_id) }
|
|
124
|
+
let(:auth_id) { 'remote-auth-id-42' }
|
|
125
|
+
before do
|
|
126
|
+
allow(Devise::G5::AuthUserUpdater).to receive(:new).and_return(auth_user_updater)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
context 'with successful auth user update' do
|
|
130
|
+
before { save }
|
|
131
|
+
|
|
132
|
+
it 'should initialize the auth user updater' do
|
|
133
|
+
expect(Devise::G5::AuthUserUpdater).to have_received(:new).with(model)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it 'should update the auth user' do
|
|
137
|
+
expect(auth_user_updater).to have_received(:update)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
context 'with unsuccessful auth user update' do
|
|
142
|
+
before do
|
|
143
|
+
allow(auth_user_updater).to receive(:update).and_raise(error_message)
|
|
144
|
+
end
|
|
145
|
+
let(:error_message) { 'problems' }
|
|
146
|
+
|
|
147
|
+
it 'should raise an error' do
|
|
148
|
+
expect { save }.to raise_error
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
describe '#update_with_password' do
|
|
155
|
+
subject { update_with_password }
|
|
156
|
+
let(:update_with_password) { model.update_with_password(params) }
|
|
157
|
+
|
|
158
|
+
let(:model) { create(:user) }
|
|
159
|
+
|
|
160
|
+
let(:params) do
|
|
161
|
+
{current_password: current_password,
|
|
162
|
+
password: updated_password,
|
|
163
|
+
password_confirmation: updated_password,
|
|
164
|
+
email: updated_email}
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
let(:current_password) {}
|
|
168
|
+
let(:updated_password) { 'updated_secret' }
|
|
169
|
+
let(:updated_email) { 'update@email.com' }
|
|
170
|
+
|
|
171
|
+
let(:auth_updater) { double(:auth_user_updater, update: true) }
|
|
172
|
+
before { allow(Devise::G5::AuthUserUpdater).to receive(:new).and_return(auth_updater) }
|
|
173
|
+
|
|
174
|
+
let(:password_validator) { double(:auth_password_validator) }
|
|
175
|
+
before do
|
|
176
|
+
allow(Devise::G5::AuthPasswordValidator).to receive(:new).
|
|
177
|
+
and_return(password_validator)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
context 'with valid current password' do
|
|
181
|
+
before { allow(password_validator).to receive(:valid_password?).and_return(true) }
|
|
182
|
+
|
|
183
|
+
before { update_with_password }
|
|
184
|
+
|
|
185
|
+
context 'with valid input' do
|
|
186
|
+
it 'should return true' do
|
|
187
|
+
expect(update_with_password).to be_true
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it 'should initialize the auth user updater' do
|
|
191
|
+
expect(Devise::G5::AuthUserUpdater).to have_received(:new).with(model)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it 'should update the credentials in the auth server' do
|
|
195
|
+
expect(auth_updater).to have_received(:update)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it 'should update the email on the local model' do
|
|
199
|
+
expect(model.email).to eq(updated_email)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
context 'when there is a validation error' do
|
|
204
|
+
let(:updated_email) { '' }
|
|
205
|
+
|
|
206
|
+
it 'should return false' do
|
|
207
|
+
expect(update_with_password).to be_false
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it 'should not update the credentials on the auth server' do
|
|
211
|
+
expect(auth_updater).to_not have_received(:update)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it 'should add an error to the email attribute' do
|
|
215
|
+
expect(model.errors[:email].count).to eq(1)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
context 'with invalid current password' do
|
|
221
|
+
before { allow(password_validator).to receive(:valid_password?).and_return(false) }
|
|
222
|
+
|
|
223
|
+
before { update_with_password }
|
|
224
|
+
|
|
225
|
+
context 'when current password is missing' do
|
|
226
|
+
let(:current_password) { '' }
|
|
227
|
+
|
|
228
|
+
it 'should return false' do
|
|
229
|
+
expect(update_with_password).to be_false
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it 'should set an error on the current_password attribute' do
|
|
233
|
+
expect(model.errors[:current_password]).to include("can't be blank")
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
it 'should not update user credentials in the remote server' do
|
|
237
|
+
expect(auth_updater).to_not have_received(:update)
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
context 'when current password is incorrect' do
|
|
242
|
+
let(:current_password) { 'something wrong' }
|
|
243
|
+
|
|
244
|
+
it 'should return false' do
|
|
245
|
+
expect(update_with_password).to be_false
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it 'should set an error on the current_password attribute' do
|
|
249
|
+
expect(model.errors[:current_password]).to include('is invalid')
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it 'should not update user credentials in the remote server' do
|
|
253
|
+
expect(auth_updater).to_not have_received(:update)
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
describe '#clean_up_passwords' do
|
|
260
|
+
subject(:clean_up_passwords) { model.clean_up_passwords }
|
|
261
|
+
let(:model) do
|
|
262
|
+
build_stubbed(:user, password: password,
|
|
263
|
+
password_confirmation: password)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
let(:password) { 'foobarbaz' }
|
|
267
|
+
|
|
268
|
+
it 'should change the password to nil' do
|
|
269
|
+
expect { clean_up_passwords }.to change { model.password }.
|
|
270
|
+
from(password).to(nil)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
it 'should change the password_confirmation to nil' do
|
|
274
|
+
expect { clean_up_passwords }.to change { model.password_confirmation }.
|
|
275
|
+
from(password).to(nil)
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
describe '#valid_password?' do
|
|
280
|
+
subject(:valid_password?) { model.valid_password?(password) }
|
|
281
|
+
|
|
282
|
+
let(:model) { create(:user) }
|
|
283
|
+
let(:password) { 'foobarbaz' }
|
|
284
|
+
|
|
285
|
+
let(:password_validator) { double(:password_validator, valid_password?: valid) }
|
|
286
|
+
before do
|
|
287
|
+
allow(Devise::G5::AuthPasswordValidator).to receive(:new).and_return(password_validator)
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
before { valid_password? }
|
|
291
|
+
|
|
292
|
+
context 'when password is valid' do
|
|
293
|
+
let(:valid) { true }
|
|
294
|
+
|
|
295
|
+
it 'should return true' do
|
|
296
|
+
expect(valid_password?).to be_true
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
it 'should initialize the validator with the model' do
|
|
300
|
+
expect(Devise::G5::AuthPasswordValidator).to have_received(:new).with(model)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
it 'should check the password against the auth server' do
|
|
304
|
+
expect(password_validator).to have_received(:valid_password?).with(password)
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
context 'when password is invalid' do
|
|
309
|
+
let(:valid) { false }
|
|
310
|
+
|
|
311
|
+
it 'should return false' do
|
|
312
|
+
expect(valid_password?).to be_false
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
it 'should initialize the validator with the model' do
|
|
316
|
+
expect(Devise::G5::AuthPasswordValidator).to have_received(:new).with(model)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
it 'should check the password against the auth server' do
|
|
320
|
+
expect(password_validator).to have_received(:valid_password?).with(password)
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
describe '.find_and_update_for_g5_oauth' do
|
|
326
|
+
subject(:find_and_update) { model_class.find_and_update_for_g5_oauth(auth_data) }
|
|
327
|
+
|
|
328
|
+
let(:auth_data) do
|
|
329
|
+
OmniAuth::AuthHash.new({
|
|
330
|
+
provider: 'g5',
|
|
331
|
+
uid: '123999',
|
|
332
|
+
info: {name: 'Foo Bar',
|
|
333
|
+
email: 'foo@bar.com'},
|
|
334
|
+
credentials: {token: 'abc123'}
|
|
335
|
+
})
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
context 'when model exists' do
|
|
339
|
+
let!(:model) do
|
|
340
|
+
create(:user, provider: auth_data['provider'],
|
|
341
|
+
uid: auth_data['uid'],
|
|
342
|
+
g5_access_token: 'old_token')
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
it 'should return the model' do
|
|
346
|
+
expect(find_and_update).to eq(model)
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
it 'should save the updated g5_access_token' do
|
|
350
|
+
find_and_update
|
|
351
|
+
model.reload
|
|
352
|
+
expect(model.g5_access_token).to eq(auth_data.credentials.token)
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
context 'when model does not exist' do
|
|
357
|
+
it 'should return nothing' do
|
|
358
|
+
expect(find_and_update).to be_nil
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
describe '.find_for_g5_oauth' do
|
|
364
|
+
subject(:find_for_g5_oauth) { model_class.find_for_g5_oauth(auth_data) }
|
|
365
|
+
|
|
366
|
+
let(:auth_data) do
|
|
367
|
+
OmniAuth::AuthHash.new({
|
|
368
|
+
provider: 'g5',
|
|
369
|
+
uid: uid,
|
|
370
|
+
info: {name: 'Foo Bar',
|
|
371
|
+
email: 'foo@bar.com'},
|
|
372
|
+
credentials: {token: 'abc123'}
|
|
373
|
+
})
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
context 'when model exists' do
|
|
377
|
+
let!(:model) do
|
|
378
|
+
create(:user, provider: auth_data.provider,
|
|
379
|
+
uid: uid.to_s)
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
context 'when auth data uid is an integer' do
|
|
383
|
+
let(:uid) { 42 }
|
|
384
|
+
|
|
385
|
+
it 'should return the model' do
|
|
386
|
+
expect(find_for_g5_oauth).to eq(model)
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
it 'should not create any new models' do
|
|
390
|
+
expect { find_for_g5_oauth }.to_not change { model_class.count }
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
context 'when auth data uid is a string' do
|
|
395
|
+
let(:uid) { 'some/crazy/string1234#id' }
|
|
396
|
+
|
|
397
|
+
it 'should return the model' do
|
|
398
|
+
expect(find_for_g5_oauth).to eq(model)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
it 'should not create any new models' do
|
|
402
|
+
expect { find_for_g5_oauth }.to_not change { model_class.count }
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
context 'when model does not exist' do
|
|
408
|
+
let(:uid) { '42' }
|
|
409
|
+
|
|
410
|
+
it 'should not return anything' do
|
|
411
|
+
expect(find_for_g5_oauth).to be_nil
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
it 'should not create any new models' do
|
|
415
|
+
expect { find_for_g5_oauth }.to_not change { model_class.count }
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
describe '#update_g5_credentials' do
|
|
421
|
+
subject(:update_g5_credentials) { model.update_g5_credentials(auth_data) }
|
|
422
|
+
|
|
423
|
+
let(:auth_data) do
|
|
424
|
+
OmniAuth::AuthHash.new({
|
|
425
|
+
provider: 'g5',
|
|
426
|
+
uid: '123999',
|
|
427
|
+
info: {name: 'Foo Bar',
|
|
428
|
+
email: 'foo@bar.com'},
|
|
429
|
+
credentials: {token: 'abc123'}
|
|
430
|
+
})
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
let(:model) do
|
|
434
|
+
create(:user, provider: auth_data['provider'],
|
|
435
|
+
uid: auth_data['uid'],
|
|
436
|
+
g5_access_token: 'old_token')
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
it 'should update the g5_access_token' do
|
|
440
|
+
expect { update_g5_credentials }.to change { model.g5_access_token }.to(auth_data.credentials.token)
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
it 'should not save the changes' do
|
|
444
|
+
update_g5_credentials
|
|
445
|
+
expect(model.g5_access_token_changed?).to be_true
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
describe '#revoke_g5_credentials!' do
|
|
450
|
+
subject(:revoke_g5_credentials!) { model.revoke_g5_credentials! }
|
|
451
|
+
|
|
452
|
+
let(:auth_updater) { double(:auth_user_updater, update: nil) }
|
|
453
|
+
before { allow(Devise::G5::AuthUserUpdater).to receive(:new).and_return(auth_updater) }
|
|
454
|
+
|
|
455
|
+
let(:model) { create(:user, g5_access_token: g5_token) }
|
|
456
|
+
before { model.password = model.password_confirmation = nil }
|
|
457
|
+
|
|
458
|
+
context 'when there is a g5 token' do
|
|
459
|
+
let(:g5_token) { 'my_g5_token' }
|
|
460
|
+
|
|
461
|
+
it 'should reset the g5 token' do
|
|
462
|
+
revoke_g5_credentials!
|
|
463
|
+
expect(model.g5_access_token).to be_nil
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
it 'should save the changes' do
|
|
467
|
+
revoke_g5_credentials!
|
|
468
|
+
expect { model.reload }.to_not change { model.g5_access_token }
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
context 'when there is no g5 token' do
|
|
473
|
+
let(:g5_token) {}
|
|
474
|
+
|
|
475
|
+
it 'should not set the g5 token' do
|
|
476
|
+
revoke_g5_credentials!
|
|
477
|
+
expect(model.g5_access_token).to be_nil
|
|
478
|
+
end
|
|
479
|
+
end
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
describe '#new_with_session' do
|
|
483
|
+
subject(:new_with_session) { model_class.new_with_session(params, session) }
|
|
484
|
+
|
|
485
|
+
let(:auth_data) do
|
|
486
|
+
OmniAuth::AuthHash.new({
|
|
487
|
+
provider: 'g5',
|
|
488
|
+
uid: '123999',
|
|
489
|
+
info: {name: 'Foo Bar',
|
|
490
|
+
email: 'foo@bar.com'},
|
|
491
|
+
credentials: {token: 'abc123'}
|
|
492
|
+
})
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
context 'with params' do
|
|
496
|
+
let(:params) { {'email' => email_param} }
|
|
497
|
+
let(:email_param) { 'my.email.param@test.host' }
|
|
498
|
+
|
|
499
|
+
context 'with session data' do
|
|
500
|
+
let(:session) { {'omniauth.auth' => auth_data} }
|
|
501
|
+
|
|
502
|
+
it { should be_new_record }
|
|
503
|
+
its(:email) { should == email_param }
|
|
504
|
+
its(:provider) { should == auth_data.provider }
|
|
505
|
+
its(:uid) { should == auth_data.uid }
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
context 'without session data' do
|
|
509
|
+
let(:session) { Hash.new }
|
|
510
|
+
|
|
511
|
+
it { should be_new_record }
|
|
512
|
+
its(:email) { should == email_param }
|
|
513
|
+
its(:provider) { should be_nil }
|
|
514
|
+
its(:uid) { should be_nil }
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
context 'without params' do
|
|
519
|
+
let(:params) { Hash.new }
|
|
520
|
+
|
|
521
|
+
context 'with session data' do
|
|
522
|
+
let(:session) { {'omniauth.auth' => auth_data} }
|
|
523
|
+
|
|
524
|
+
it { should be_new_record }
|
|
525
|
+
its(:email) { should == auth_data.info[:email] }
|
|
526
|
+
its(:provider) { should == auth_data.provider }
|
|
527
|
+
its(:uid) { should == auth_data.uid }
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
context 'without session data' do
|
|
531
|
+
let(:session) { Hash.new }
|
|
532
|
+
|
|
533
|
+
it { should be_new_record }
|
|
534
|
+
its(:email) { should be_blank }
|
|
535
|
+
its(:provider) { should be_nil }
|
|
536
|
+
its(:uid) { should be_nil }
|
|
537
|
+
end
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
end
|