cbsorcery 0.8.6
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.
- data/.document +5 -0
- data/.gitignore +56 -0
- data/.rspec +1 -0
- data/.travis.yml +40 -0
- data/CHANGELOG.md +263 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +20 -0
- data/README.md +360 -0
- data/Rakefile +6 -0
- data/gemfiles/active_record-rails40.gemfile +7 -0
- data/gemfiles/active_record-rails41.gemfile +7 -0
- data/lib/generators/sorcery/USAGE +22 -0
- data/lib/generators/sorcery/helpers.rb +40 -0
- data/lib/generators/sorcery/install_generator.rb +95 -0
- data/lib/generators/sorcery/templates/initializer.rb +451 -0
- data/lib/generators/sorcery/templates/migration/activity_logging.rb +10 -0
- data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +9 -0
- data/lib/generators/sorcery/templates/migration/core.rb +13 -0
- data/lib/generators/sorcery/templates/migration/external.rb +12 -0
- data/lib/generators/sorcery/templates/migration/remember_me.rb +8 -0
- data/lib/generators/sorcery/templates/migration/reset_password.rb +9 -0
- data/lib/generators/sorcery/templates/migration/user_activation.rb +9 -0
- data/lib/sorcery.rb +85 -0
- data/lib/sorcery/adapters/active_record_adapter.rb +120 -0
- data/lib/sorcery/adapters/base_adapter.rb +30 -0
- data/lib/sorcery/controller.rb +157 -0
- data/lib/sorcery/controller/config.rb +65 -0
- data/lib/sorcery/controller/submodules/activity_logging.rb +82 -0
- data/lib/sorcery/controller/submodules/brute_force_protection.rb +38 -0
- data/lib/sorcery/controller/submodules/external.rb +199 -0
- data/lib/sorcery/controller/submodules/http_basic_auth.rb +74 -0
- data/lib/sorcery/controller/submodules/remember_me.rb +81 -0
- data/lib/sorcery/controller/submodules/session_timeout.rb +56 -0
- data/lib/sorcery/crypto_providers/aes256.rb +51 -0
- data/lib/sorcery/crypto_providers/bcrypt.rb +97 -0
- data/lib/sorcery/crypto_providers/common.rb +35 -0
- data/lib/sorcery/crypto_providers/md5.rb +19 -0
- data/lib/sorcery/crypto_providers/sha1.rb +28 -0
- data/lib/sorcery/crypto_providers/sha256.rb +36 -0
- data/lib/sorcery/crypto_providers/sha512.rb +36 -0
- data/lib/sorcery/engine.rb +21 -0
- data/lib/sorcery/model.rb +183 -0
- data/lib/sorcery/model/config.rb +96 -0
- data/lib/sorcery/model/submodules/activity_logging.rb +70 -0
- data/lib/sorcery/model/submodules/brute_force_protection.rb +125 -0
- data/lib/sorcery/model/submodules/external.rb +100 -0
- data/lib/sorcery/model/submodules/remember_me.rb +62 -0
- data/lib/sorcery/model/submodules/reset_password.rb +131 -0
- data/lib/sorcery/model/submodules/user_activation.rb +149 -0
- data/lib/sorcery/model/temporary_token.rb +30 -0
- data/lib/sorcery/protocols/certs/ca-bundle.crt +5182 -0
- data/lib/sorcery/protocols/oauth.rb +42 -0
- data/lib/sorcery/protocols/oauth2.rb +47 -0
- data/lib/sorcery/providers/base.rb +27 -0
- data/lib/sorcery/providers/facebook.rb +63 -0
- data/lib/sorcery/providers/github.rb +51 -0
- data/lib/sorcery/providers/google.rb +51 -0
- data/lib/sorcery/providers/jira.rb +77 -0
- data/lib/sorcery/providers/linkedin.rb +66 -0
- data/lib/sorcery/providers/liveid.rb +53 -0
- data/lib/sorcery/providers/twitter.rb +59 -0
- data/lib/sorcery/providers/vk.rb +63 -0
- data/lib/sorcery/providers/xing.rb +64 -0
- data/lib/sorcery/railties/tasks.rake +6 -0
- data/lib/sorcery/test_helpers/internal.rb +78 -0
- data/lib/sorcery/test_helpers/internal/rails.rb +68 -0
- data/lib/sorcery/test_helpers/rails/controller.rb +21 -0
- data/lib/sorcery/test_helpers/rails/integration.rb +26 -0
- data/lib/sorcery/version.rb +3 -0
- data/sorcery.gemspec +34 -0
- data/spec/active_record/user_activation_spec.rb +18 -0
- data/spec/active_record/user_activity_logging_spec.rb +17 -0
- data/spec/active_record/user_brute_force_protection_spec.rb +16 -0
- data/spec/active_record/user_oauth_spec.rb +16 -0
- data/spec/active_record/user_remember_me_spec.rb +16 -0
- data/spec/active_record/user_reset_password_spec.rb +16 -0
- data/spec/active_record/user_spec.rb +37 -0
- data/spec/controllers/controller_activity_logging_spec.rb +124 -0
- data/spec/controllers/controller_brute_force_protection_spec.rb +43 -0
- data/spec/controllers/controller_http_basic_auth_spec.rb +68 -0
- data/spec/controllers/controller_oauth2_spec.rb +407 -0
- data/spec/controllers/controller_oauth_spec.rb +240 -0
- data/spec/controllers/controller_remember_me_spec.rb +117 -0
- data/spec/controllers/controller_session_timeout_spec.rb +80 -0
- data/spec/controllers/controller_spec.rb +215 -0
- data/spec/orm/active_record.rb +21 -0
- data/spec/rails_app/app/active_record/authentication.rb +3 -0
- data/spec/rails_app/app/active_record/user.rb +5 -0
- data/spec/rails_app/app/active_record/user_provider.rb +3 -0
- data/spec/rails_app/app/controllers/sorcery_controller.rb +265 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/mailers/sorcery_mailer.rb +32 -0
- data/spec/rails_app/app/views/application/index.html.erb +17 -0
- data/spec/rails_app/app/views/layouts/application.html.erb +14 -0
- data/spec/rails_app/app/views/sorcery_mailer/activation_email.html.erb +17 -0
- data/spec/rails_app/app/views/sorcery_mailer/activation_email.text.erb +9 -0
- data/spec/rails_app/app/views/sorcery_mailer/activation_needed_email.html.erb +17 -0
- data/spec/rails_app/app/views/sorcery_mailer/activation_success_email.html.erb +17 -0
- data/spec/rails_app/app/views/sorcery_mailer/activation_success_email.text.erb +9 -0
- data/spec/rails_app/app/views/sorcery_mailer/reset_password_email.html.erb +16 -0
- data/spec/rails_app/app/views/sorcery_mailer/reset_password_email.text.erb +8 -0
- data/spec/rails_app/app/views/sorcery_mailer/send_unlock_token_email.text.erb +1 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/config/application.rb +56 -0
- data/spec/rails_app/config/boot.rb +4 -0
- data/spec/rails_app/config/database.yml +22 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/test.rb +37 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/inflections.rb +10 -0
- data/spec/rails_app/config/initializers/mime_types.rb +5 -0
- data/spec/rails_app/config/initializers/secret_token.rb +7 -0
- data/spec/rails_app/config/initializers/session_store.rb +12 -0
- data/spec/rails_app/config/locales/en.yml +5 -0
- data/spec/rails_app/config/routes.rb +48 -0
- data/spec/rails_app/db/migrate/activation/20101224223622_add_activation_to_users.rb +17 -0
- data/spec/rails_app/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +19 -0
- data/spec/rails_app/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +13 -0
- data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +16 -0
- data/spec/rails_app/db/migrate/external/20101224223628_create_authentications_and_user_providers.rb +22 -0
- data/spec/rails_app/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +15 -0
- data/spec/rails_app/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +13 -0
- data/spec/rails_app/db/schema.rb +23 -0
- data/spec/rails_app/db/seeds.rb +7 -0
- data/spec/shared_examples/user_activation_shared_examples.rb +242 -0
- data/spec/shared_examples/user_activity_logging_shared_examples.rb +97 -0
- data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +156 -0
- data/spec/shared_examples/user_oauth_shared_examples.rb +36 -0
- data/spec/shared_examples/user_remember_me_shared_examples.rb +57 -0
- data/spec/shared_examples/user_reset_password_shared_examples.rb +263 -0
- data/spec/shared_examples/user_shared_examples.rb +467 -0
- data/spec/sorcery_crypto_providers_spec.rb +198 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +41 -0
- metadata +350 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
shared_examples_for "rails_3_activity_logging_model" do
|
|
2
|
+
context "loaded plugin configuration" do
|
|
3
|
+
before(:all) do
|
|
4
|
+
sorcery_reload!([:activity_logging])
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
after(:each) do
|
|
8
|
+
User.sorcery_config.reset!
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "allows configuration option 'last_login_at_attribute_name'" do
|
|
12
|
+
sorcery_model_property_set(:last_login_at_attribute_name, :login_time)
|
|
13
|
+
|
|
14
|
+
expect(User.sorcery_config.last_login_at_attribute_name).to eq :login_time
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "allows configuration option 'last_logout_at_attribute_name'" do
|
|
18
|
+
sorcery_model_property_set(:last_logout_at_attribute_name, :logout_time)
|
|
19
|
+
expect(User.sorcery_config.last_logout_at_attribute_name).to eq :logout_time
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "allows configuration option 'last_activity_at_attribute_name'" do
|
|
23
|
+
sorcery_model_property_set(:last_activity_at_attribute_name, :activity_time)
|
|
24
|
+
expect(User.sorcery_config.last_activity_at_attribute_name).to eq :activity_time
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "allows configuration option 'last_login_from_ip_adress'" do
|
|
28
|
+
sorcery_model_property_set(:last_login_from_ip_address_name, :ip_address)
|
|
29
|
+
expect(User.sorcery_config.last_login_from_ip_address_name).to eq :ip_address
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe ".current_users" do
|
|
33
|
+
let(:user) { create_new_user }
|
|
34
|
+
|
|
35
|
+
it "is empty when no users are logged in" do
|
|
36
|
+
expect(User.current_users).to be_empty
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "holds the user object when 1 user is logged in" do
|
|
40
|
+
user.set_last_activity_at(Time.now.in_time_zone)
|
|
41
|
+
|
|
42
|
+
expect(User.current_users).to match([User.sorcery_adapter.find(user.id)])
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "'current_users' shows all current_users, whether they have logged out before or not." do
|
|
46
|
+
User.sorcery_adapter.delete_all
|
|
47
|
+
user1 = create_new_user({:username => 'gizmo1', :email => "bla1@bla.com", :password => 'secret1'})
|
|
48
|
+
user2 = create_new_user({:username => 'gizmo2', :email => "bla2@bla.com", :password => 'secret2'})
|
|
49
|
+
user3 = create_new_user({:username => 'gizmo3', :email => "bla3@bla.com", :password => 'secret3'})
|
|
50
|
+
|
|
51
|
+
now = Time.now.in_time_zone
|
|
52
|
+
[user1, user2, user3].each do |user|
|
|
53
|
+
user.set_last_login_at(now)
|
|
54
|
+
user.set_last_activity_at(now)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
expect(User.current_users.map(&:id)).to match_array([user1, user2, user3].map(&:id))
|
|
58
|
+
Timecop.travel now + 5
|
|
59
|
+
user1.set_last_logout_at(Time.now.in_time_zone)
|
|
60
|
+
expect(User.current_users.map(&:id)).to match_array([user2, user3].map(&:id))
|
|
61
|
+
Timecop.return
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it '.set_last_login_at update last_login_at' do
|
|
67
|
+
user = create_new_user
|
|
68
|
+
now = Time.now.in_time_zone
|
|
69
|
+
expect(user.sorcery_adapter).to receive(:update_attribute).with(:last_login_at, now)
|
|
70
|
+
|
|
71
|
+
user.set_last_login_at(now)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it '.set_last_logout_at update last_logout_at' do
|
|
75
|
+
user = create_new_user
|
|
76
|
+
now = Time.now.in_time_zone
|
|
77
|
+
expect(user.sorcery_adapter).to receive(:update_attribute).with(:last_logout_at, now)
|
|
78
|
+
|
|
79
|
+
user.set_last_logout_at(now)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it '.set_last_activity_at update last_activity_at' do
|
|
83
|
+
user = create_new_user
|
|
84
|
+
now = Time.now.in_time_zone
|
|
85
|
+
expect(user.sorcery_adapter).to receive(:update_attribute).with(:last_activity_at, now)
|
|
86
|
+
|
|
87
|
+
user.set_last_activity_at(now)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it '.set_last_ip_addess update last_login_from_ip_address' do
|
|
91
|
+
user = create_new_user
|
|
92
|
+
expect(user.sorcery_adapter).to receive(:update_attribute).with(:last_login_from_ip_address, '0.0.0.0')
|
|
93
|
+
|
|
94
|
+
user.set_last_ip_addess('0.0.0.0')
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
shared_examples_for "rails_3_brute_force_protection_model" do
|
|
2
|
+
let(:user) { create_new_user }
|
|
3
|
+
before(:each) do
|
|
4
|
+
User.sorcery_adapter.delete_all
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
context "loaded plugin configuration" do
|
|
9
|
+
|
|
10
|
+
let(:config) { User.sorcery_config }
|
|
11
|
+
|
|
12
|
+
before(:all) do
|
|
13
|
+
sorcery_reload!([:brute_force_protection])
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
after(:each) do
|
|
17
|
+
User.sorcery_config.reset!
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
specify { expect(user).to respond_to(:failed_logins_count) }
|
|
21
|
+
specify { expect(user).to respond_to(:lock_expires_at) }
|
|
22
|
+
|
|
23
|
+
it "enables configuration option 'failed_logins_count_attribute_name'" do
|
|
24
|
+
sorcery_model_property_set(:failed_logins_count_attribute_name, :my_count)
|
|
25
|
+
expect(config.failed_logins_count_attribute_name).to eq :my_count
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "enables configuration option 'lock_expires_at_attribute_name'" do
|
|
29
|
+
sorcery_model_property_set(:lock_expires_at_attribute_name, :expires)
|
|
30
|
+
expect(config.lock_expires_at_attribute_name).to eq :expires
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "enables configuration option 'consecutive_login_retries_amount_allowed'" do
|
|
34
|
+
sorcery_model_property_set(:consecutive_login_retries_amount_limit, 34)
|
|
35
|
+
expect(config.consecutive_login_retries_amount_limit).to eq 34
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "enables configuration option 'login_lock_time_period'" do
|
|
39
|
+
sorcery_model_property_set(:login_lock_time_period, 2.hours)
|
|
40
|
+
expect(config.login_lock_time_period).to eq 2.hours
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe "#locked?" do
|
|
44
|
+
it "is locked" do
|
|
45
|
+
user.send("#{config.lock_expires_at_attribute_name}=", Time.now + 5.days)
|
|
46
|
+
expect(user).to be_locked
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "isn't locked" do
|
|
50
|
+
user.send("#{config.lock_expires_at_attribute_name}=", nil)
|
|
51
|
+
expect(user).not_to be_locked
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe "#register_failed_login!" do
|
|
57
|
+
it "locks user when number of retries reached the limit" do
|
|
58
|
+
expect(user.lock_expires_at).to be_nil
|
|
59
|
+
|
|
60
|
+
sorcery_model_property_set(:consecutive_login_retries_amount_limit, 1)
|
|
61
|
+
user.register_failed_login!
|
|
62
|
+
lock_expires_at = User.sorcery_adapter.find_by_id(user.id).lock_expires_at
|
|
63
|
+
|
|
64
|
+
expect(lock_expires_at).not_to be_nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context "unlock_token_mailer_disabled is true" do
|
|
68
|
+
it "does not automatically send unlock email" do
|
|
69
|
+
sorcery_model_property_set(:unlock_token_mailer_disabled, true)
|
|
70
|
+
sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
|
|
71
|
+
sorcery_model_property_set(:login_lock_time_period, 0)
|
|
72
|
+
sorcery_model_property_set(:unlock_token_mailer, SorceryMailer)
|
|
73
|
+
|
|
74
|
+
3.times { user.register_failed_login! }
|
|
75
|
+
|
|
76
|
+
expect(ActionMailer::Base.deliveries.size).to eq 0
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context "unlock_token_mailer_disabled is false" do
|
|
82
|
+
before do
|
|
83
|
+
sorcery_model_property_set(:unlock_token_mailer_disabled, false)
|
|
84
|
+
sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
|
|
85
|
+
sorcery_model_property_set(:login_lock_time_period, 0)
|
|
86
|
+
sorcery_model_property_set(:unlock_token_mailer, SorceryMailer)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "does not automatically send unlock email" do
|
|
90
|
+
3.times { user.register_failed_login! }
|
|
91
|
+
|
|
92
|
+
expect(ActionMailer::Base.deliveries.size).to eq 1
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "generates unlock token before mail is sent" do
|
|
96
|
+
3.times { user.register_failed_login! }
|
|
97
|
+
|
|
98
|
+
expect(ActionMailer::Base.deliveries.last.body.to_s.match(user.unlock_token)).not_to be_nil
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
context ".authenticate" do
|
|
104
|
+
|
|
105
|
+
it "unlocks after lock time period passes" do
|
|
106
|
+
sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
|
|
107
|
+
sorcery_model_property_set(:login_lock_time_period, 0.2)
|
|
108
|
+
2.times { user.register_failed_login! }
|
|
109
|
+
|
|
110
|
+
lock_expires_at = User.sorcery_adapter.find_by_id(user.id).lock_expires_at
|
|
111
|
+
expect(lock_expires_at).not_to be_nil
|
|
112
|
+
|
|
113
|
+
Timecop.travel(Time.now.in_time_zone + 0.3)
|
|
114
|
+
User.authenticate('bla@bla.com', 'secret')
|
|
115
|
+
|
|
116
|
+
lock_expires_at = User.sorcery_adapter.find_by_id(user.id).lock_expires_at
|
|
117
|
+
expect(lock_expires_at).to be_nil
|
|
118
|
+
Timecop.return
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "doest not unlock if time period is 0 (permanent lock)" do
|
|
122
|
+
sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
|
|
123
|
+
sorcery_model_property_set(:login_lock_time_period, 0)
|
|
124
|
+
|
|
125
|
+
2.times { user.register_failed_login! }
|
|
126
|
+
|
|
127
|
+
unlock_date = user.lock_expires_at
|
|
128
|
+
Timecop.travel(Time.now.in_time_zone + 1)
|
|
129
|
+
|
|
130
|
+
user.register_failed_login!
|
|
131
|
+
|
|
132
|
+
expect(user.lock_expires_at.to_s).to eq unlock_date.to_s
|
|
133
|
+
Timecop.return
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
describe "#unlock!" do
|
|
139
|
+
it "unlocks after entering unlock token" do
|
|
140
|
+
sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
|
|
141
|
+
sorcery_model_property_set(:login_lock_time_period, 0)
|
|
142
|
+
sorcery_model_property_set(:unlock_token_mailer, SorceryMailer)
|
|
143
|
+
3.times { user.register_failed_login! }
|
|
144
|
+
|
|
145
|
+
expect(user.unlock_token).not_to be_nil
|
|
146
|
+
|
|
147
|
+
token = user.unlock_token
|
|
148
|
+
user = User.load_from_unlock_token(token)
|
|
149
|
+
|
|
150
|
+
expect(user).not_to be_nil
|
|
151
|
+
|
|
152
|
+
user.unlock!
|
|
153
|
+
expect(User.load_from_unlock_token(user.unlock_token)).to be_nil
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
shared_examples_for "rails_3_oauth_model" do
|
|
2
|
+
# ----------------- PLUGIN CONFIGURATION -----------------------
|
|
3
|
+
|
|
4
|
+
let(:external_user) { create_new_external_user :twitter }
|
|
5
|
+
|
|
6
|
+
describe "loaded plugin configuration" do
|
|
7
|
+
|
|
8
|
+
before(:all) do
|
|
9
|
+
Authentication.sorcery_adapter.delete_all
|
|
10
|
+
User.sorcery_adapter.delete_all
|
|
11
|
+
|
|
12
|
+
sorcery_reload!([:external])
|
|
13
|
+
sorcery_controller_property_set(:external_providers, [:twitter])
|
|
14
|
+
sorcery_model_property_set(:authentications_class, Authentication)
|
|
15
|
+
sorcery_controller_external_property_set(:twitter, :key, "eYVNBjBDi33aa9GkA3w")
|
|
16
|
+
sorcery_controller_external_property_set(:twitter, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
|
|
17
|
+
sorcery_controller_external_property_set(:twitter, :callback_url, "http://blabla.com")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "responds to 'load_from_provider'" do
|
|
21
|
+
expect(User).to respond_to(:load_from_provider)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "'load_from_provider' loads user if exists" do
|
|
25
|
+
external_user
|
|
26
|
+
expect(User.load_from_provider :twitter, 123).to eq external_user
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "'load_from_provider' returns nil if user doesn't exist" do
|
|
30
|
+
external_user
|
|
31
|
+
expect(User.load_from_provider :twitter, 980342).to be_nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
shared_examples_for "rails_3_remember_me_model" do
|
|
2
|
+
let(:user) { create_new_user }
|
|
3
|
+
|
|
4
|
+
describe "loaded plugin configuration" do
|
|
5
|
+
|
|
6
|
+
before(:all) do
|
|
7
|
+
sorcery_reload!([:remember_me])
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
after(:each) do
|
|
11
|
+
User.sorcery_config.reset!
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "allows configuration option 'remember_me_token_attribute_name'" do
|
|
15
|
+
sorcery_model_property_set(:remember_me_token_attribute_name, :my_token)
|
|
16
|
+
|
|
17
|
+
expect(User.sorcery_config.remember_me_token_attribute_name).to eq :my_token
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "allows configuration option 'remember_me_token_expires_at_attribute_name'" do
|
|
21
|
+
sorcery_model_property_set(:remember_me_token_expires_at_attribute_name, :my_expires)
|
|
22
|
+
|
|
23
|
+
expect(User.sorcery_config.remember_me_token_expires_at_attribute_name).to eq :my_expires
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
specify { expect(user).to respond_to :remember_me! }
|
|
27
|
+
|
|
28
|
+
specify { expect(user).to respond_to :forget_me! }
|
|
29
|
+
|
|
30
|
+
it "generates a new token on 'remember_me!'" do
|
|
31
|
+
expect(user.remember_me_token).to be_nil
|
|
32
|
+
|
|
33
|
+
user.remember_me!
|
|
34
|
+
|
|
35
|
+
expect(user.remember_me_token).not_to be_nil
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# FIXME: assert on line 37 sometimes fails by a second
|
|
39
|
+
it "sets an expiration based on 'remember_me_for' attribute" do
|
|
40
|
+
sorcery_model_property_set(:remember_me_for, 2 * 60 * 60 * 24)
|
|
41
|
+
user.remember_me!
|
|
42
|
+
|
|
43
|
+
expect(user.remember_me_token_expires_at.utc.to_s).to eq (Time.now.in_time_zone + 2 * 60 * 60 * 24).utc.to_s
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "deletes the token and expiration on 'forget_me!'" do
|
|
47
|
+
user.remember_me!
|
|
48
|
+
|
|
49
|
+
expect(user.remember_me_token).not_to be_nil
|
|
50
|
+
|
|
51
|
+
user.forget_me!
|
|
52
|
+
|
|
53
|
+
expect(user.remember_me_token).to be_nil
|
|
54
|
+
expect(user.remember_me_token_expires_at).to be_nil
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
shared_examples_for "rails_3_reset_password_model" do
|
|
2
|
+
# ----------------- PLUGIN CONFIGURATION -----------------------
|
|
3
|
+
let(:user) { create_new_user }
|
|
4
|
+
|
|
5
|
+
describe "loaded plugin configuration" do
|
|
6
|
+
|
|
7
|
+
before(:all) do
|
|
8
|
+
sorcery_reload!([:reset_password], :reset_password_mailer => ::SorceryMailer)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
after(:each) do
|
|
12
|
+
User.sorcery_config.reset!
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
context "API" do
|
|
16
|
+
|
|
17
|
+
specify { expect(user).to respond_to :deliver_reset_password_instructions! }
|
|
18
|
+
|
|
19
|
+
specify { expect(user).to respond_to :change_password! }
|
|
20
|
+
|
|
21
|
+
it "responds to .load_from_reset_password_token" do
|
|
22
|
+
expect(User).to respond_to :load_from_reset_password_token
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "allows configuration option 'reset_password_token_attribute_name'" do
|
|
27
|
+
sorcery_model_property_set(:reset_password_token_attribute_name, :my_code)
|
|
28
|
+
|
|
29
|
+
expect(User.sorcery_config.reset_password_token_attribute_name).to eq :my_code
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "allows configuration option 'reset_password_mailer'" do
|
|
33
|
+
sorcery_model_property_set(:reset_password_mailer, TestUser)
|
|
34
|
+
|
|
35
|
+
expect(User.sorcery_config.reset_password_mailer).to eq TestUser
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "enables configuration option 'reset_password_mailer_disabled'" do
|
|
39
|
+
sorcery_model_property_set(:reset_password_mailer_disabled, :my_reset_password_mailer_disabled)
|
|
40
|
+
|
|
41
|
+
expect(User.sorcery_config.reset_password_mailer_disabled).to eq :my_reset_password_mailer_disabled
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "if mailer is nil and mailer is enabled, throw exception!" do
|
|
45
|
+
expect{sorcery_reload!([:reset_password], :reset_password_mailer_disabled => false)}.to raise_error(ArgumentError)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "if mailer is disabled and mailer is nil, do NOT throw exception" do
|
|
49
|
+
expect{sorcery_reload!([:reset_password], :reset_password_mailer_disabled => true)}.to_not raise_error
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "allows configuration option 'reset_password_email_method_name'" do
|
|
53
|
+
sorcery_model_property_set(:reset_password_email_method_name, :my_mailer_method)
|
|
54
|
+
|
|
55
|
+
expect(User.sorcery_config.reset_password_email_method_name).to eq :my_mailer_method
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "allows configuration option 'reset_password_expiration_period'" do
|
|
59
|
+
sorcery_model_property_set(:reset_password_expiration_period, 16)
|
|
60
|
+
|
|
61
|
+
expect(User.sorcery_config.reset_password_expiration_period).to eq 16
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "allows configuration option 'reset_password_email_sent_at_attribute_name'" do
|
|
65
|
+
sorcery_model_property_set(:reset_password_email_sent_at_attribute_name, :blabla)
|
|
66
|
+
|
|
67
|
+
expect(User.sorcery_config.reset_password_email_sent_at_attribute_name).to eq :blabla
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "allows configuration option 'reset_password_time_between_emails'" do
|
|
71
|
+
sorcery_model_property_set(:reset_password_time_between_emails, 16)
|
|
72
|
+
|
|
73
|
+
expect(User.sorcery_config.reset_password_time_between_emails).to eq 16
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
describe "when activated with sorcery" do
|
|
79
|
+
|
|
80
|
+
before(:all) do
|
|
81
|
+
sorcery_reload!([:reset_password], :reset_password_mailer => ::SorceryMailer)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
before(:each) do
|
|
85
|
+
User.sorcery_adapter.delete_all
|
|
86
|
+
user
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
after(:each) do
|
|
90
|
+
Timecop.return
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "load_from_reset_password_token returns user when token is found" do
|
|
94
|
+
user.generate_reset_password_token!
|
|
95
|
+
updated_user = User.sorcery_adapter.find(user.id)
|
|
96
|
+
|
|
97
|
+
expect(User.load_from_reset_password_token user.reset_password_token).to eq updated_user
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "load_from_reset_password_token does NOT return user when token is NOT found" do
|
|
101
|
+
user.generate_reset_password_token!
|
|
102
|
+
|
|
103
|
+
expect(User.load_from_reset_password_token "a").to be_nil
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "load_from_reset_password_token returns user when token is found and not expired" do
|
|
107
|
+
sorcery_model_property_set(:reset_password_expiration_period, 500)
|
|
108
|
+
user.generate_reset_password_token!
|
|
109
|
+
updated_user = User.sorcery_adapter.find(user.id)
|
|
110
|
+
|
|
111
|
+
expect(User.load_from_reset_password_token user.reset_password_token).to eq updated_user
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "load_from_reset_password_token does NOT return user when token is found and expired" do
|
|
115
|
+
sorcery_model_property_set(:reset_password_expiration_period, 0.1)
|
|
116
|
+
user.generate_reset_password_token!
|
|
117
|
+
Timecop.travel(Time.now.in_time_zone+0.5)
|
|
118
|
+
|
|
119
|
+
expect(User.load_from_reset_password_token user.reset_password_token).to be_nil
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "load_from_reset_password_token is always valid if expiration period is nil" do
|
|
123
|
+
sorcery_model_property_set(:reset_password_expiration_period, nil)
|
|
124
|
+
user.generate_reset_password_token!
|
|
125
|
+
updated_user = User.sorcery_adapter.find(user.id)
|
|
126
|
+
|
|
127
|
+
expect(User.load_from_reset_password_token user.reset_password_token).to eq updated_user
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it "load_from_reset_password_token returns nil if token is blank" do
|
|
131
|
+
expect(User.load_from_reset_password_token nil).to be_nil
|
|
132
|
+
expect(User.load_from_reset_password_token "").to be_nil
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "'deliver_reset_password_instructions!' generates a reset_password_token" do
|
|
136
|
+
expect(user.reset_password_token).to be_nil
|
|
137
|
+
|
|
138
|
+
user.deliver_reset_password_instructions!
|
|
139
|
+
|
|
140
|
+
expect(user.reset_password_token).not_to be_nil
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "the reset_password_token is random" do
|
|
144
|
+
sorcery_model_property_set(:reset_password_time_between_emails, 0)
|
|
145
|
+
user.deliver_reset_password_instructions!
|
|
146
|
+
old_password_code = user.reset_password_token
|
|
147
|
+
user.deliver_reset_password_instructions!
|
|
148
|
+
|
|
149
|
+
expect(user.reset_password_token).not_to eq old_password_code
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
context "mailer is enabled" do
|
|
153
|
+
it "sends an email on reset" do
|
|
154
|
+
old_size = ActionMailer::Base.deliveries.size
|
|
155
|
+
user.deliver_reset_password_instructions!
|
|
156
|
+
|
|
157
|
+
expect(ActionMailer::Base.deliveries.size).to eq old_size + 1
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it "calls send_reset_password_email! on reset" do
|
|
161
|
+
expect(user).to receive(:send_reset_password_email!).once
|
|
162
|
+
|
|
163
|
+
user.deliver_reset_password_instructions!
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it "does not send an email if time between emails has not passed since last email" do
|
|
167
|
+
sorcery_model_property_set(:reset_password_time_between_emails, 10000)
|
|
168
|
+
old_size = ActionMailer::Base.deliveries.size
|
|
169
|
+
user.deliver_reset_password_instructions!
|
|
170
|
+
|
|
171
|
+
expect(ActionMailer::Base.deliveries.size).to eq old_size + 1
|
|
172
|
+
|
|
173
|
+
user.deliver_reset_password_instructions!
|
|
174
|
+
|
|
175
|
+
expect(ActionMailer::Base.deliveries.size).to eq old_size + 1
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it "sends an email if time between emails has passed since last email" do
|
|
179
|
+
sorcery_model_property_set(:reset_password_time_between_emails, 0.5)
|
|
180
|
+
old_size = ActionMailer::Base.deliveries.size
|
|
181
|
+
user.deliver_reset_password_instructions!
|
|
182
|
+
|
|
183
|
+
expect(ActionMailer::Base.deliveries.size).to eq old_size + 1
|
|
184
|
+
|
|
185
|
+
Timecop.travel(Time.now.in_time_zone+0.5)
|
|
186
|
+
user.deliver_reset_password_instructions!
|
|
187
|
+
|
|
188
|
+
expect(ActionMailer::Base.deliveries.size).to eq old_size + 2
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
context "mailer is disabled" do
|
|
193
|
+
|
|
194
|
+
before(:all) do
|
|
195
|
+
sorcery_reload!([:reset_password], :reset_password_mailer_disabled => true, :reset_password_mailer => ::SorceryMailer)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it "sends an email on reset" do
|
|
199
|
+
old_size = ActionMailer::Base.deliveries.size
|
|
200
|
+
user.deliver_reset_password_instructions!
|
|
201
|
+
|
|
202
|
+
expect(ActionMailer::Base.deliveries.size).to eq old_size
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
it "does not call send_reset_password_email! on reset" do
|
|
206
|
+
expect(user).to receive(:send_reset_password_email!).never
|
|
207
|
+
|
|
208
|
+
user.deliver_reset_password_instructions!
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it "does not send an email if time between emails has not passed since last email" do
|
|
212
|
+
sorcery_model_property_set(:reset_password_time_between_emails, 10000)
|
|
213
|
+
old_size = ActionMailer::Base.deliveries.size
|
|
214
|
+
user.deliver_reset_password_instructions!
|
|
215
|
+
|
|
216
|
+
expect(ActionMailer::Base.deliveries.size).to eq old_size
|
|
217
|
+
|
|
218
|
+
user.deliver_reset_password_instructions!
|
|
219
|
+
|
|
220
|
+
expect(ActionMailer::Base.deliveries.size).to eq old_size
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
it "sends an email if time between emails has passed since last email" do
|
|
224
|
+
sorcery_model_property_set(:reset_password_time_between_emails, 0.5)
|
|
225
|
+
old_size = ActionMailer::Base.deliveries.size
|
|
226
|
+
user.deliver_reset_password_instructions!
|
|
227
|
+
|
|
228
|
+
expect(ActionMailer::Base.deliveries.size).to eq old_size
|
|
229
|
+
|
|
230
|
+
Timecop.travel(Time.now.in_time_zone+0.5)
|
|
231
|
+
user.deliver_reset_password_instructions!
|
|
232
|
+
|
|
233
|
+
expect(ActionMailer::Base.deliveries.size).to eq old_size
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it "when change_password! is called, deletes reset_password_token" do
|
|
238
|
+
user.deliver_reset_password_instructions!
|
|
239
|
+
|
|
240
|
+
expect(user.reset_password_token).not_to be_nil
|
|
241
|
+
|
|
242
|
+
user.change_password!("blabulsdf")
|
|
243
|
+
user.save!
|
|
244
|
+
|
|
245
|
+
expect(user.reset_password_token).to be_nil
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it "returns false if time between emails has not passed since last email" do
|
|
249
|
+
sorcery_model_property_set(:reset_password_time_between_emails, 10000)
|
|
250
|
+
user.deliver_reset_password_instructions!
|
|
251
|
+
|
|
252
|
+
expect(user.deliver_reset_password_instructions!).to be false
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it "encrypts properly on reset" do
|
|
256
|
+
user.deliver_reset_password_instructions!
|
|
257
|
+
user.change_password!("blagu")
|
|
258
|
+
|
|
259
|
+
expect(Sorcery::CryptoProviders::BCrypt.matches? user.crypted_password, "blagu", user.salt).to be true
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
end
|
|
263
|
+
end
|