devise 1.3.4 → 1.4.1

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 (74) hide show
  1. data/.travis.yml +3 -2
  2. data/CHANGELOG.rdoc +29 -0
  3. data/Gemfile +10 -7
  4. data/Gemfile.lock +47 -47
  5. data/README.rdoc +2 -2
  6. data/Rakefile +1 -1
  7. data/app/controllers/devise/confirmations_controller.rb +2 -2
  8. data/app/controllers/devise/passwords_controller.rb +10 -2
  9. data/app/controllers/devise/registrations_controller.rb +6 -4
  10. data/app/controllers/devise/unlocks_controller.rb +2 -2
  11. data/app/helpers/devise_helper.rb +1 -1
  12. data/app/mailers/devise/mailer.rb +4 -77
  13. data/config/locales/en.yml +3 -0
  14. data/lib/devise.rb +45 -13
  15. data/lib/devise/controllers/helpers.rb +5 -2
  16. data/lib/devise/controllers/internal_helpers.rb +15 -1
  17. data/lib/devise/controllers/rememberable.rb +1 -1
  18. data/lib/devise/email.rb +23 -0
  19. data/lib/devise/hooks/forgetable.rb +1 -1
  20. data/lib/devise/hooks/trackable.rb +1 -1
  21. data/lib/devise/mailers/helpers.rb +84 -0
  22. data/lib/devise/mapping.rb +23 -7
  23. data/lib/devise/models/authenticatable.rb +14 -6
  24. data/lib/devise/models/database_authenticatable.rb +18 -1
  25. data/lib/devise/models/recoverable.rb +1 -1
  26. data/lib/devise/models/rememberable.rb +7 -5
  27. data/lib/devise/models/validatable.rb +5 -7
  28. data/lib/devise/modules.rb +1 -1
  29. data/lib/devise/omniauth.rb +0 -5
  30. data/lib/devise/omniauth/config.rb +6 -0
  31. data/lib/devise/rails/routes.rb +65 -10
  32. data/lib/devise/strategies/rememberable.rb +2 -7
  33. data/lib/devise/version.rb +1 -1
  34. data/lib/generators/devise/install_generator.rb +2 -2
  35. data/lib/generators/devise/simple_form_for/confirmations/new.html.erb +15 -0
  36. data/lib/generators/devise/simple_form_for/passwords/edit.html.erb +19 -0
  37. data/lib/generators/devise/simple_form_for/passwords/new.html.erb +15 -0
  38. data/lib/generators/devise/simple_form_for/registrations/edit.html.erb +22 -0
  39. data/lib/generators/devise/simple_form_for/registrations/new.html.erb +17 -0
  40. data/lib/generators/devise/simple_form_for/sessions/new.html.erb +15 -0
  41. data/lib/generators/devise/simple_form_for/unlocks/new.html.erb +15 -0
  42. data/lib/generators/devise/views_generator.rb +61 -9
  43. data/lib/generators/templates/devise.rb +13 -3
  44. data/test/controllers/internal_helpers_test.rb +9 -2
  45. data/test/generators/views_generator_test.rb +10 -0
  46. data/test/helpers/devise_helper_test.rb +43 -0
  47. data/test/integration/authenticatable_test.rb +74 -5
  48. data/test/integration/confirmable_test.rb +39 -1
  49. data/test/integration/database_authenticatable_test.rb +22 -0
  50. data/test/integration/http_authenticatable_test.rb +8 -0
  51. data/test/integration/lockable_test.rb +62 -4
  52. data/test/integration/omniauthable_test.rb +1 -3
  53. data/test/integration/recoverable_test.rb +66 -6
  54. data/test/integration/registerable_test.rb +1 -1
  55. data/test/integration/rememberable_test.rb +20 -1
  56. data/test/integration/trackable_test.rb +17 -0
  57. data/test/mapping_test.rb +5 -0
  58. data/test/models/database_authenticatable_test.rb +56 -1
  59. data/test/models/encryptable_test.rb +1 -1
  60. data/test/models/recoverable_test.rb +14 -3
  61. data/test/models/rememberable_test.rb +8 -0
  62. data/test/models/token_authenticatable_test.rb +0 -6
  63. data/test/models/validatable_test.rb +17 -4
  64. data/test/models_test.rb +4 -0
  65. data/test/omniauth/url_helpers_test.rb +4 -0
  66. data/test/rails_app/app/controllers/home_controller.rb +9 -0
  67. data/test/rails_app/app/controllers/users_controller.rb +6 -1
  68. data/test/rails_app/app/views/home/admin_dashboard.html.erb +1 -0
  69. data/test/rails_app/app/views/home/join.html.erb +1 -0
  70. data/test/rails_app/app/views/home/user_dashboard.html.erb +1 -0
  71. data/test/rails_app/config/initializers/devise.rb +6 -0
  72. data/test/rails_app/config/routes.rb +30 -2
  73. data/test/routes_test.rb +54 -0
  74. metadata +21 -4
@@ -35,6 +35,11 @@ Devise.setup do |config|
35
35
  # These keys will be downcased upon creating or modifying a user and when used
36
36
  # to authenticate or find a user. Default is :email.
37
37
  config.case_insensitive_keys = [ :email ]
38
+
39
+ # Configure which authentication keys should have whitespace stripped.
40
+ # These keys will have whitespace before and after removed upon creating or
41
+ # modifying a user and when used to authenticate or find a user. Default is :email.
42
+ config.strip_whitespace_keys = [ :email ]
38
43
 
39
44
  # Tell if authentication through request.params is enabled. True by default.
40
45
  # config.params_authenticatable = true
@@ -48,13 +53,18 @@ Devise.setup do |config|
48
53
  # The realm used in Http Basic Authentication. "Application" by default.
49
54
  # config.http_authentication_realm = "Application"
50
55
 
56
+ # It will change confirmation, password recovery and other workflows
57
+ # to behave the same regardless if the e-mail provided was right or wrong.
58
+ # Does not affect registerable.
59
+ # config.paranoid = true
60
+
51
61
  # ==> Configuration for :database_authenticatable
52
62
  # For bcrypt, this is the cost for hashing the password and defaults to 10. If
53
63
  # using other encryptors, it sets how many times you want the password re-encrypted.
54
64
  config.stretches = 10
55
65
 
56
66
  # Setup a pepper to generate the encrypted password.
57
- # config.pepper = <%= ActiveSupport::SecureRandom.hex(64).inspect %>
67
+ # config.pepper = <%= SecureRandom.hex(64).inspect %>
58
68
 
59
69
  # ==> Configuration for :confirmable
60
70
  # The time you want to give your user to confirm his account. During this time
@@ -174,8 +184,8 @@ Devise.setup do |config|
174
184
  # Explorer requests.
175
185
  # config.navigational_formats = [:"*/*", "*/*", :html]
176
186
 
177
- # The default HTTP method used to sign out a resource. Default is :get.
178
- # config.sign_out_via = :get
187
+ # The default HTTP method used to sign out a resource. Default is :delete.
188
+ config.sign_out_via = :delete
179
189
 
180
190
  # ==> OmniAuth
181
191
  # Add a new OmniAuth provider. Check the wiki for more information on setting
@@ -39,14 +39,21 @@ class HelpersTest < ActionController::TestCase
39
39
  end
40
40
 
41
41
  test 'require no authentication tests current mapping' do
42
- @mock_warden.expects(:authenticated?).with(:user).returns(true)
42
+ @mock_warden.expects(:authenticate?).with(:rememberable, :token_authenticatable, :scope => :user).returns(true)
43
43
  @mock_warden.expects(:user).with(:user).returns(User.new)
44
44
  @controller.expects(:redirect_to).with(root_path)
45
45
  @controller.send :require_no_authentication
46
46
  end
47
47
 
48
+ test 'require no authentication skips if no inputs are available' do
49
+ Devise.mappings[:user].expects(:no_input_strategies).returns([])
50
+ @mock_warden.expects(:authenticate?).never
51
+ @controller.expects(:redirect_to).never
52
+ @controller.send :require_no_authentication
53
+ end
54
+
48
55
  test 'require no authentication sets a flash message' do
49
- @mock_warden.expects(:authenticated?).with(:user).returns(true)
56
+ @mock_warden.expects(:authenticate?).with(:rememberable, :token_authenticatable, :scope => :user).returns(true)
50
57
  @mock_warden.expects(:user).with(:user).returns(User.new)
51
58
  @controller.expects(:redirect_to).with(root_path)
52
59
  @controller.send :require_no_authentication
@@ -18,6 +18,16 @@ class ViewsGeneratorTest < Rails::Generators::TestCase
18
18
  assert_files "admins"
19
19
  end
20
20
 
21
+ test "Assert views with simple form" do
22
+ run_generator %w(-b simple_form_for)
23
+ assert_files
24
+ assert_file "app/views/devise/confirmations/new.html.erb", /simple_form_for/
25
+
26
+ run_generator %w(users -b simple_form_for)
27
+ assert_files "users"
28
+ assert_file "app/views/users/confirmations/new.html.erb", /simple_form_for/
29
+ end
30
+
21
31
  def assert_files(scope = nil, template_engine = nil)
22
32
  scope = "devise" if scope.nil?
23
33
  assert_file "app/views/#{scope}/confirmations/new.html.erb"
@@ -0,0 +1,43 @@
1
+ require 'test_helper'
2
+
3
+ class DeviseHelperTest < ActionController::IntegrationTest
4
+ setup do
5
+ I18n.backend.store_translations :fr,
6
+ {
7
+ :errors => { :messages => { :not_saved => {
8
+ :one => "Erreur lors de l'enregistrement de '%{resource}': 1 erreur.",
9
+ :other => "Erreur lors de l'enregistrement de '%{resource}': %{count} erreurs."
10
+ } } },
11
+ :activerecord => { :models => { :user => "utilisateur" } }
12
+ }
13
+
14
+ I18n.locale = 'fr'
15
+ end
16
+
17
+ teardown do
18
+ I18n.locale = 'en'
19
+ end
20
+
21
+ test 'test errors.messages.not_saved with single error from i18n' do
22
+ get new_user_registration_path
23
+
24
+ fill_in 'password', :with => 'new_user123'
25
+ fill_in 'password confirmation', :with => 'new_user123'
26
+ click_button 'Sign up'
27
+
28
+ assert_have_selector '#error_explanation'
29
+ assert_contain "Erreur lors de l'enregistrement de 'utilisateur': 1 erreur"
30
+ end
31
+
32
+ test 'test errors.messages.not_saved with multiple errors from i18n' do
33
+ get new_user_registration_path
34
+
35
+ fill_in 'email', :with => 'invalid_email'
36
+ fill_in 'password', :with => 'new_user123'
37
+ fill_in 'password confirmation', :with => 'new_user321'
38
+ click_button 'Sign up'
39
+
40
+ assert_have_selector '#error_explanation'
41
+ assert_contain "Erreur lors de l'enregistrement de 'utilisateur': 2 erreurs"
42
+ end
43
+ end
@@ -101,6 +101,54 @@ class AuthenticationSanityTest < ActionController::IntegrationTest
101
101
  assert_contain 'Private!'
102
102
  end
103
103
 
104
+ test 'signed in as admin should get admin dashboard' do
105
+ sign_in_as_admin
106
+ assert warden.authenticated?(:admin)
107
+ assert_not warden.authenticated?(:user)
108
+
109
+ get dashboard_path
110
+
111
+ assert_response :success
112
+ assert_template 'home/admin'
113
+ assert_contain 'Admin dashboard'
114
+ end
115
+
116
+ test 'signed in as user should get user dashboard' do
117
+ sign_in_as_user
118
+ assert warden.authenticated?(:user)
119
+ assert_not warden.authenticated?(:admin)
120
+
121
+ get dashboard_path
122
+
123
+ assert_response :success
124
+ assert_template 'home/user'
125
+ assert_contain 'User dashboard'
126
+ end
127
+
128
+ test 'not signed in should get no dashboard' do
129
+ assert_raises ActionController::RoutingError do
130
+ get dashboard_path
131
+ end
132
+ end
133
+
134
+ test 'signed in user should not see join page' do
135
+ sign_in_as_user
136
+ assert warden.authenticated?(:user)
137
+ assert_not warden.authenticated?(:admin)
138
+
139
+ assert_raises ActionController::RoutingError do
140
+ get join_path
141
+ end
142
+ end
143
+
144
+ test 'not signed in should see join page' do
145
+ get join_path
146
+
147
+ assert_response :success
148
+ assert_template 'home/join'
149
+ assert_contain 'Join'
150
+ end
151
+
104
152
  test 'signed in as user should not be able to access admins actions' do
105
153
  sign_in_as_user
106
154
  assert warden.authenticated?(:user)
@@ -306,6 +354,20 @@ class AuthenticationWithScopesTest < ActionController::IntegrationTest
306
354
  end
307
355
 
308
356
  class AuthenticationOthersTest < ActionController::IntegrationTest
357
+ test 'handles unverified requests gets rid of caches' do
358
+ swap UsersController, :allow_forgery_protection => true do
359
+ post exhibit_user_url(1)
360
+ assert_not warden.authenticated?(:user)
361
+
362
+ sign_in_as_user
363
+ assert warden.authenticated?(:user)
364
+
365
+ post exhibit_user_url(1)
366
+ assert_not warden.authenticated?(:user)
367
+ assert_equal "User is not authenticated", response.body
368
+ end
369
+ end
370
+
309
371
  test 'uses the custom controller with the custom controller view' do
310
372
  get '/admin_area/sign_in'
311
373
  assert_contain 'Sign in'
@@ -314,8 +376,9 @@ class AuthenticationOthersTest < ActionController::IntegrationTest
314
376
  end
315
377
 
316
378
  test 'render 404 on roles without routes' do
317
- get '/admin_area/password/new'
318
- assert_equal 404, response.status
379
+ assert_raise ActionController::RoutingError do
380
+ get '/admin_area/password/new'
381
+ end
319
382
  end
320
383
 
321
384
  test 'does not intercept Rails 401 responses' do
@@ -446,7 +509,9 @@ class AuthenticationSignOutViaTest < ActionController::IntegrationTest
446
509
 
447
510
  test 'do not allow sign out via get when sign_out_via provides only delete' do
448
511
  sign_in!(:sign_out_via_delete)
449
- get destroy_sign_out_via_delete_session_path
512
+ assert_raise ActionController::RoutingError do
513
+ get destroy_sign_out_via_delete_session_path
514
+ end
450
515
  assert warden.authenticated?(:sign_out_via_delete)
451
516
  end
452
517
 
@@ -458,7 +523,9 @@ class AuthenticationSignOutViaTest < ActionController::IntegrationTest
458
523
 
459
524
  test 'do not allow sign out via get when sign_out_via provides only post' do
460
525
  sign_in!(:sign_out_via_post)
461
- get destroy_sign_out_via_delete_session_path
526
+ assert_raise ActionController::RoutingError do
527
+ get destroy_sign_out_via_delete_session_path
528
+ end
462
529
  assert warden.authenticated?(:sign_out_via_post)
463
530
  end
464
531
 
@@ -476,7 +543,9 @@ class AuthenticationSignOutViaTest < ActionController::IntegrationTest
476
543
 
477
544
  test 'do not allow sign out via get when sign_out_via provides delete and post' do
478
545
  sign_in!(:sign_out_via_delete_or_post)
479
- get destroy_sign_out_via_delete_or_post_session_path
546
+ assert_raise ActionController::RoutingError do
547
+ get destroy_sign_out_via_delete_or_post_session_path
548
+ end
480
549
  assert warden.authenticated?(:sign_out_via_delete_or_post)
481
550
  end
482
551
  end
@@ -106,7 +106,7 @@ class ConfirmationTest < ActionController::IntegrationTest
106
106
  user = create_user(:confirm => false)
107
107
  post user_confirmation_path(:format => 'xml'), :user => { :email => user.email }
108
108
  assert_response :success
109
- assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user>)
109
+ assert_equal response.body, {}.to_xml
110
110
  end
111
111
 
112
112
  test 'resent confirmation token with invalid E-Mail in XML format should return invalid response' do
@@ -129,4 +129,42 @@ class ConfirmationTest < ActionController::IntegrationTest
129
129
  assert_response :unprocessable_entity
130
130
  assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<errors>)
131
131
  end
132
+
133
+ test 'request an account confirmation account with JSON, should return an empty JSON' do
134
+ user = create_user(:confirm => false)
135
+
136
+ post user_confirmation_path, :user => { :email => user.email }, :format => :json
137
+ assert_response :success
138
+ assert_equal response.body, {}.to_json
139
+ end
140
+
141
+ test "when in paranoid mode and with a valid e-mail, should not say that the e-mail is valid" do
142
+ swap Devise, :paranoid => true do
143
+ user = create_user(:confirm => false)
144
+ visit new_user_session_path
145
+
146
+ click_link "Didn't receive confirmation instructions?"
147
+ fill_in 'email', :with => user.email
148
+ click_button 'Resend confirmation instructions'
149
+
150
+ assert_contain "If your e-mail exists on our database, you will receive an email with instructions about how to confirm your account in a few minutes."
151
+ assert_current_url "/users/confirmation"
152
+ end
153
+ end
154
+
155
+ test "when in paranoid mode and with a invalid e-mail, should not say that the e-mail is invalid" do
156
+ swap Devise, :paranoid => true do
157
+ visit new_user_session_path
158
+
159
+ click_link "Didn't receive confirmation instructions?"
160
+ fill_in 'email', :with => "idonthavethisemail@gmail.com"
161
+ click_button 'Resend confirmation instructions'
162
+
163
+ assert_not_contain "1 error prohibited this user from being saved:"
164
+ assert_not_contain "Email not found"
165
+
166
+ assert_contain "If your e-mail exists on our database, you will receive an email with instructions about how to confirm your account in a few minutes."
167
+ assert_current_url "/users/confirmation"
168
+ end
169
+ end
132
170
  end
@@ -22,6 +22,28 @@ class DatabaseAuthenticationTest < ActionController::IntegrationTest
22
22
  assert_not warden.authenticated?(:user)
23
23
  end
24
24
  end
25
+
26
+ test 'sign in with email including extra spaces should succeed when email is in the list of strip whitespace keys' do
27
+ create_user(:email => ' foo@bar.com ')
28
+
29
+ sign_in_as_user do
30
+ fill_in 'email', :with => 'foo@bar.com'
31
+ end
32
+
33
+ assert warden.authenticated?(:user)
34
+ end
35
+
36
+ test 'sign in with email including extra spaces should fail when email is NOT the list of strip whitespace keys' do
37
+ swap Devise, :strip_whitespace_keys => [] do
38
+ create_user(:email => 'foo@bar.com')
39
+
40
+ sign_in_as_user do
41
+ fill_in 'email', :with => ' foo@bar.com '
42
+ end
43
+
44
+ assert_not warden.authenticated?(:user)
45
+ end
46
+ end
25
47
 
26
48
  test 'sign in should not authenticate if not using proper authentication keys' do
27
49
  swap Devise, :authentication_keys => [:username] do
@@ -1,6 +1,14 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class HttpAuthenticationTest < ActionController::IntegrationTest
4
+ test 'handles unverified requests gets rid of caches but continues signed in' do
5
+ swap UsersController, :allow_forgery_protection => true do
6
+ create_user
7
+ post exhibit_user_url(1), {}, "HTTP_AUTHORIZATION" => "Basic #{ActiveSupport::Base64.encode64("user@test.com:123456")}"
8
+ assert warden.authenticated?(:user)
9
+ assert_equal "User is authenticated", response.body
10
+ end
11
+ end
4
12
 
5
13
  test 'sign in should authenticate with http' do
6
14
  sign_in_as_new_user_with_http
@@ -37,7 +37,7 @@ class LockTest < ActionController::IntegrationTest
37
37
  end
38
38
 
39
39
  test 'unlocked pages should not be available if email strategy is disabled' do
40
- visit "/admins/sign_in"
40
+ visit "/admin_area/sign_in"
41
41
 
42
42
  assert_raise Webrat::NotFoundError do
43
43
  click_link "Didn't receive unlock instructions?"
@@ -47,8 +47,9 @@ class LockTest < ActionController::IntegrationTest
47
47
  visit new_admin_unlock_path
48
48
  end
49
49
 
50
- visit "/admins/unlock/new"
51
- assert_response :not_found
50
+ assert_raise ActionController::RoutingError do
51
+ visit "/admin_area/unlock/new"
52
+ end
52
53
  end
53
54
 
54
55
  test 'user with invalid unlock token should not be able to unlock an account' do
@@ -112,7 +113,7 @@ class LockTest < ActionController::IntegrationTest
112
113
 
113
114
  post user_unlock_path(:format => 'xml'), :user => {:email => user.email}
114
115
  assert_response :success
115
- assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user>)
116
+ assert_equal response.body, {}.to_xml
116
117
  assert_equal 1, ActionMailer::Base.deliveries.size
117
118
  end
118
119
 
@@ -140,4 +141,61 @@ class LockTest < ActionController::IntegrationTest
140
141
  assert_response :unprocessable_entity
141
142
  assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<errors>)
142
143
  end
144
+
145
+ test "when using json to ask a unlock request, should not return the user" do
146
+ user = create_user(:locked => true)
147
+ post user_unlock_path(:format => "json", :user => {:email => user.email})
148
+ assert_response :success
149
+ assert_equal response.body, {}.to_json
150
+ end
151
+
152
+ test "in paranoid mode, when trying to unlock an user that exists it should not say that it exists if it is locked" do
153
+ swap Devise, :paranoid => true do
154
+ user = create_user(:locked => true)
155
+
156
+ visit new_user_session_path
157
+ click_link "Didn't receive unlock instructions?"
158
+
159
+ fill_in 'email', :with => user.email
160
+ click_button 'Resend unlock instructions'
161
+
162
+ assert_current_url "/users/unlock"
163
+
164
+ assert_contain "If your account exists, you will receive an email with instructions about how to unlock it in a few minutes."
165
+ end
166
+ end
167
+
168
+ test "in paranoid mode, when trying to unlock an user that exists it should not say that it exists if it is not locked" do
169
+ swap Devise, :paranoid => true do
170
+ user = create_user(:locked => false)
171
+
172
+ visit new_user_session_path
173
+ click_link "Didn't receive unlock instructions?"
174
+
175
+ fill_in 'email', :with => user.email
176
+ click_button 'Resend unlock instructions'
177
+
178
+ assert_current_url "/users/unlock"
179
+
180
+ assert_contain "If your account exists, you will receive an email with instructions about how to unlock it in a few minutes."
181
+ end
182
+ end
183
+
184
+ test "in paranoid mode, when trying to unlock an user that does not exists it should not say that it does not exists" do
185
+ swap Devise, :paranoid => true do
186
+ visit new_user_session_path
187
+ click_link "Didn't receive unlock instructions?"
188
+
189
+ fill_in 'email', :with => "arandomemail@hotmail.com"
190
+ click_button 'Resend unlock instructions'
191
+
192
+ assert_not_contain "1 error prohibited this user from being saved:"
193
+ assert_not_contain "Email not found"
194
+ assert_current_url "/users/unlock"
195
+
196
+ assert_contain "If your account exists, you will receive an email with instructions about how to unlock it in a few minutes."
197
+
198
+ end
199
+ end
200
+
143
201
  end
@@ -114,9 +114,7 @@ class OmniauthableIntegrationTest < ActionController::IntegrationTest
114
114
  test "generates a proper link when SCRIPT_NAME is set" do
115
115
  header 'SCRIPT_NAME', '/q'
116
116
  visit "/users/sign_in"
117
- click_link "Sign in with Facebook"
118
-
119
- assert_equal '/q/users/auth/facebook', current_url
117
+ assert_select "a", :href => "/q/users/auth/facebook"
120
118
  end
121
119
 
122
120
  test "handles callback error parameter according to the specification" do