devise 3.4.1 → 3.5.1

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.

Potentially problematic release.


This version of devise might be problematic. Click here for more details.

Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +26 -16
  3. data/CHANGELOG.md +131 -104
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +84 -85
  6. data/MIT-LICENSE +1 -1
  7. data/README.md +52 -32
  8. data/Rakefile +2 -1
  9. data/app/controllers/devise/confirmations_controller.rb +4 -0
  10. data/app/controllers/devise/omniauth_callbacks_controller.rb +4 -0
  11. data/app/controllers/devise/passwords_controller.rb +14 -4
  12. data/app/controllers/devise/registrations_controller.rb +10 -11
  13. data/app/controllers/devise/sessions_controller.rb +7 -2
  14. data/app/controllers/devise/unlocks_controller.rb +3 -0
  15. data/app/controllers/devise_controller.rb +34 -18
  16. data/app/views/devise/confirmations/new.html.erb +1 -1
  17. data/app/views/devise/passwords/edit.html.erb +3 -0
  18. data/app/views/devise/registrations/new.html.erb +1 -1
  19. data/gemfiles/Gemfile.rails-3.2-stable.lock +43 -43
  20. data/gemfiles/Gemfile.rails-4.0-stable.lock +45 -47
  21. data/gemfiles/Gemfile.rails-4.1-stable.lock +52 -53
  22. data/gemfiles/Gemfile.rails-4.2-stable +29 -0
  23. data/gemfiles/Gemfile.rails-4.2-stable.lock +191 -0
  24. data/lib/devise.rb +23 -28
  25. data/lib/devise/controllers/rememberable.rb +1 -1
  26. data/lib/devise/controllers/sign_in_out.rb +1 -1
  27. data/lib/devise/controllers/store_location.rb +3 -1
  28. data/lib/devise/controllers/url_helpers.rb +7 -9
  29. data/lib/devise/encryptor.rb +22 -0
  30. data/lib/devise/failure_app.rb +26 -10
  31. data/lib/devise/mapping.rb +1 -0
  32. data/lib/devise/models/authenticatable.rb +20 -26
  33. data/lib/devise/models/confirmable.rb +29 -7
  34. data/lib/devise/models/database_authenticatable.rb +6 -9
  35. data/lib/devise/models/recoverable.rb +22 -10
  36. data/lib/devise/models/rememberable.rb +16 -3
  37. data/lib/devise/models/trackable.rb +1 -2
  38. data/lib/devise/models/validatable.rb +3 -3
  39. data/lib/devise/rails.rb +1 -1
  40. data/lib/devise/rails/routes.rb +3 -3
  41. data/lib/devise/strategies/authenticatable.rb +5 -2
  42. data/lib/devise/strategies/database_authenticatable.rb +1 -1
  43. data/lib/devise/strategies/rememberable.rb +10 -0
  44. data/lib/devise/test_helpers.rb +2 -2
  45. data/lib/devise/version.rb +1 -1
  46. data/lib/generators/active_record/templates/migration.rb +1 -1
  47. data/lib/generators/active_record/templates/migration_existing.rb +1 -1
  48. data/lib/generators/templates/controllers/README +1 -1
  49. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +1 -1
  50. data/lib/generators/templates/controllers/registrations_controller.rb +2 -2
  51. data/lib/generators/templates/controllers/sessions_controller.rb +1 -1
  52. data/lib/generators/templates/devise.rb +14 -8
  53. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +1 -1
  54. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +1 -1
  55. data/test/controllers/custom_registrations_controller_test.rb +6 -1
  56. data/test/controllers/helpers_test.rb +5 -0
  57. data/test/controllers/inherited_controller_i18n_messages_test.rb +51 -0
  58. data/test/controllers/internal_helpers_test.rb +4 -4
  59. data/test/controllers/load_hooks_controller_test.rb +19 -0
  60. data/test/controllers/passwords_controller_test.rb +1 -1
  61. data/test/controllers/sessions_controller_test.rb +3 -3
  62. data/test/devise_test.rb +2 -2
  63. data/test/failure_app_test.rb +23 -0
  64. data/test/integration/database_authenticatable_test.rb +11 -0
  65. data/test/integration/omniauthable_test.rb +1 -1
  66. data/test/integration/recoverable_test.rb +13 -0
  67. data/test/integration/rememberable_test.rb +9 -0
  68. data/test/mapping_test.rb +6 -0
  69. data/test/models/confirmable_test.rb +47 -34
  70. data/test/models/lockable_test.rb +6 -6
  71. data/test/models/recoverable_test.rb +39 -7
  72. data/test/models/rememberable_test.rb +8 -2
  73. data/test/models/validatable_test.rb +5 -5
  74. data/test/rails_app/app/controllers/custom/registrations_controller.rb +10 -0
  75. data/test/rails_app/config/application.rb +1 -1
  76. data/test/rails_app/config/environments/production.rb +6 -2
  77. data/test/rails_app/config/environments/test.rb +7 -2
  78. data/test/rails_app/config/initializers/devise.rb +12 -15
  79. data/test/rails_app/lib/shared_user.rb +1 -1
  80. data/test/rails_test.rb +9 -0
  81. data/test/support/integration.rb +2 -2
  82. data/test/test_helpers_test.rb +22 -7
  83. data/test/test_models.rb +2 -2
  84. metadata +11 -2
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+
3
+ class LoadHooksControllerTest < ActionController::TestCase
4
+ setup do
5
+ ActiveSupport.on_load(:devise_controller) do
6
+ define_method :defined_by_load_hook do
7
+ puts 'I am defined dynamically by activesupport load hook'
8
+ end
9
+ end
10
+ end
11
+
12
+ teardown do
13
+ DeviseController.class_eval { undef :defined_by_load_hook }
14
+ end
15
+
16
+ test 'load hook called when controller is loaded' do
17
+ assert DeviseController.instance_methods.include? :defined_by_load_hook
18
+ end
19
+ end
@@ -6,7 +6,7 @@ class PasswordsControllerTest < ActionController::TestCase
6
6
 
7
7
  setup do
8
8
  request.env["devise.mapping"] = Devise.mappings[:user]
9
- @user = create_user.tap(&:confirm!)
9
+ @user = create_user.tap(&:confirm)
10
10
  @raw = @user.send_reset_password_instructions
11
11
  end
12
12
 
@@ -36,7 +36,7 @@ class SessionsControllerTest < ActionController::TestCase
36
36
  request.session["user_return_to"] = 'foo.bar'
37
37
 
38
38
  user = create_user
39
- user.confirm!
39
+ user.confirm
40
40
  post :create, user: {
41
41
  email: user.email,
42
42
  password: user.password
@@ -50,7 +50,7 @@ class SessionsControllerTest < ActionController::TestCase
50
50
  request.session["user_return_to"] = 'foo.bar'
51
51
 
52
52
  user = create_user
53
- user.confirm!
53
+ user.confirm
54
54
  post :create, format: 'json', user: {
55
55
  email: user.email,
56
56
  password: user.password
@@ -72,7 +72,7 @@ class SessionsControllerTest < ActionController::TestCase
72
72
  test "#destroy doesn't set the flash if the requested format is not navigational" do
73
73
  request.env["devise.mapping"] = Devise.mappings[:user]
74
74
  user = create_user
75
- user.confirm!
75
+ user.confirm
76
76
  post :create, format: 'json', user: {
77
77
  email: user.email,
78
78
  password: user.password
@@ -14,11 +14,11 @@ class DeviseTest < ActiveSupport::TestCase
14
14
  test 'bcrypt on the class' do
15
15
  password = "super secret"
16
16
  klass = Struct.new(:pepper, :stretches).new("blahblah", 2)
17
- hash = Devise.bcrypt(klass, password)
17
+ hash = Devise::Encryptor.digest(klass, password)
18
18
  assert_equal ::BCrypt::Password.create(hash), hash
19
19
 
20
20
  klass = Struct.new(:pepper, :stretches).new("bla", 2)
21
- hash = Devise.bcrypt(klass, password)
21
+ hash = Devise::Encryptor.digest(klass, password)
22
22
  assert_not_equal ::BCrypt::Password.new(hash), hash
23
23
  end
24
24
 
@@ -26,6 +26,22 @@ class FailureTest < ActiveSupport::TestCase
26
26
  end
27
27
  end
28
28
 
29
+ class FakeEngineApp < Devise::FailureApp
30
+ class FakeEngine
31
+ def new_user_on_engine_session_url _
32
+ '/user_on_engines/sign_in'
33
+ end
34
+ end
35
+
36
+ def main_app
37
+ raise 'main_app router called instead of fake_engine'
38
+ end
39
+
40
+ def fake_engine
41
+ @fake_engine ||= FakeEngine.new
42
+ end
43
+ end
44
+
29
45
  def self.context(name, &block)
30
46
  instance_eval(&block)
31
47
  end
@@ -85,6 +101,13 @@ class FailureTest < ActiveSupport::TestCase
85
101
  end
86
102
  end
87
103
 
104
+ test 'returns to the default redirect location considering the router for supplied scope' do
105
+ call_failure app: FakeEngineApp, 'warden.options' => { scope: :user_on_engine }
106
+ assert_equal 302, @response.first
107
+ assert_equal 'You need to sign in or sign up before continuing.', @request.flash[:alert]
108
+ assert_equal 'http://test.host/user_on_engines/sign_in', @response.second['Location']
109
+ end
110
+
88
111
  if Rails.application.config.respond_to?(:relative_url_root)
89
112
  test 'returns to the default redirect location considering the relative url root' do
90
113
  swap Rails.application.config, relative_url_root: "/sample" do
@@ -81,4 +81,15 @@ class DatabaseAuthenticationTest < ActionDispatch::IntegrationTest
81
81
  assert_contain 'Invalid credentials'
82
82
  end
83
83
  end
84
+
85
+ test 'valid sign in calls after_database_authentication callback' do
86
+ user = create_user(email: ' foo@bar.com ')
87
+
88
+ User.expects(:find_for_database_authentication).returns user
89
+ user.expects :after_database_authentication
90
+
91
+ sign_in_as_user do
92
+ fill_in 'email', with: 'foo@bar.com'
93
+ end
94
+ end
84
95
  end
@@ -121,7 +121,7 @@ class OmniauthableIntegrationTest < ActionDispatch::IntegrationTest
121
121
  assert_contain 'Could not authenticate you from Facebook because "Access denied".'
122
122
  end
123
123
 
124
- test "handles other exceptions from omniauth" do
124
+ test "handles other exceptions from OmniAuth" do
125
125
  OmniAuth.config.mock_auth[:facebook] = :invalid_credentials
126
126
 
127
127
  visit "/users/sign_in"
@@ -197,6 +197,19 @@ class PasswordTest < ActionDispatch::IntegrationTest
197
197
  assert warden.authenticated?(:user)
198
198
  end
199
199
 
200
+ test 'does not sign in user automatically after changing its password if config.sign_in_after_reset_password is false' do
201
+ swap Devise, sign_in_after_reset_password: false do
202
+ create_user
203
+ request_forgot_password
204
+ reset_password
205
+
206
+ assert_contain 'Your password has been changed successfully.'
207
+ assert_not_contain 'You are now signed in.'
208
+ assert_equal new_user_session_path, @request.path
209
+ assert !warden.authenticated?(:user)
210
+ end
211
+ end
212
+
200
213
  test 'does not sign in user automatically after changing its password if it\'s locked and unlock strategy is :none or :time' do
201
214
  [:none, :time].each do |strategy|
202
215
  swap Devise, unlock_strategy: strategy do
@@ -164,4 +164,13 @@ class RememberMeTest < ActionDispatch::IntegrationTest
164
164
  get users_path
165
165
  assert_not warden.authenticated?(:user)
166
166
  end
167
+
168
+ test 'valid sign in calls after_remembered callback' do
169
+ user = create_user_and_remember
170
+
171
+ User.expects(:serialize_from_cookie).returns user
172
+ user.expects :after_remembered
173
+
174
+ get new_user_registration_path
175
+ end
167
176
  end
@@ -71,6 +71,12 @@ class MappingTest < ActiveSupport::TestCase
71
71
  assert_equal :user, Devise::Mapping.find_scope!(Class.new(User).new)
72
72
  end
73
73
 
74
+ test 'find scope uses devise_scope' do
75
+ user = User.new
76
+ def user.devise_scope; :special_scope; end
77
+ assert_equal :special_scope, Devise::Mapping.find_scope!(user)
78
+ end
79
+
74
80
  test 'find scope raises an error if cannot be found' do
75
81
  assert_raise RuntimeError do
76
82
  Devise::Mapping.find_scope!(String)
@@ -23,31 +23,24 @@ class ConfirmableTest < ActiveSupport::TestCase
23
23
  test 'should confirm a user by updating confirmed at' do
24
24
  user = create_user
25
25
  assert_nil user.confirmed_at
26
- assert user.confirm!
26
+ assert user.confirm
27
27
  assert_not_nil user.confirmed_at
28
28
  end
29
29
 
30
- test 'should clear confirmation token while confirming a user' do
31
- user = create_user
32
- assert_present user.confirmation_token
33
- user.confirm!
34
- assert_nil user.confirmation_token
35
- end
36
-
37
30
  test 'should verify whether a user is confirmed or not' do
38
31
  assert_not new_user.confirmed?
39
32
  user = create_user
40
33
  assert_not user.confirmed?
41
- user.confirm!
34
+ user.confirm
42
35
  assert user.confirmed?
43
36
  end
44
37
 
45
38
  test 'should not confirm a user already confirmed' do
46
39
  user = create_user
47
- assert user.confirm!
40
+ assert user.confirm
48
41
  assert_blank user.errors[:email]
49
42
 
50
- assert_not user.confirm!
43
+ assert_not user.confirm
51
44
  assert_equal "was already confirmed, please try signing in", user.errors[:email].join
52
45
  end
53
46
 
@@ -80,6 +73,16 @@ class ConfirmableTest < ActiveSupport::TestCase
80
73
  assert_equal "was already confirmed, please try signing in", confirmed_user.errors[:email].join
81
74
  end
82
75
 
76
+ test 'should show error when a token has already been used' do
77
+ user = create_user
78
+ raw = user.raw_confirmation_token
79
+ User.confirm_by_token(raw)
80
+ assert user.reload.confirmed?
81
+
82
+ confirmed_user = User.confirm_by_token(raw)
83
+ assert_equal "was already confirmed, please try signing in", confirmed_user.errors[:email].join
84
+ end
85
+
83
86
  test 'should send confirmation instructions by email' do
84
87
  assert_email_sent "mynewuser@example.com" do
85
88
  create_user email: "mynewuser@example.com"
@@ -165,18 +168,19 @@ class ConfirmableTest < ActiveSupport::TestCase
165
168
 
166
169
  test 'should not reset confirmation status or token when updating email' do
167
170
  user = create_user
168
- user.confirm!
171
+ original_token = user.confirmation_token
172
+ user.confirm
169
173
  user.email = 'new_test@example.com'
170
174
  user.save!
171
175
 
172
176
  user.reload
173
177
  assert user.confirmed?
174
- assert_nil user.confirmation_token
178
+ assert_equal original_token, user.confirmation_token
175
179
  end
176
180
 
177
181
  test 'should not be able to send instructions if the user is already confirmed' do
178
182
  user = create_user
179
- user.confirm!
183
+ user.confirm
180
184
  assert_not user.resend_confirmation_instructions
181
185
  assert user.confirmed?
182
186
  assert_equal 'was already confirmed, please try signing in', user.errors[:email].join
@@ -211,7 +215,7 @@ class ConfirmableTest < ActiveSupport::TestCase
211
215
  assert_not user.confirmed?
212
216
  assert_not user.active_for_authentication?
213
217
 
214
- user.confirm!
218
+ user.confirm
215
219
  assert user.confirmed?
216
220
  assert user.active_for_authentication?
217
221
  end
@@ -301,43 +305,52 @@ class ConfirmableTest < ActiveSupport::TestCase
301
305
  self.username = self.username.to_s + 'updated'
302
306
  end
303
307
  old = user.username
304
- assert user.confirm!
308
+ assert user.confirm
305
309
  assert_not_equal user.username, old
306
310
  end
307
311
 
308
312
  test 'should not call after_confirmation if not confirmed' do
309
313
  user = create_user
310
- assert user.confirm!
314
+ assert user.confirm
311
315
  user.define_singleton_method :after_confirmation do
312
316
  self.username = self.username.to_s + 'updated'
313
317
  end
314
318
  old = user.username
315
- assert_not user.confirm!
319
+ assert_not user.confirm
316
320
  assert_equal user.username, old
317
321
  end
322
+
323
+ test 'should always perform validations upon confirm when ensure valid true' do
324
+ admin = create_admin
325
+ admin.stubs(:valid?).returns(false)
326
+ assert_not admin.confirm(ensure_valid: true)
327
+ end
318
328
  end
319
329
 
320
330
  class ReconfirmableTest < ActiveSupport::TestCase
321
331
  test 'should not worry about validations on confirm even with reconfirmable' do
322
332
  admin = create_admin
323
333
  admin.reset_password_token = "a"
324
- assert admin.confirm!
334
+ assert admin.confirm
325
335
  end
326
336
 
327
337
  test 'should generate confirmation token after changing email' do
328
338
  admin = create_admin
329
- assert admin.confirm!
330
- assert_nil admin.confirmation_token
339
+ assert admin.confirm
340
+ residual_token = admin.confirmation_token
331
341
  assert admin.update_attributes(email: 'new_test@example.com')
332
- assert_not_nil admin.confirmation_token
342
+ assert_not_equal residual_token, admin.confirmation_token
333
343
  end
334
344
 
335
- test 'should not generate confirmation token if skipping reconfirmation after changing email' do
345
+ test 'should not regenerate confirmation token or require reconfirmation if skipping reconfirmation after changing email' do
336
346
  admin = create_admin
337
- assert admin.confirm!
347
+ original_token = admin.confirmation_token
348
+ assert admin.confirm
338
349
  admin.skip_reconfirmation!
339
350
  assert admin.update_attributes(email: 'new_test@example.com')
340
- assert_nil admin.confirmation_token
351
+ assert admin.confirmed?
352
+ assert_not admin.pending_reconfirmation?
353
+ assert_equal original_token, admin.confirmation_token
341
354
  end
342
355
 
343
356
  test 'should skip sending reconfirmation email when email is changed and skip_confirmation_notification! is invoked' do
@@ -351,7 +364,7 @@ class ReconfirmableTest < ActiveSupport::TestCase
351
364
 
352
365
  test 'should regenerate confirmation token after changing email' do
353
366
  admin = create_admin
354
- assert admin.confirm!
367
+ assert admin.confirm
355
368
  assert admin.update_attributes(email: 'old_test@example.com')
356
369
  token = admin.confirmation_token
357
370
  assert admin.update_attributes(email: 'new_test@example.com')
@@ -360,7 +373,7 @@ class ReconfirmableTest < ActiveSupport::TestCase
360
373
 
361
374
  test 'should send confirmation instructions by email after changing email' do
362
375
  admin = create_admin
363
- assert admin.confirm!
376
+ assert admin.confirm
364
377
  assert_email_sent "new_test@example.com" do
365
378
  assert admin.update_attributes(email: 'new_test@example.com')
366
379
  end
@@ -369,7 +382,7 @@ class ReconfirmableTest < ActiveSupport::TestCase
369
382
 
370
383
  test 'should not send confirmation by email after changing password' do
371
384
  admin = create_admin
372
- assert admin.confirm!
385
+ assert admin.confirm
373
386
  assert_email_not_sent do
374
387
  assert admin.update_attributes(password: 'newpass', password_confirmation: 'newpass')
375
388
  end
@@ -377,7 +390,7 @@ class ReconfirmableTest < ActiveSupport::TestCase
377
390
 
378
391
  test 'should not send confirmation by email after changing to a blank email' do
379
392
  admin = create_admin
380
- assert admin.confirm!
393
+ assert admin.confirm
381
394
  assert_email_not_sent do
382
395
  admin.email = ''
383
396
  admin.save(validate: false)
@@ -386,23 +399,23 @@ class ReconfirmableTest < ActiveSupport::TestCase
386
399
 
387
400
  test 'should stay confirmed when email is changed' do
388
401
  admin = create_admin
389
- assert admin.confirm!
402
+ assert admin.confirm
390
403
  assert admin.update_attributes(email: 'new_test@example.com')
391
404
  assert admin.confirmed?
392
405
  end
393
406
 
394
407
  test 'should update email only when it is confirmed' do
395
408
  admin = create_admin
396
- assert admin.confirm!
409
+ assert admin.confirm
397
410
  assert admin.update_attributes(email: 'new_test@example.com')
398
411
  assert_not_equal 'new_test@example.com', admin.email
399
- assert admin.confirm!
412
+ assert admin.confirm
400
413
  assert_equal 'new_test@example.com', admin.email
401
414
  end
402
415
 
403
416
  test 'should not allow admin to get past confirmation email by resubmitting their new address' do
404
417
  admin = create_admin
405
- assert admin.confirm!
418
+ assert admin.confirm
406
419
  assert admin.update_attributes(email: 'new_test@example.com')
407
420
  assert_not_equal 'new_test@example.com', admin.email
408
421
  assert admin.update_attributes(email: 'new_test@example.com')
@@ -411,7 +424,7 @@ class ReconfirmableTest < ActiveSupport::TestCase
411
424
 
412
425
  test 'should find a admin by send confirmation instructions with unconfirmed_email' do
413
426
  admin = create_admin
414
- assert admin.confirm!
427
+ assert admin.confirm
415
428
  assert admin.update_attributes(email: 'new_test@example.com')
416
429
  confirmation_admin = Admin.send_confirmation_instructions(email: admin.unconfirmed_email)
417
430
  assert_equal confirmation_admin, admin
@@ -7,7 +7,7 @@ class LockableTest < ActiveSupport::TestCase
7
7
 
8
8
  test "should respect maximum attempts configuration" do
9
9
  user = create_user
10
- user.confirm!
10
+ user.confirm
11
11
  swap Devise, maximum_attempts: 2 do
12
12
  2.times { user.valid_for_authentication?{ false } }
13
13
  assert user.reload.access_locked?
@@ -16,7 +16,7 @@ class LockableTest < ActiveSupport::TestCase
16
16
 
17
17
  test "should increment failed_attempts on successfull validation if the user is already locked" do
18
18
  user = create_user
19
- user.confirm!
19
+ user.confirm
20
20
 
21
21
  swap Devise, maximum_attempts: 2 do
22
22
  2.times { user.valid_for_authentication?{ false } }
@@ -29,7 +29,7 @@ class LockableTest < ActiveSupport::TestCase
29
29
 
30
30
  test "should not touch failed_attempts if lock_strategy is none" do
31
31
  user = create_user
32
- user.confirm!
32
+ user.confirm
33
33
  swap Devise, lock_strategy: :none, maximum_attempts: 2 do
34
34
  3.times { user.valid_for_authentication?{ false } }
35
35
  assert !user.access_locked?
@@ -53,7 +53,7 @@ class LockableTest < ActiveSupport::TestCase
53
53
 
54
54
  test "active_for_authentication? should be the opposite of locked?" do
55
55
  user = create_user
56
- user.confirm!
56
+ user.confirm
57
57
  assert user.active_for_authentication?
58
58
  user.lock_access!
59
59
  assert_not user.active_for_authentication?
@@ -230,7 +230,7 @@ class LockableTest < ActiveSupport::TestCase
230
230
  test 'should unlock account if lock has expired and increase attempts on failure' do
231
231
  swap Devise, unlock_in: 1.minute do
232
232
  user = create_user
233
- user.confirm!
233
+ user.confirm
234
234
 
235
235
  user.failed_attempts = 2
236
236
  user.locked_at = 2.minutes.ago
@@ -243,7 +243,7 @@ class LockableTest < ActiveSupport::TestCase
243
243
  test 'should unlock account if lock has expired on success' do
244
244
  swap Devise, unlock_in: 1.minute do
245
245
  user = create_user
246
- user.confirm!
246
+ user.confirm
247
247
 
248
248
  user.failed_attempts = 2
249
249
  user.locked_at = 2.minutes.ago