devise 2.0.6 → 2.1.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 (68) hide show
  1. data/.travis.yml +0 -1
  2. data/CHANGELOG.rdoc +12 -6
  3. data/Gemfile.lock +3 -3
  4. data/README.md +9 -15
  5. data/app/controllers/devise_controller.rb +2 -3
  6. data/app/views/devise/_links.erb +3 -25
  7. data/app/views/devise/confirmations/new.html.erb +1 -1
  8. data/app/views/devise/passwords/edit.html.erb +1 -1
  9. data/app/views/devise/passwords/new.html.erb +1 -1
  10. data/app/views/devise/registrations/new.html.erb +1 -1
  11. data/app/views/devise/sessions/new.html.erb +1 -1
  12. data/app/views/devise/shared/_links.erb +25 -3
  13. data/app/views/devise/unlocks/new.html.erb +1 -1
  14. data/config/locales/en.yml +2 -2
  15. data/gemfiles/Gemfile.rails-3.1.x.lock +3 -3
  16. data/lib/devise.rb +1 -0
  17. data/lib/devise/controllers/helpers.rb +1 -1
  18. data/lib/devise/encryptors/base.rb +5 -1
  19. data/lib/devise/encryptors/bcrypt.rb +14 -0
  20. data/lib/devise/failure_app.rb +1 -0
  21. data/lib/devise/models.rb +32 -2
  22. data/lib/devise/models/authenticatable.rb +15 -10
  23. data/lib/devise/models/confirmable.rb +21 -1
  24. data/lib/devise/models/database_authenticatable.rb +11 -5
  25. data/lib/devise/models/encryptable.rb +17 -9
  26. data/lib/devise/models/lockable.rb +17 -1
  27. data/lib/devise/models/omniauthable.rb +4 -0
  28. data/lib/devise/models/recoverable.rb +4 -0
  29. data/lib/devise/models/registerable.rb +4 -0
  30. data/lib/devise/models/rememberable.rb +6 -2
  31. data/lib/devise/models/timeoutable.rb +4 -0
  32. data/lib/devise/models/token_authenticatable.rb +5 -0
  33. data/lib/devise/models/trackable.rb +4 -0
  34. data/lib/devise/models/validatable.rb +4 -0
  35. data/lib/devise/param_filter.rb +2 -1
  36. data/lib/devise/rails/routes.rb +3 -2
  37. data/lib/devise/strategies/authenticatable.rb +10 -4
  38. data/lib/devise/version.rb +1 -1
  39. data/lib/generators/devise/views_generator.rb +15 -6
  40. data/lib/generators/templates/devise.rb +1 -1
  41. data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +1 -1
  42. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +1 -1
  43. data/lib/generators/templates/simple_form_for/passwords/new.html.erb +1 -1
  44. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +1 -1
  45. data/lib/generators/templates/simple_form_for/sessions/new.html.erb +1 -1
  46. data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +1 -1
  47. data/test/generators/views_generator_test.rb +1 -1
  48. data/test/integration/omniauthable_test.rb +2 -2
  49. data/test/integration/recoverable_test.rb +9 -0
  50. data/test/models/authenticatable_test.rb +3 -5
  51. data/test/models/confirmable_test.rb +26 -0
  52. data/test/models/database_authenticatable_test.rb +29 -7
  53. data/test/models/encryptable_test.rb +6 -0
  54. data/test/models/lockable_test.rb +34 -0
  55. data/test/models/omniauthable_test.rb +7 -0
  56. data/test/models/recoverable_test.rb +8 -1
  57. data/test/models/registerable_test.rb +7 -0
  58. data/test/models/rememberable_test.rb +8 -1
  59. data/test/models/timeoutable_test.rb +4 -0
  60. data/test/models/token_authenticatable_test.rb +6 -0
  61. data/test/models/trackable_test.rb +9 -1
  62. data/test/models/validatable_test.rb +5 -1
  63. data/test/models_test.rb +70 -0
  64. data/test/rails_app/config/routes.rb +4 -0
  65. data/test/routes_test.rb +4 -0
  66. data/test/support/assertions.rb +15 -0
  67. data/test/support/helpers.rb +21 -0
  68. metadata +19 -34
@@ -12,4 +12,4 @@
12
12
  </div>
13
13
  <% end %>
14
14
 
15
- <%= render "links" %>
15
+ <%= render :partial => "devise/shared/links" %>
@@ -12,4 +12,4 @@
12
12
  </div>
13
13
  <% end %>
14
14
 
15
- <%= render "links" %>
15
+ <%= render :partial => "devise/shared/links" %>
@@ -46,7 +46,7 @@ class ViewsGeneratorTest < Rails::Generators::TestCase
46
46
  assert_file "app/views/#{scope}/registrations/new.html.erb"
47
47
  assert_file "app/views/#{scope}/registrations/edit.html.erb"
48
48
  assert_file "app/views/#{scope}/sessions/new.html.erb"
49
+ assert_file "app/views/#{scope}/shared/_links.erb"
49
50
  assert_file "app/views/#{scope}/unlocks/new.html.erb"
50
- assert_file "app/views/#{scope}/_links.erb"
51
51
  end
52
52
  end
@@ -118,7 +118,7 @@ class OmniauthableIntegrationTest < ActionController::IntegrationTest
118
118
  OmniAuth.config.mock_auth[:facebook] = :access_denied
119
119
  visit "/users/auth/facebook/callback?error=access_denied"
120
120
  assert_current_url "/users/sign_in"
121
- assert_contain 'Could not authorize you from Facebook because "Access denied".'
121
+ assert_contain 'Could not authenticate you from Facebook because "Access denied".'
122
122
  end
123
123
 
124
124
  test "handles other exceptions from omniauth" do
@@ -128,6 +128,6 @@ class OmniauthableIntegrationTest < ActionController::IntegrationTest
128
128
  click_link "Sign in with Facebook"
129
129
 
130
130
  assert_current_url "/users/sign_in"
131
- assert_contain 'Could not authorize you from Facebook because "Invalid credentials".'
131
+ assert_contain 'Could not authenticate you from Facebook because "Invalid credentials".'
132
132
  end
133
133
  end
@@ -195,6 +195,15 @@ class PasswordTest < ActionController::IntegrationTest
195
195
  assert !warden.authenticated?(:user)
196
196
  end
197
197
 
198
+ test 'sign in user automatically and confirm after changing its password if it\'s not confirmed' do
199
+ user = create_user(:confirm => false)
200
+ request_forgot_password
201
+ reset_password :reset_password_token => user.reload.reset_password_token
202
+
203
+ assert warden.authenticated?(:user)
204
+ assert user.reload.confirmed?
205
+ end
206
+
198
207
  test 'reset password request with valid E-Mail in XML format should return valid response' do
199
208
  create_user
200
209
  post user_password_path(:format => 'xml'), :user => {:email => "user@test.com"}
@@ -1,9 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class AuthenticatableTest < ActiveSupport::TestCase
4
- test 'find_first_by_auth_conditions allows custom filtering parameters' do
5
- user = User.create!(:email => "example@example.com", :password => "123456")
6
- assert_equal User.find_first_by_auth_conditions({ :email => "example@example.com" }), user
7
- assert_equal User.find_first_by_auth_conditions({ :email => "example@example.com" }, :id => user.id + 1), nil
4
+ test 'required_fields should be an empty array' do
5
+ assert_equal Devise::Models::Validatable.required_fields(User), []
8
6
  end
9
- end
7
+ end
@@ -252,6 +252,15 @@ class ReconfirmableTest < ActiveSupport::TestCase
252
252
  assert_not_nil admin.confirmation_token
253
253
  end
254
254
 
255
+ test 'should not generate confirmation token if skipping reconfirmation after changing email' do
256
+ admin = create_admin
257
+ assert admin.confirm!
258
+ admin.skip_reconfirmation!
259
+ assert admin.update_attributes(:email => 'new_test@example.com')
260
+ assert_nil admin.confirmation_token
261
+ end
262
+
263
+
255
264
  test 'should regenerate confirmation token after changing email' do
256
265
  admin = create_admin
257
266
  assert admin.confirm!
@@ -328,4 +337,21 @@ class ReconfirmableTest < ActiveSupport::TestCase
328
337
  admin = Admin.find_by_unconfirmed_email_with_errors(:email => "new_test@email.com")
329
338
  assert admin.persisted?
330
339
  end
340
+
341
+ test 'required_fields should contain the fields that Devise uses' do
342
+ assert_same_content Devise::Models::Confirmable.required_fields(User), [
343
+ :confirmation_sent_at,
344
+ :confirmation_token,
345
+ :confirmed_at
346
+ ]
347
+ end
348
+
349
+ test 'required_fields should also contain unconfirmable when reconfirmable_email is true' do
350
+ assert_same_content Devise::Models::Confirmable.required_fields(Admin), [
351
+ :confirmation_sent_at,
352
+ :confirmation_token,
353
+ :confirmed_at,
354
+ :unconfirmed_email
355
+ ]
356
+ end
331
357
  end
@@ -11,7 +11,7 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
11
11
  user.save!
12
12
  assert_equal email.downcase, user.email
13
13
  end
14
-
14
+
15
15
  test 'should remove whitespace from strip whitespace keys when saving' do
16
16
  # strip_whitespace_keys is set to :email by default.
17
17
  email = ' foo@bar.com '
@@ -23,9 +23,15 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
23
23
  end
24
24
 
25
25
  test "param filter should not convert booleans and integer to strings" do
26
- conditions = { "login" => "foo@bar.com", "bool1" => true, "bool2" => false, "fixnum" => 123, "will_be_converted" => (1..10) }
26
+ conditions = { 'login' => 'foo@bar.com', "bool1" => true, "bool2" => false, "fixnum" => 123, "will_be_converted" => (1..10) }
27
+ conditions = Devise::ParamFilter.new([], []).filter(conditions)
28
+ assert_equal( { 'login' => 'foo@bar.com', "bool1" => true, "bool2" => false, "fixnum" => 123, "will_be_converted" => "1..10" }, conditions)
29
+ end
30
+
31
+ test "param filter should not convert regular expressions to strings" do
32
+ conditions = { "regexp" => /expression/ }
27
33
  conditions = Devise::ParamFilter.new([], []).filter(conditions)
28
- assert_equal( { "login" => "foo@bar.com", "bool1" => "true", "bool2" => "false", "fixnum" => "123", "will_be_converted" => "1..10" }, conditions)
34
+ assert_equal( { "regexp" => /expression/ }, conditions)
29
35
  end
30
36
 
31
37
  test 'should respond to password and password confirmation' do
@@ -86,14 +92,14 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
86
92
  :password => 'pass321', :password_confirmation => 'pass321')
87
93
  assert user.reload.valid_password?('pass321')
88
94
  end
89
-
95
+
90
96
  test 'should update password with valid current password and :as option' do
91
97
  user = create_user
92
98
  assert user.update_with_password(:current_password => '123456',
93
99
  :password => 'pass321', :password_confirmation => 'pass321', :as => :admin)
94
100
  assert user.reload.valid_password?('pass321')
95
101
  end
96
-
102
+
97
103
  test 'should add an error to current password when it is invalid' do
98
104
  user = create_user
99
105
  assert_not user.update_with_password(:current_password => 'other',
@@ -145,7 +151,7 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
145
151
  user.update_without_password(:email => 'new@example.com')
146
152
  assert_equal 'new@example.com', user.email
147
153
  end
148
-
154
+
149
155
  test 'should update the user without password with :as option' do
150
156
  user = create_user
151
157
  user.update_without_password(:email => 'new@example.com', :as => :admin)
@@ -164,4 +170,20 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
164
170
  user = User.create(:email => "HEllO@example.com", :password => "123456")
165
171
  assert !user.valid?
166
172
  end
167
- end
173
+
174
+ test 'required_fiels should be encryptable_password and the email field by default' do
175
+ assert_same_content Devise::Models::DatabaseAuthenticatable.required_fields(User), [
176
+ :email,
177
+ :encrypted_password
178
+ ]
179
+ end
180
+
181
+ test 'required_fields should be encryptable_password and the login when the login is on authentication_keys' do
182
+ swap Devise, :authentication_keys => [:login] do
183
+ assert_same_content Devise::Models::DatabaseAuthenticatable.required_fields(User), [
184
+ :encrypted_password,
185
+ :login
186
+ ]
187
+ end
188
+ end
189
+ end
@@ -64,4 +64,10 @@ class EncryptableTest < ActiveSupport::TestCase
64
64
  admin.save
65
65
  assert_not admin.valid_password?('123456')
66
66
  end
67
+
68
+ test 'required_fields should contain the fields that Devise uses' do
69
+ assert_same_content Devise::Models::Encryptable.required_fields(User), [
70
+ :password_salt
71
+ ]
72
+ end
67
73
  end
@@ -235,4 +235,38 @@ class LockableTest < ActiveSupport::TestCase
235
235
  assert_nil user.locked_at
236
236
  end
237
237
  end
238
+
239
+ test 'required_fields should contain the all the fields when all the strategies are enabled' do
240
+ swap Devise, :unlock_strategy => :both do
241
+ swap Devise, :lock_strategy => :failed_attempts do
242
+ assert_same_content Devise::Models::Lockable.required_fields(User), [
243
+ :failed_attempts,
244
+ :unlock_at,
245
+ :unlock_token
246
+ ]
247
+ end
248
+ end
249
+ end
250
+
251
+ test 'required_fields should contain only failed_attempts and unlock_at when the strategies are time and failed_attempts are enabled' do
252
+ swap Devise, :unlock_strategy => :time do
253
+ swap Devise, :lock_strategy => :failed_attempts do
254
+ assert_same_content Devise::Models::Lockable.required_fields(User), [
255
+ :failed_attempts,
256
+ :unlock_at
257
+ ]
258
+ end
259
+ end
260
+ end
261
+
262
+ test 'required_fields should contain only failed_attempts and unlock_token when the strategies are token and failed_attempts are enabled' do
263
+ swap Devise, :unlock_strategy => :email do
264
+ swap Devise, :lock_strategy => :failed_attempts do
265
+ assert_same_content Devise::Models::Lockable.required_fields(User), [
266
+ :failed_attempts,
267
+ :unlock_token
268
+ ]
269
+ end
270
+ end
271
+ end
238
272
  end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class OmniauthableTest < ActiveSupport::TestCase
4
+ test 'required_fields should contain the fields that Devise uses' do
5
+ assert_same_content Devise::Models::Omniauthable.required_fields(User), []
6
+ end
7
+ end
@@ -195,4 +195,11 @@ class RecoverableTest < ActiveSupport::TestCase
195
195
  assert_equal "has expired, please request a new one", reset_password_user.errors[:reset_password_token].join
196
196
  end
197
197
  end
198
- end
198
+
199
+ test 'required_fields should contain the fields that Devise uses' do
200
+ assert_same_content Devise::Models::Recoverable.required_fields(User), [
201
+ :reset_password_sent_at,
202
+ :reset_password_token
203
+ ]
204
+ end
205
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class RegisterableTest < ActiveSupport::TestCase
4
+ test 'required_fields should contain the fields that Devise uses' do
5
+ assert_same_content Devise::Models::Registerable.required_fields(User), []
6
+ end
7
+ end
@@ -54,7 +54,7 @@ class RememberableTest < ActiveSupport::TestCase
54
54
  resource.forget_me!
55
55
  assert resource.remember_created_at.nil?
56
56
  end
57
-
57
+
58
58
  test 'forget_me should not try to update resource if it has been destroyed' do
59
59
  resource = create_resource
60
60
  resource.destroy
@@ -165,4 +165,11 @@ class RememberableTest < ActiveSupport::TestCase
165
165
  assert_not_equal old, resource.remember_created_at
166
166
  end
167
167
  end
168
+
169
+ test 'should have the required_fiels array' do
170
+ assert_same_content Devise::Models::Rememberable.required_fields(User), [
171
+ :remember_created_at,
172
+ :remember_token
173
+ ]
174
+ end
168
175
  end
@@ -39,4 +39,8 @@ class TimeoutableTest < ActiveSupport::TestCase
39
39
  assert user.timedout?(6.minutes.ago)
40
40
  end
41
41
  end
42
+
43
+ test 'required_fields should contain the fields that Devise uses' do
44
+ assert_same_content Devise::Models::Timeoutable.required_fields(User), []
45
+ end
42
46
  end
@@ -46,4 +46,10 @@ class TokenAuthenticatableTest < ActiveSupport::TestCase
46
46
  user = User.find_for_token_authentication(:auth_token => {'$ne' => user1.authentication_token})
47
47
  assert_nil user
48
48
  end
49
+
50
+ test 'required_fields should contain the fields that Devise uses' do
51
+ assert_same_content Devise::Models::TokenAuthenticatable.required_fields(User), [
52
+ :authentication_token
53
+ ]
54
+ end
49
55
  end
@@ -1,5 +1,13 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class TrackableTest < ActiveSupport::TestCase
4
-
4
+ test 'required_fields should contain the fields that Devise uses' do
5
+ assert_same_content Devise::Models::Trackable.required_fields(User), [
6
+ :current_sign_in_at,
7
+ :current_sign_in_ip,
8
+ :last_sign_in_at,
9
+ :last_sign_in_ip,
10
+ :sign_in_count
11
+ ]
12
+ end
5
13
  end
@@ -105,9 +105,13 @@ class ValidatableTest < ActiveSupport::TestCase
105
105
  assert_equal 'is too long (maximum is 128 characters)', user.errors[:password].join
106
106
  end
107
107
 
108
- test 'shuold not be included in objects with invalid API' do
108
+ test 'should not be included in objects with invalid API' do
109
109
  assert_raise RuntimeError do
110
110
  Class.new.send :include, Devise::Models::Validatable
111
111
  end
112
112
  end
113
+
114
+ test 'required_fields should be an empty array' do
115
+ assert_equal Devise::Models::Validatable.required_fields(User), []
116
+ end
113
117
  end
data/test/models_test.rb CHANGED
@@ -107,3 +107,73 @@ class ActiveRecordTest < ActiveSupport::TestCase
107
107
  Admin.create!
108
108
  end
109
109
  end
110
+
111
+ class CheckFieldsTest < ActiveSupport::TestCase
112
+ test 'checks if the class respond_to the required fields' do
113
+ Player = Class.new do
114
+ extend Devise::Models
115
+
116
+ def self.before_validation(instance)
117
+ end
118
+
119
+ devise :database_authenticatable
120
+
121
+ attr_accessor :encrypted_password, :email
122
+ end
123
+
124
+ assert_nothing_raised Devise::Models::MissingAttribute do
125
+ Devise::Models.check_fields!(Player)
126
+ end
127
+ end
128
+
129
+ test 'raises Devise::Models::MissingAtrribute and shows the missing attribute if the class doesn\'t respond_to one of the attributes' do
130
+ Clown = Class.new do
131
+ extend Devise::Models
132
+
133
+ def self.before_validation(instance)
134
+ end
135
+
136
+ devise :database_authenticatable
137
+
138
+ attr_accessor :encrypted_password
139
+ end
140
+
141
+ assert_raise_with_message Devise::Models::MissingAttribute, "The following attribute(s) is (are) missing on your model: email" do
142
+ Devise::Models.check_fields!(Clown)
143
+ end
144
+ end
145
+
146
+ test 'raises Devise::Models::MissingAtrribute with all the missing attributes if there is more than one' do
147
+ Magician = Class.new do
148
+ extend Devise::Models
149
+
150
+ def self.before_validation(instance)
151
+ end
152
+
153
+ devise :database_authenticatable
154
+ end
155
+
156
+ exception = assert_raise_with_message Devise::Models::MissingAttribute, "The following attribute(s) is (are) missing on your model: encrypted_password, email" do
157
+ Devise::Models.check_fields!(Magician)
158
+ end
159
+ end
160
+
161
+ test "doesn't raise a NoMethodError exception when the module doesn't have a required_field(klass) class method" do
162
+ driver = Class.new do
163
+ extend Devise::Models
164
+
165
+ def self.before_validation(instance)
166
+ end
167
+
168
+ attr_accessor :encrypted_password, :email
169
+
170
+ devise :database_authenticatable
171
+ end
172
+
173
+ swap_module_method_existence Devise::Models::DatabaseAuthenticatable, :required_fields do
174
+ assert_deprecated do
175
+ Devise::Models.check_fields!(driver)
176
+ end
177
+ end
178
+ end
179
+ end
@@ -58,6 +58,10 @@ Rails.application.routes.draw do
58
58
  # Other routes for routing_test.rb
59
59
  devise_for :reader, :class_name => "User", :only => :passwords
60
60
 
61
+ scope :host => "sub.example.com" do
62
+ devise_for :sub_admin, :class_name => "Admin"
63
+ end
64
+
61
65
  namespace :publisher, :path_names => { :sign_in => "i_dont_care", :sign_out => "get_out" } do
62
66
  devise_for :accounts, :class_name => "Admin", :path_names => { :sign_in => "get_in" }
63
67
  end
data/test/routes_test.rb CHANGED
@@ -128,6 +128,10 @@ class CustomizedRoutingTest < ActionController::TestCase
128
128
  end
129
129
  end
130
130
 
131
+ test 'subdomain admin' do
132
+ assert_recognizes({"host"=>"sub.example.com", :controller => 'devise/sessions', :action => 'new'}, {:host => "sub.example.com", :path => '/sub_admin/sign_in', :method => :get})
133
+ end
134
+
131
135
  test 'does only map reader password' do
132
136
  assert_raise ActionController::RoutingError do
133
137
  assert_recognizes({:controller => 'devise/sessions', :action => 'new'}, 'reader/sessions/new')
@@ -24,4 +24,19 @@ class ActiveSupport::TestCase
24
24
  def assert_email_not_sent(&block)
25
25
  assert_no_difference('ActionMailer::Base.deliveries.size') { yield }
26
26
  end
27
+
28
+ def assert_same_content(result, expected)
29
+ assert expected.size == result.size, "the arrays doesn't have the same size"
30
+ expected.each do |element|
31
+ assert result.include?(element), "The array doesn't include '#{element}'."
32
+ end
33
+ end
34
+
35
+ def assert_raise_with_message(exception_klass, message)
36
+ exception = assert_raise exception_klass do
37
+ yield
38
+ end
39
+
40
+ assert_equal exception.message, message, "The expected message was #{message} but your exception throwed #{exception.message}"
41
+ end
27
42
  end