devise 2.2.8 → 3.0.0.rc

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 (61) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +2 -17
  3. data/CHANGELOG.rdoc +4 -20
  4. data/Gemfile +3 -4
  5. data/Gemfile.lock +68 -64
  6. data/README.md +50 -30
  7. data/app/controllers/devise/confirmations_controller.rb +1 -2
  8. data/app/controllers/devise/passwords_controller.rb +1 -1
  9. data/app/controllers/devise/registrations_controller.rb +13 -6
  10. data/app/controllers/devise/sessions_controller.rb +5 -1
  11. data/app/controllers/devise/unlocks_controller.rb +1 -1
  12. data/app/controllers/devise_controller.rb +4 -21
  13. data/devise.gemspec +1 -1
  14. data/gemfiles/{Gemfile.rails-3.1.x → Gemfile.rails-3.2.x} +3 -7
  15. data/gemfiles/{Gemfile.rails-3.1.x.lock → Gemfile.rails-3.2.x.lock} +47 -58
  16. data/lib/devise.rb +8 -10
  17. data/lib/devise/controllers/helpers.rb +11 -0
  18. data/lib/devise/controllers/rememberable.rb +0 -1
  19. data/lib/devise/models/authenticatable.rb +0 -1
  20. data/lib/devise/models/confirmable.rb +5 -0
  21. data/lib/devise/parameter_sanitizer.rb +59 -0
  22. data/lib/devise/rails/warden_compat.rb +2 -9
  23. data/lib/devise/strategies/database_authenticatable.rb +3 -6
  24. data/lib/devise/version.rb +1 -1
  25. data/lib/generators/active_record/devise_generator.rb +1 -4
  26. data/lib/generators/templates/devise.rb +0 -6
  27. data/test/controllers/helpers_test.rb +1 -1
  28. data/test/controllers/internal_helpers_test.rb +13 -3
  29. data/test/controllers/passwords_controller_test.rb +1 -1
  30. data/test/generators/active_record_generator_test.rb +1 -3
  31. data/test/integration/authenticatable_test.rb +3 -17
  32. data/test/integration/http_authenticatable_test.rb +1 -1
  33. data/test/integration/recoverable_test.rb +11 -1
  34. data/test/integration/registerable_test.rb +8 -6
  35. data/test/integration/rememberable_test.rb +13 -15
  36. data/test/models/database_authenticatable_test.rb +0 -13
  37. data/test/models/validatable_test.rb +12 -2
  38. data/test/omniauth/url_helpers_test.rb +4 -1
  39. data/test/orm/active_record.rb +1 -0
  40. data/test/parameter_sanitizer_test.rb +51 -0
  41. data/test/rails_app/Rakefile +0 -4
  42. data/test/rails_app/app/mongoid/shim.rb +2 -3
  43. data/test/rails_app/bin/bundle +3 -0
  44. data/test/rails_app/bin/rails +4 -0
  45. data/test/rails_app/bin/rake +4 -0
  46. data/test/rails_app/config/application.rb +1 -2
  47. data/test/rails_app/config/boot.rb +3 -3
  48. data/test/rails_app/config/environment.rb +2 -2
  49. data/test/rails_app/config/environments/development.rb +23 -7
  50. data/test/rails_app/config/environments/production.rb +68 -17
  51. data/test/rails_app/config/environments/test.rb +18 -15
  52. data/test/rails_app/config/initializers/secret_token.rb +8 -2
  53. data/test/rails_app/config/initializers/session_store.rb +1 -0
  54. data/test/rails_app/config/routes.rb +1 -1
  55. data/test/rails_app/lib/shared_user.rb +0 -1
  56. data/test/routes_test.rb +22 -20
  57. data/test/test_helper.rb +7 -0
  58. data/test/test_models.rb +0 -1
  59. metadata +31 -27
  60. data/lib/devise/hooks/csrf_cleaner.rb +0 -5
  61. data/test/rails_app/script/rails +0 -10
@@ -5,16 +5,13 @@ module Devise
5
5
  # Default strategy for signing in a user, based on his email and password in the database.
6
6
  class DatabaseAuthenticatable < Authenticatable
7
7
  def authenticate!
8
- resource = valid_password? && mapping.to.find_for_database_authentication(authentication_hash)
9
- encrypted = false
8
+ resource = valid_password? && mapping.to.find_for_database_authentication(authentication_hash)
9
+ return fail(:not_found_in_database) unless resource
10
10
 
11
- if validate(resource){ encrypted = true; resource.valid_password?(password) }
11
+ if validate(resource){ resource.valid_password?(password) }
12
12
  resource.after_database_authentication
13
13
  success!(resource)
14
14
  end
15
-
16
- mapping.to.new.password = password if !encrypted && Devise.paranoid
17
- fail(:not_found_in_database) unless resource
18
15
  end
19
16
  end
20
17
  end
@@ -1,3 +1,3 @@
1
1
  module Devise
2
- VERSION = "2.2.8".freeze
2
+ VERSION = "3.0.0.rc".freeze
3
3
  end
@@ -22,10 +22,7 @@ module ActiveRecord
22
22
  end
23
23
 
24
24
  def inject_devise_content
25
- content = model_contents + <<CONTENT
26
- # Setup accessible (or protected) attributes for your model
27
- attr_accessible :email, :password, :password_confirmation, :remember_me
28
- CONTENT
25
+ content = model_contents
29
26
 
30
27
  class_path = if namespaced?
31
28
  class_name.to_s.split("::")
@@ -76,12 +76,6 @@ Devise.setup do |config|
76
76
  # passing :skip => :sessions to `devise_for` in your config/routes.rb
77
77
  config.skip_session_storage = [:http_auth]
78
78
 
79
- # By default, Devise cleans up the CSRF token on authentication to
80
- # avoid CSRF token fixation attacks. This means that, when using AJAX
81
- # requests for sign in and sign up, you need to get a new CSRF token
82
- # from the server. You can disable this option at your own risk.
83
- # config.clean_up_csrf_token_on_authentication = true
84
-
85
79
  # ==> Configuration for :database_authenticatable
86
80
  # For bcrypt, this is the cost for hashing the password and defaults to 10. If
87
81
  # using other encryptors, it sets how many times you want the password re-encrypted.
@@ -202,7 +202,7 @@ class ControllerAuthenticatableTest < ActionController::TestCase
202
202
 
203
203
  test 'sign in and redirect uses the stored location' do
204
204
  user = User.new
205
- @controller.session[:user_return_to] = "/foo.bar"
205
+ @controller.session[:"user_return_to"] = "/foo.bar"
206
206
  @mock_warden.expects(:user).with(:user).returns(nil)
207
207
  @mock_warden.expects(:set_user).with(user, :scope => :user).returns(true)
208
208
  @controller.expects(:redirect_to).with("/foo.bar")
@@ -34,10 +34,20 @@ class HelpersTest < ActionController::TestCase
34
34
  end
35
35
 
36
36
  test 'get resource params from request params using resource name as key' do
37
- user_params = {'name' => 'Shirley Templar'}
38
- @controller.stubs(:params).returns(HashWithIndifferentAccess.new({'user' => user_params}))
37
+ user_params = {'email' => 'shirley@templar.com'}
39
38
 
40
- assert_equal user_params, @controller.resource_params
39
+ params = if Devise.rails4?
40
+ # Stub controller name so strong parameters can filter properly.
41
+ # DeviseController does not allow any parameters by default.
42
+ @controller.stubs(:controller_name).returns(:sessions_controller)
43
+
44
+ ActionController::Parameters.new({'user' => user_params})
45
+ else
46
+ HashWithIndifferentAccess.new({'user' => user_params})
47
+ end
48
+ @controller.stubs(:params).returns(params)
49
+
50
+ assert_equal user_params, @controller.send(:resource_params)
41
51
  end
42
52
 
43
53
  test 'resources methods are not controller actions' do
@@ -7,7 +7,7 @@ class PasswordsControllerTest < ActionController::TestCase
7
7
  def setup
8
8
  request.env["devise.mapping"] = Devise.mappings[:user]
9
9
 
10
- @user = create_user.tap(&:confirm!)
10
+ @user = create_user
11
11
  @user.send_reset_password_instructions
12
12
  end
13
13
 
@@ -10,13 +10,11 @@ if DEVISE_ORM == :active_record
10
10
 
11
11
  test "all files are properly created with rails31 migration syntax" do
12
12
  run_generator %w(monster)
13
- assert_file "app/models/monster.rb", /devise/, /attr_accessible (:[a-z_]+(, )?)+/
14
13
  assert_migration "db/migrate/devise_create_monsters.rb", /def change/
15
14
  end
16
15
 
17
16
  test "all files for namespaced model are properly created" do
18
17
  run_generator %w(admin/monster)
19
- assert_file "app/models/admin/monster.rb", /devise/, /attr_accessible (:[a-z_]+(, )?)+/
20
18
  assert_migration "db/migrate/devise_create_admin_monsters.rb", /def change/
21
19
  end
22
20
 
@@ -68,7 +66,7 @@ if DEVISE_ORM == :active_record
68
66
  simulate_inside_engine(RailsEngine::Engine, RailsEngine) do
69
67
  run_generator ["monster"]
70
68
 
71
- assert_file "app/models/rails_engine/monster.rb", /devise/,/attr_accessible (:[a-z_]+(, )?)+/
69
+ assert_file "app/models/rails_engine/monster.rb", /devise/
72
70
  end
73
71
  end
74
72
  end
@@ -191,7 +191,7 @@ class AuthenticationRoutesRestrictions < ActionDispatch::IntegrationTest
191
191
  get dashboard_path
192
192
 
193
193
  assert_response :success
194
- assert_template 'home/admin'
194
+ assert_template 'home/admin_dashboard'
195
195
  assert_contain 'Admin dashboard'
196
196
  end
197
197
 
@@ -203,7 +203,7 @@ class AuthenticationRoutesRestrictions < ActionDispatch::IntegrationTest
203
203
  get dashboard_path
204
204
 
205
205
  assert_response :success
206
- assert_template 'home/user'
206
+ assert_template 'home/user_dashboard'
207
207
  assert_contain 'User dashboard'
208
208
  end
209
209
 
@@ -327,20 +327,6 @@ class AuthenticationSessionTest < ActionDispatch::IntegrationTest
327
327
  assert_redirected_to new_user_session_path
328
328
  end
329
329
 
330
- test 'refreshes _csrf_token' do
331
- ApplicationController.allow_forgery_protection = true
332
-
333
- begin
334
- get new_user_session_path
335
- token = request.session[:_csrf_token]
336
-
337
- sign_in_as_user
338
- assert_not_equal request.session[:_csrf_token], token
339
- ensure
340
- ApplicationController.allow_forgery_protection = false
341
- end
342
- end
343
-
344
330
  test 'allows session to be set for a given scope' do
345
331
  sign_in_as_user
346
332
  get '/users'
@@ -433,7 +419,7 @@ end
433
419
 
434
420
  class AuthenticationOthersTest < ActionDispatch::IntegrationTest
435
421
  test 'handles unverified requests gets rid of caches' do
436
- swap ApplicationController, :allow_forgery_protection => true do
422
+ swap UsersController, :allow_forgery_protection => true do
437
423
  post exhibit_user_url(1)
438
424
  assert_not warden.authenticated?(:user)
439
425
 
@@ -2,7 +2,7 @@ require 'test_helper'
2
2
 
3
3
  class HttpAuthenticationTest < ActionDispatch::IntegrationTest
4
4
  test 'handles unverified requests gets rid of caches but continues signed in' do
5
- swap ApplicationController, :allow_forgery_protection => true do
5
+ swap UsersController, :allow_forgery_protection => true do
6
6
  create_user
7
7
  post exhibit_user_url(1), {}, "HTTP_AUTHORIZATION" => "Basic #{Base64.encode64("user@test.com:12345678")}"
8
8
  assert warden.authenticated?(:user)
@@ -153,7 +153,8 @@ class PasswordTest < ActionDispatch::IntegrationTest
153
153
  assert_response :success
154
154
  assert_current_url '/users/password'
155
155
  assert_have_selector '#error_explanation'
156
- assert_contain 'Password doesn\'t match confirmation'
156
+ assert_contain Devise.rails4? ?
157
+ "Password confirmation doesn't match Password" : "Password doesn't match confirmation"
157
158
  assert_not user.reload.valid_password?('987654321')
158
159
  end
159
160
 
@@ -229,6 +230,15 @@ class PasswordTest < ActionDispatch::IntegrationTest
229
230
  end
230
231
  end
231
232
 
233
+ test 'sign in user automatically and confirm after changing its password if it\'s not confirmed' do
234
+ user = create_user(:confirm => false)
235
+ request_forgot_password
236
+ reset_password :reset_password_token => user.reload.reset_password_token
237
+
238
+ assert warden.authenticated?(:user)
239
+ assert user.reload.confirmed?
240
+ end
241
+
232
242
  test 'reset password request with valid E-Mail in XML format should return valid response' do
233
243
  create_user
234
244
  post user_password_path(:format => 'xml'), :user => {:email => "user@test.com"}
@@ -17,7 +17,7 @@ class RegistrationTest < ActionDispatch::IntegrationTest
17
17
  assert warden.authenticated?(:admin)
18
18
  assert_current_url "/admin_area/home"
19
19
 
20
- admin = Admin.last :order => "id"
20
+ admin = Admin.order(:id).last
21
21
  assert_equal admin.email, 'new_user@test.com'
22
22
  end
23
23
 
@@ -56,7 +56,7 @@ class RegistrationTest < ActionDispatch::IntegrationTest
56
56
 
57
57
  assert_not warden.authenticated?(:user)
58
58
 
59
- user = User.last :order => "id"
59
+ user = User.order(:id).last
60
60
  assert_equal user.email, 'new_user@test.com'
61
61
  assert_not user.confirmed?
62
62
  end
@@ -100,7 +100,8 @@ class RegistrationTest < ActionDispatch::IntegrationTest
100
100
  assert_template 'registrations/new'
101
101
  assert_have_selector '#error_explanation'
102
102
  assert_contain "Email is invalid"
103
- assert_contain "Password doesn't match confirmation"
103
+ assert_contain Devise.rails4? ?
104
+ "Password confirmation doesn't match Password" : "Password doesn't match confirmation"
104
105
  assert_contain "2 errors prohibited"
105
106
  assert_nil User.first
106
107
 
@@ -206,7 +207,8 @@ class RegistrationTest < ActionDispatch::IntegrationTest
206
207
  fill_in 'current password', :with => '12345678'
207
208
  click_button 'Update'
208
209
 
209
- assert_contain "Password doesn't match confirmation"
210
+ assert_contain Devise.rails4? ?
211
+ "Password confirmation doesn't match Password" : "Password doesn't match confirmation"
210
212
  assert_not User.first.valid_password?('pas123')
211
213
  end
212
214
 
@@ -251,7 +253,7 @@ class RegistrationTest < ActionDispatch::IntegrationTest
251
253
  assert_response :success
252
254
  assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<admin>)
253
255
 
254
- admin = Admin.last :order => "id"
256
+ admin = Admin.order(:id).last
255
257
  assert_equal admin.email, 'new_user@test.com'
256
258
  end
257
259
 
@@ -260,7 +262,7 @@ class RegistrationTest < ActionDispatch::IntegrationTest
260
262
  assert_response :success
261
263
  assert response.body.include? %(<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user>)
262
264
 
263
- user = User.last :order => "id"
265
+ user = User.order(:id).last
264
266
  assert_equal user.email, 'new_user@test.com'
265
267
  end
266
268
 
@@ -30,8 +30,8 @@ class RememberMeTest < ActionDispatch::IntegrationTest
30
30
  assert_nil request.cookies["remember_user_cookie"]
31
31
  end
32
32
 
33
- test 'handle unverified requests gets rid of caches' do
34
- swap ApplicationController, :allow_forgery_protection => true do
33
+ test 'handles unverified requests gets rid of caches' do
34
+ swap UsersController, :allow_forgery_protection => true do
35
35
  post exhibit_user_url(1)
36
36
  assert_not warden.authenticated?(:user)
37
37
 
@@ -42,21 +42,9 @@ class RememberMeTest < ActionDispatch::IntegrationTest
42
42
  end
43
43
  end
44
44
 
45
- test 'handle unverified requests does not create cookies on sign in' do
46
- swap ApplicationController, :allow_forgery_protection => true do
47
- get new_user_session_path
48
- assert request.session[:_csrf_token]
49
-
50
- post user_session_path, :authenticity_token => "oops", :user =>
51
- { :email => "jose.valim@gmail.com", :password => "123456", :remember_me => "1" }
52
- assert_not warden.authenticated?(:user)
53
- assert_not request.cookies['remember_user_token']
54
- end
55
- end
56
-
57
45
  test 'generate remember token after sign in' do
58
46
  sign_in_as_user :remember_me => true
59
- assert request.cookies['remember_user_token']
47
+ assert request.cookies["remember_user_token"]
60
48
  end
61
49
 
62
50
  test 'generate remember token after sign in setting cookie options' do
@@ -102,6 +90,16 @@ class RememberMeTest < ActionDispatch::IntegrationTest
102
90
  assert_redirected_to root_path
103
91
  end
104
92
 
93
+ test 'cookies are destroyed on unverified requests' do
94
+ swap ApplicationController, :allow_forgery_protection => true do
95
+ create_user_and_remember
96
+ get users_path
97
+ assert warden.authenticated?(:user)
98
+ post root_path, :authenticity_token => 'INVALID'
99
+ assert_not warden.authenticated?(:user)
100
+ end
101
+ end
102
+
105
103
  test 'does not extend remember period through sign in' do
106
104
  swap Devise, :extend_remember_period => true, :remember_for => 1.year do
107
105
  user = create_user
@@ -123,13 +123,6 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
123
123
  assert user.reload.valid_password?('pass4321')
124
124
  end
125
125
 
126
- test 'should update password with valid current password and :as option' do
127
- user = create_user
128
- assert user.update_with_password(:current_password => '12345678',
129
- :password => 'pass4321', :password_confirmation => 'pass4321', :as => :admin)
130
- assert user.reload.valid_password?('pass4321')
131
- end
132
-
133
126
  test 'should add an error to current password when it is invalid' do
134
127
  user = create_user
135
128
  assert_not user.update_with_password(:current_password => 'other',
@@ -182,12 +175,6 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
182
175
  assert_equal 'new@example.com', user.email
183
176
  end
184
177
 
185
- test 'should update the user without password with :as option' do
186
- user = create_user
187
- user.update_without_password(:email => 'new@example.com', :as => :admin)
188
- assert_equal 'new@example.com', user.email
189
- end
190
-
191
178
  test 'should not update password without password' do
192
179
  user = create_user
193
180
  user.update_without_password(:password => 'pass4321', :password_confirmation => 'pass4321')
@@ -56,7 +56,12 @@ class ValidatableTest < ActiveSupport::TestCase
56
56
  test 'should require confirmation to be set when creating a new record' do
57
57
  user = new_user(:password => 'new_password', :password_confirmation => 'blabla')
58
58
  assert user.invalid?
59
- assert_equal 'doesn\'t match confirmation', user.errors[:password].join
59
+
60
+ if Devise.rails4?
61
+ assert_equal 'doesn\'t match Password', user.errors[:password_confirmation].join
62
+ else
63
+ assert_equal 'doesn\'t match confirmation', user.errors[:password].join
64
+ end
60
65
  end
61
66
 
62
67
  test 'should require password when updating/resetting password' do
@@ -73,7 +78,12 @@ class ValidatableTest < ActiveSupport::TestCase
73
78
  user = create_user
74
79
  user.password_confirmation = 'another_password'
75
80
  assert user.invalid?
76
- assert_equal 'doesn\'t match confirmation', user.errors[:password].join
81
+
82
+ if Devise.rails4?
83
+ assert_equal 'doesn\'t match Password', user.errors[:password_confirmation].join
84
+ else
85
+ assert_equal 'doesn\'t match confirmation', user.errors[:password].join
86
+ end
77
87
  end
78
88
 
79
89
  test 'should require a password with minimum of 6 characters' do
@@ -1,6 +1,9 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class OmniAuthRoutesTest < ActionController::TestCase
4
+ ExpectedUrlGeneratiorError = Devise.rails4? ?
5
+ ActionController::UrlGenerationError : ActionController::RoutingError
6
+
4
7
  tests ApplicationController
5
8
 
6
9
  def assert_path(action, provider, with_param=true)
@@ -30,7 +33,7 @@ class OmniAuthRoutesTest < ActionController::TestCase
30
33
  test 'should generate authorization path' do
31
34
  assert_match "/users/auth/facebook", @controller.omniauth_authorize_path(:user, :facebook)
32
35
 
33
- assert_raise ActionController::RoutingError do
36
+ assert_raise ExpectedUrlGeneratiorError do
34
37
  @controller.omniauth_authorize_path(:user, :github)
35
38
  end
36
39
  end
@@ -1,5 +1,6 @@
1
1
  ActiveRecord::Migration.verbose = false
2
2
  ActiveRecord::Base.logger = Logger.new(nil)
3
+ ActiveRecord::Base.include_root_in_json = true
3
4
 
4
5
  ActiveRecord::Migrator.migrate(File.expand_path("../../rails_app/db/migrate/", __FILE__))
5
6
 
@@ -0,0 +1,51 @@
1
+ require 'test_helper'
2
+ require 'devise/parameter_sanitizer'
3
+
4
+ class BaseSanitizerTest < ActiveSupport::TestCase
5
+ def sanitizer
6
+ Devise::BaseSanitizer.new(User, :user, { user: { "email" => "jose" } })
7
+ end
8
+
9
+ test 'returns chosen params' do
10
+ assert_equal({ "email" => "jose" }, sanitizer.for(:sign_in))
11
+ end
12
+ end
13
+
14
+ if defined?(ActionController::StrongParameters)
15
+ require 'active_model/forbidden_attributes_protection'
16
+
17
+ class ParameterSanitizerTest < ActiveSupport::TestCase
18
+ def sanitizer(params)
19
+ params = ActionController::Parameters.new(params)
20
+ Devise::ParameterSanitizer.new(User, :user, params)
21
+ end
22
+
23
+ test 'filters some parameters on sign in by default' do
24
+ sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid" })
25
+ assert_equal({ "email" => "jose" }, sanitizer.for(:sign_in))
26
+ end
27
+
28
+ test 'filters some parameters on sign up by default' do
29
+ sanitizer = sanitizer(user: { "email" => "jose", "role" => "invalid" })
30
+ assert_equal({ "email" => "jose" }, sanitizer.for(:sign_up))
31
+ end
32
+
33
+ test 'filters some parameters on account update by default' do
34
+ sanitizer = sanitizer(user: { "email" => "jose", "role" => "invalid" })
35
+ assert_equal({ "email" => "jose" }, sanitizer.for(:account_update))
36
+ end
37
+
38
+ test 'allows custom hooks' do
39
+ sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid" })
40
+ sanitizer.for(:sign_in) { |user| user.permit(:email, :password) }
41
+ assert_equal({ "email" => "jose", "password" => "invalid" }, sanitizer.for(:sign_in))
42
+ end
43
+
44
+ test 'raises on unknown hooks' do
45
+ sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid" })
46
+ assert_raise NotImplementedError do
47
+ sanitizer.for(:unknown)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -3,8 +3,4 @@
3
3
 
4
4
  require File.expand_path('../config/application', __FILE__)
5
5
 
6
- require 'rake'
7
- require 'rake/testtask'
8
- require 'rake/rdoctask'
9
-
10
6
  Rails.application.load_tasks