devise 4.4.3 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +12 -11
  3. data/CHANGELOG.md +23 -1
  4. data/Gemfile +2 -2
  5. data/Gemfile.lock +82 -73
  6. data/README.md +17 -18
  7. data/app/controllers/devise/registrations_controller.rb +1 -1
  8. data/app/controllers/devise_controller.rb +1 -1
  9. data/app/views/devise/passwords/edit.html.erb +1 -1
  10. data/app/views/devise/registrations/edit.html.erb +3 -3
  11. data/app/views/devise/registrations/new.html.erb +2 -2
  12. data/app/views/devise/sessions/new.html.erb +1 -1
  13. data/gemfiles/Gemfile.rails-4.1-stable.lock +2 -2
  14. data/gemfiles/Gemfile.rails-4.2-stable.lock +2 -2
  15. data/gemfiles/Gemfile.rails-5.0-stable.lock +2 -2
  16. data/gemfiles/Gemfile.rails-5.2-rc1.lock +2 -2
  17. data/guides/bug_report_templates/integration_test.rb +1 -1
  18. data/lib/devise/controllers/sign_in_out.rb +3 -0
  19. data/lib/devise/failure_app.rb +2 -0
  20. data/lib/devise/models/authenticatable.rb +31 -24
  21. data/lib/devise/models/database_authenticatable.rb +7 -7
  22. data/lib/devise/models/trackable.rb +8 -1
  23. data/lib/devise/parameter_filter.rb +2 -0
  24. data/lib/devise/parameter_sanitizer.rb +13 -1
  25. data/lib/devise/secret_key_finder.rb +2 -0
  26. data/lib/devise/strategies/database_authenticatable.rb +3 -1
  27. data/lib/devise/version.rb +1 -1
  28. data/lib/generators/active_record/devise_generator.rb +5 -5
  29. data/lib/generators/devise/orm_helpers.rb +2 -2
  30. data/lib/generators/mongoid/devise_generator.rb +5 -5
  31. data/lib/generators/templates/devise.rb +7 -0
  32. data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +5 -1
  33. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +6 -1
  34. data/lib/generators/templates/simple_form_for/passwords/new.html.erb +4 -1
  35. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +11 -3
  36. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +11 -3
  37. data/lib/generators/templates/simple_form_for/sessions/new.html.erb +7 -2
  38. data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +4 -1
  39. data/test/failure_app_test.rb +6 -0
  40. data/test/integration/confirmable_test.rb +5 -5
  41. data/test/integration/database_authenticatable_test.rb +13 -0
  42. data/test/mailers/email_changed_test.rb +2 -2
  43. data/test/models/confirmable_test.rb +14 -14
  44. data/test/models/database_authenticatable_test.rb +10 -3
  45. data/test/models/trackable_test.rb +18 -0
  46. data/test/parameter_sanitizer_test.rb +28 -0
  47. data/test/rails_app/config/initializers/devise.rb +5 -0
  48. data/test/rails_app/lib/lazy_load_test_module.rb +5 -0
  49. data/test/secret_key_finder_test.rb +24 -0
  50. metadata +5 -3
@@ -7,7 +7,12 @@
7
7
  <%= f.full_error :reset_password_token %>
8
8
 
9
9
  <div class="form-inputs">
10
- <%= f.input :password, label: "New password", required: true, autofocus: true, hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length) %>
10
+ <%= f.input :password,
11
+ label: "New password",
12
+ required: true,
13
+ autofocus: true,
14
+ hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length),
15
+ input_html: { autocomplete: "new-password" } %>
11
16
  <%= f.input :password_confirmation, label: "Confirm your new password", required: true %>
12
17
  </div>
13
18
 
@@ -4,7 +4,10 @@
4
4
  <%= f.error_notification %>
5
5
 
6
6
  <div class="form-inputs">
7
- <%= f.input :email, required: true, autofocus: true %>
7
+ <%= f.input :email,
8
+ required: true,
9
+ autofocus: true,
10
+ input_html: { autocomplete: "email" } %>
8
11
  </div>
9
12
 
10
13
  <div class="form-actions">
@@ -10,9 +10,17 @@
10
10
  <p>Currently waiting confirmation for: <%= resource.unconfirmed_email %></p>
11
11
  <% end %>
12
12
 
13
- <%= f.input :password, autocomplete: "off", hint: "leave it blank if you don't want to change it", required: false %>
14
- <%= f.input :password_confirmation, required: false %>
15
- <%= f.input :current_password, hint: "we need your current password to confirm your changes", required: true %>
13
+ <%= f.input :password,
14
+ hint: "leave it blank if you don't want to change it",
15
+ required: false
16
+ input_html: { autocomplete: "new-password" } %>
17
+ <%= f.input :password_confirmation,
18
+ required: false,
19
+ input_html: { autocomplete: "new-password" } %>
20
+ <%= f.input :current_password,
21
+ hint: "we need your current password to confirm your changes",
22
+ required: true,
23
+ input_html: { autocomplete: "current-password" } %>
16
24
  </div>
17
25
 
18
26
  <div class="form-actions">
@@ -4,9 +4,17 @@
4
4
  <%= f.error_notification %>
5
5
 
6
6
  <div class="form-inputs">
7
- <%= f.input :email, required: true, autofocus: true %>
8
- <%= f.input :password, required: true, hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length) %>
9
- <%= f.input :password_confirmation, required: true %>
7
+ <%= f.input :email,
8
+ required: true,
9
+ autofocus: true ,
10
+ input_html: { autocomplete: "email" }%>
11
+ <%= f.input :password,
12
+ required: true,
13
+ hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length),
14
+ input_html: { autocomplete: "new-password" } %>
15
+ <%= f.input :password_confirmation,
16
+ required: true,
17
+ input_html: { autocomplete: "new-password" } %>
10
18
  </div>
11
19
 
12
20
  <div class="form-actions">
@@ -2,8 +2,13 @@
2
2
 
3
3
  <%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
4
4
  <div class="form-inputs">
5
- <%= f.input :email, required: false, autofocus: true %>
6
- <%= f.input :password, required: false %>
5
+ <%= f.input :email,
6
+ required: false,
7
+ autofocus: true,
8
+ input_html: { autocomplete: "email" } %>
9
+ <%= f.input :password,
10
+ required: false,
11
+ input_html: { autocomplete: "current-password" } %>
7
12
  <%= f.input :remember_me, as: :boolean if devise_mapping.rememberable? %>
8
13
  </div>
9
14
 
@@ -5,7 +5,10 @@
5
5
  <%= f.full_error :unlock_token %>
6
6
 
7
7
  <div class="form-inputs">
8
- <%= f.input :email, required: true, autofocus: true %>
8
+ <%= f.input :email,
9
+ required: true,
10
+ autofocus: true,
11
+ input_html: { autocomplete: "email" } %>
9
12
  </div>
10
13
 
11
14
  <div class="form-actions">
@@ -337,4 +337,10 @@ class FailureTest < ActiveSupport::TestCase
337
337
  end
338
338
  end
339
339
  end
340
+
341
+ context "Lazy loading" do
342
+ test "loads" do
343
+ assert_equal Devise::FailureApp.new.lazy_loading_works?, "yes it does"
344
+ end
345
+ end
340
346
  end
@@ -263,7 +263,7 @@ class ConfirmationOnChangeTest < Devise::IntegrationTest
263
263
 
264
264
  test 'admin should be able to request a new confirmation after email changed' do
265
265
  admin = create_admin
266
- admin.update_attributes(email: 'new_test@example.com')
266
+ admin.update(email: 'new_test@example.com')
267
267
 
268
268
  visit new_admin_session_path
269
269
  click_link "Didn't receive confirmation instructions?"
@@ -279,7 +279,7 @@ class ConfirmationOnChangeTest < Devise::IntegrationTest
279
279
 
280
280
  test 'admin with valid confirmation token should be able to confirm email after email changed' do
281
281
  admin = create_admin
282
- admin.update_attributes(email: 'new_test@example.com')
282
+ admin.update(email: 'new_test@example.com')
283
283
  assert_equal 'new_test@example.com', admin.unconfirmed_email
284
284
  visit_admin_confirmation_with_token(admin.raw_confirmation_token)
285
285
 
@@ -291,13 +291,13 @@ class ConfirmationOnChangeTest < Devise::IntegrationTest
291
291
 
292
292
  test 'admin with previously valid confirmation token should not be able to confirm email after email changed again' do
293
293
  admin = create_admin
294
- admin.update_attributes(email: 'first_test@example.com')
294
+ admin.update(email: 'first_test@example.com')
295
295
  assert_equal 'first_test@example.com', admin.unconfirmed_email
296
296
 
297
297
  raw_confirmation_token = admin.raw_confirmation_token
298
298
  admin = Admin.find(admin.id)
299
299
 
300
- admin.update_attributes(email: 'second_test@example.com')
300
+ admin.update(email: 'second_test@example.com')
301
301
  assert_equal 'second_test@example.com', admin.unconfirmed_email
302
302
 
303
303
  visit_admin_confirmation_with_token(raw_confirmation_token)
@@ -313,7 +313,7 @@ class ConfirmationOnChangeTest < Devise::IntegrationTest
313
313
 
314
314
  test 'admin email should be unique also within unconfirmed_email' do
315
315
  admin = create_admin
316
- admin.update_attributes(email: 'new_admin_test@example.com')
316
+ admin.update(email: 'new_admin_test@example.com')
317
317
  assert_equal 'new_admin_test@example.com', admin.unconfirmed_email
318
318
 
319
319
  create_second_admin(email: "new_admin_test@example.com")
@@ -74,6 +74,19 @@ class DatabaseAuthenticationTest < Devise::IntegrationTest
74
74
  refute warden.authenticated?(:admin)
75
75
  end
76
76
 
77
+ test 'when in paranoid mode and without a valid e-mail' do
78
+ swap Devise, paranoid: true do
79
+ store_translations :en, devise: { failure: { not_found_in_database: 'Not found in database' } } do
80
+ sign_in_as_user do
81
+ fill_in 'email', with: 'wrongemail@test.com'
82
+ end
83
+
84
+ assert_not_contain 'Not found in database'
85
+ assert_contain 'Invalid Email or password.'
86
+ end
87
+ end
88
+ end
89
+
77
90
  test 'error message is configurable by resource name' do
78
91
  store_translations :en, devise: { failure: { admin: { invalid: "Invalid credentials" } } } do
79
92
  sign_in_as_admin do
@@ -19,7 +19,7 @@ class EmailChangedTest < ActionMailer::TestCase
19
19
  def user
20
20
  @user ||= create_user.tap { |u|
21
21
  @original_user_email = u.email
22
- u.update_attributes!(email: 'new-email@example.com')
22
+ u.update!(email: 'new-email@example.com')
23
23
  }
24
24
  end
25
25
 
@@ -108,7 +108,7 @@ class EmailChangedReconfirmationTest < ActionMailer::TestCase
108
108
  def admin
109
109
  @admin ||= create_admin.tap { |u|
110
110
  @original_admin_email = u.email
111
- u.update_attributes!(email: 'new-email@example.com')
111
+ u.update!(email: 'new-email@example.com')
112
112
  }
113
113
  end
114
114
 
@@ -372,7 +372,7 @@ class ReconfirmableTest < ActiveSupport::TestCase
372
372
  admin = create_admin
373
373
  assert admin.confirm
374
374
  residual_token = admin.confirmation_token
375
- assert admin.update_attributes(email: 'new_test@example.com')
375
+ assert admin.update(email: 'new_test@example.com')
376
376
  assert_not_equal residual_token, admin.confirmation_token
377
377
  end
378
378
 
@@ -381,7 +381,7 @@ class ReconfirmableTest < ActiveSupport::TestCase
381
381
  original_token = admin.confirmation_token
382
382
  assert admin.confirm
383
383
  admin.skip_reconfirmation!
384
- assert admin.update_attributes(email: 'new_test@example.com')
384
+ assert admin.update(email: 'new_test@example.com')
385
385
  assert admin.confirmed?
386
386
  refute admin.pending_reconfirmation?
387
387
  assert_equal original_token, admin.confirmation_token
@@ -392,16 +392,16 @@ class ReconfirmableTest < ActiveSupport::TestCase
392
392
  admin.skip_confirmation_notification!
393
393
 
394
394
  assert_email_not_sent do
395
- admin.update_attributes(email: 'new_test@example.com')
395
+ admin.update(email: 'new_test@example.com')
396
396
  end
397
397
  end
398
398
 
399
399
  test 'should regenerate confirmation token after changing email' do
400
400
  admin = create_admin
401
401
  assert admin.confirm
402
- assert admin.update_attributes(email: 'old_test@example.com')
402
+ assert admin.update(email: 'old_test@example.com')
403
403
  token = admin.confirmation_token
404
- assert admin.update_attributes(email: 'new_test@example.com')
404
+ assert admin.update(email: 'new_test@example.com')
405
405
  assert_not_equal token, admin.confirmation_token
406
406
  end
407
407
 
@@ -409,7 +409,7 @@ class ReconfirmableTest < ActiveSupport::TestCase
409
409
  admin = create_admin
410
410
  assert admin.confirm
411
411
  assert_email_sent "new_test@example.com" do
412
- assert admin.update_attributes(email: 'new_test@example.com')
412
+ assert admin.update(email: 'new_test@example.com')
413
413
  end
414
414
  assert_match "new_test@example.com", ActionMailer::Base.deliveries.last.body.encoded
415
415
  end
@@ -417,7 +417,7 @@ class ReconfirmableTest < ActiveSupport::TestCase
417
417
  test 'should send confirmation instructions by email after changing email from nil' do
418
418
  admin = create_admin(email: nil)
419
419
  assert_email_sent "new_test@example.com" do
420
- assert admin.update_attributes(email: 'new_test@example.com')
420
+ assert admin.update(email: 'new_test@example.com')
421
421
  end
422
422
  assert_match "new_test@example.com", ActionMailer::Base.deliveries.last.body.encoded
423
423
  end
@@ -426,7 +426,7 @@ class ReconfirmableTest < ActiveSupport::TestCase
426
426
  admin = create_admin
427
427
  assert admin.confirm
428
428
  assert_email_not_sent do
429
- assert admin.update_attributes(password: 'newpass', password_confirmation: 'newpass')
429
+ assert admin.update(password: 'newpass', password_confirmation: 'newpass')
430
430
  end
431
431
  end
432
432
 
@@ -442,14 +442,14 @@ class ReconfirmableTest < ActiveSupport::TestCase
442
442
  test 'should stay confirmed when email is changed' do
443
443
  admin = create_admin
444
444
  assert admin.confirm
445
- assert admin.update_attributes(email: 'new_test@example.com')
445
+ assert admin.update(email: 'new_test@example.com')
446
446
  assert admin.confirmed?
447
447
  end
448
448
 
449
449
  test 'should update email only when it is confirmed' do
450
450
  admin = create_admin
451
451
  assert admin.confirm
452
- assert admin.update_attributes(email: 'new_test@example.com')
452
+ assert admin.update(email: 'new_test@example.com')
453
453
  assert_not_equal 'new_test@example.com', admin.email
454
454
  assert admin.confirm
455
455
  assert_equal 'new_test@example.com', admin.email
@@ -458,16 +458,16 @@ class ReconfirmableTest < ActiveSupport::TestCase
458
458
  test 'should not allow admin to get past confirmation email by resubmitting their new address' do
459
459
  admin = create_admin
460
460
  assert admin.confirm
461
- assert admin.update_attributes(email: 'new_test@example.com')
461
+ assert admin.update(email: 'new_test@example.com')
462
462
  assert_not_equal 'new_test@example.com', admin.email
463
- assert admin.update_attributes(email: 'new_test@example.com')
463
+ assert admin.update(email: 'new_test@example.com')
464
464
  assert_not_equal 'new_test@example.com', admin.email
465
465
  end
466
466
 
467
467
  test 'should find a admin by send confirmation instructions with unconfirmed_email' do
468
468
  admin = create_admin
469
469
  assert admin.confirm
470
- assert admin.update_attributes(email: 'new_test@example.com')
470
+ assert admin.update(email: 'new_test@example.com')
471
471
  confirmation_admin = Admin.send_confirmation_instructions(email: admin.unconfirmed_email)
472
472
  assert_equal confirmation_admin, admin
473
473
  end
@@ -536,7 +536,7 @@ class ReconfirmableTest < ActiveSupport::TestCase
536
536
  original_email = admin.email
537
537
 
538
538
  assert_difference 'ActionMailer::Base.deliveries.size', 2 do
539
- assert admin.update_attributes(email: 'new-email@example.com')
539
+ assert admin.update(email: 'new-email@example.com')
540
540
  end
541
541
  assert_equal original_email, ActionMailer::Base.deliveries[-2]['to'].to_s
542
542
  assert_equal 'new-email@example.com', ActionMailer::Base.deliveries[-1]['to'].to_s
@@ -88,6 +88,13 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
88
88
  assert_equal( {'strip_whitespace' => 'strip_whitespace_val', 'do_not_strip_whitespace' => ' do_not_strip_whitespace_val '}, conditions )
89
89
  end
90
90
 
91
+ test 'param filter should not add keys to filtered hash' do
92
+ conditions = { 'present' => 'present_val' }
93
+ conditions.default = ''
94
+ conditions = Devise::ParameterFilter.new(['not_present'], []).filter(conditions)
95
+ assert_equal({ 'present' => 'present_val' }, conditions)
96
+ end
97
+
91
98
  test 'should respond to password and password confirmation' do
92
99
  user = new_user
93
100
  assert user.respond_to?(:password)
@@ -234,7 +241,7 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
234
241
  test 'should not email on password change' do
235
242
  user = create_user
236
243
  assert_email_not_sent do
237
- assert user.update_attributes(password: 'newpass', password_confirmation: 'newpass')
244
+ assert user.update(password: 'newpass', password_confirmation: 'newpass')
238
245
  end
239
246
  end
240
247
 
@@ -243,7 +250,7 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
243
250
  user = create_user
244
251
  original_email = user.email
245
252
  assert_email_sent original_email do
246
- assert user.update_attributes(email: 'new-email@example.com')
253
+ assert user.update(email: 'new-email@example.com')
247
254
  end
248
255
  assert_match original_email, ActionMailer::Base.deliveries.last.body.encoded
249
256
  end
@@ -253,7 +260,7 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
253
260
  swap Devise, send_password_change_notification: true do
254
261
  user = create_user
255
262
  assert_email_sent user.email do
256
- assert user.update_attributes(password: 'newpass', password_confirmation: 'newpass')
263
+ assert user.update(password: 'newpass', password_confirmation: 'newpass')
257
264
  end
258
265
  assert_match user.email, ActionMailer::Base.deliveries.last.body.encoded
259
266
  end
@@ -59,4 +59,22 @@ class TrackableTest < ActiveSupport::TestCase
59
59
 
60
60
  assert_not user.update_tracked_fields!(request)
61
61
  end
62
+
63
+ test 'extract_ip_from should be overridable' do
64
+ class UserWithOverride < User
65
+ protected
66
+ def extract_ip_from(request)
67
+ "127.0.0.2"
68
+ end
69
+ end
70
+
71
+ request = mock
72
+ request.stubs(:remote_ip).returns("127.0.0.1")
73
+ user = UserWithOverride.new
74
+
75
+ user.update_tracked_fields(request)
76
+
77
+ assert_equal "127.0.0.2", user.current_sign_in_ip
78
+ assert_equal "127.0.0.2", user.last_sign_in_ip
79
+ end
62
80
  end
@@ -16,6 +16,34 @@ class ParameterSanitizerTest < ActiveSupport::TestCase
16
16
  assert_equal({ 'email' => 'jose' }, sanitized)
17
17
  end
18
18
 
19
+ test 'permits empty params when received not a hash' do
20
+ sanitizer = sanitizer({ 'user' => 'string' })
21
+ sanitized = sanitizer.sanitize(:sign_in)
22
+
23
+ assert_equal({}, sanitized)
24
+ end
25
+
26
+ test 'does not rise error when received string instead of hash' do
27
+ sanitizer = sanitizer('user' => 'string')
28
+ assert_nothing_raised do
29
+ sanitizer.sanitize(:sign_in)
30
+ end
31
+ end
32
+
33
+ test 'does not rise error when received nil instead of hash' do
34
+ sanitizer = sanitizer('user' => nil)
35
+ assert_nothing_raised do
36
+ sanitizer.sanitize(:sign_in)
37
+ end
38
+ end
39
+
40
+ test 'permits empty params when received nil instead of hash' do
41
+ sanitizer = sanitizer({ 'user' => nil })
42
+ sanitized = sanitizer.sanitize(:sign_in)
43
+
44
+ assert_equal({}, sanitized)
45
+ end
46
+
19
47
  test 'permits the default parameters for sign up' do
20
48
  sanitizer = sanitizer('user' => { 'email' => 'jose', 'role' => 'invalid' })
21
49
  sanitized = sanitizer.sanitize(:sign_up)
@@ -179,4 +179,9 @@ Devise.setup do |config|
179
179
  # manager.failure_app = AnotherApp
180
180
  # manager.default_strategies(scope: :user).unshift :some_external_strategy
181
181
  # end
182
+
183
+ ActiveSupport.on_load(:devise_failure_app) do
184
+ require "lazy_load_test_module"
185
+ include LazyLoadTestModule
186
+ end
182
187
  end
@@ -0,0 +1,5 @@
1
+ module LazyLoadTestModule
2
+ def lazy_loading_works?
3
+ "yes it does"
4
+ end
5
+ end
@@ -32,6 +32,24 @@ class Rails52Config
32
32
  end
33
33
  end
34
34
 
35
+ class Rails52SecretKeyBase
36
+ def credentials
37
+ OpenStruct.new(secret_key_base: nil)
38
+ end
39
+
40
+ def secrets
41
+ OpenStruct.new(secret_key_base: nil)
42
+ end
43
+
44
+ def config
45
+ OpenStruct.new(secret_key_base: nil)
46
+ end
47
+
48
+ def secret_key_base
49
+ 'secret_key_base'
50
+ end
51
+ end
52
+
35
53
  class Rails41Secrets
36
54
  def secrets
37
55
  OpenStruct.new(secret_key_base: 'secrets')
@@ -77,6 +95,12 @@ class SecretKeyFinderTest < ActiveSupport::TestCase
77
95
  assert_equal 'config', secret_key_finder.find
78
96
  end
79
97
 
98
+ test "rails 5.2 uses secret_key_base when config is empty" do
99
+ secret_key_finder = Devise::SecretKeyFinder.new(Rails52SecretKeyBase.new)
100
+
101
+ assert_equal 'secret_key_base', secret_key_finder.find
102
+ end
103
+
80
104
  test "rails 4.1 uses secrets" do
81
105
  secret_key_finder = Devise::SecretKeyFinder.new(Rails41Secrets.new)
82
106