devise 0.8.2 → 0.9.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 (80) hide show
  1. data/CHANGELOG.rdoc +21 -2
  2. data/README.rdoc +40 -54
  3. data/Rakefile +1 -1
  4. data/TODO +1 -3
  5. data/app/controllers/confirmations_controller.rb +9 -20
  6. data/app/controllers/passwords_controller.rb +9 -20
  7. data/app/controllers/sessions_controller.rb +9 -9
  8. data/app/controllers/unlocks_controller.rb +22 -0
  9. data/app/models/devise_mailer.rb +6 -1
  10. data/app/views/confirmations/new.html.erb +1 -5
  11. data/app/views/devise_mailer/unlock_instructions.html.erb +7 -0
  12. data/app/views/passwords/edit.html.erb +1 -5
  13. data/app/views/passwords/new.html.erb +1 -5
  14. data/app/views/sessions/new.html.erb +1 -7
  15. data/app/views/shared/_devise_links.erb +15 -0
  16. data/app/views/unlocks/new.html.erb +12 -0
  17. data/generators/devise/templates/migration.rb +2 -0
  18. data/generators/devise/templates/model.rb +4 -1
  19. data/generators/devise_install/templates/devise.rb +20 -10
  20. data/lib/devise.rb +62 -18
  21. data/lib/devise/controllers/common.rb +24 -0
  22. data/lib/devise/controllers/helpers.rb +160 -80
  23. data/lib/devise/controllers/internal_helpers.rb +120 -0
  24. data/lib/devise/controllers/url_helpers.rb +2 -10
  25. data/lib/devise/encryptors/bcrypt.rb +2 -2
  26. data/lib/devise/hooks/activatable.rb +1 -4
  27. data/lib/devise/hooks/rememberable.rb +30 -0
  28. data/lib/devise/hooks/timeoutable.rb +4 -2
  29. data/lib/devise/locales/en.yml +9 -2
  30. data/lib/devise/mapping.rb +15 -11
  31. data/lib/devise/models.rb +16 -35
  32. data/lib/devise/models/activatable.rb +1 -1
  33. data/lib/devise/models/authenticatable.rb +1 -9
  34. data/lib/devise/models/confirmable.rb +6 -2
  35. data/lib/devise/models/lockable.rb +142 -0
  36. data/lib/devise/models/rememberable.rb +19 -2
  37. data/lib/devise/models/timeoutable.rb +1 -2
  38. data/lib/devise/orm/active_record.rb +2 -0
  39. data/lib/devise/orm/data_mapper.rb +1 -1
  40. data/lib/devise/orm/mongo_mapper.rb +12 -1
  41. data/lib/devise/rails/routes.rb +5 -1
  42. data/lib/devise/rails/warden_compat.rb +13 -13
  43. data/lib/devise/schema.rb +7 -0
  44. data/lib/devise/strategies/authenticatable.rb +1 -3
  45. data/lib/devise/strategies/base.rb +1 -1
  46. data/lib/devise/strategies/rememberable.rb +37 -0
  47. data/lib/devise/test_helpers.rb +1 -1
  48. data/lib/devise/version.rb +1 -1
  49. data/test/controllers/helpers_test.rb +155 -33
  50. data/test/controllers/internal_helpers_test.rb +55 -0
  51. data/test/devise_test.rb +24 -3
  52. data/test/encryptors_test.rb +3 -1
  53. data/test/integration/lockable_test.rb +83 -0
  54. data/test/integration/rememberable_test.rb +1 -1
  55. data/test/mailers/unlock_instructions_test.rb +62 -0
  56. data/test/models/authenticatable_test.rb +0 -23
  57. data/test/models/lockable_test.rb +202 -0
  58. data/test/models/timeoutable_test.rb +7 -7
  59. data/test/models/validatable_test.rb +2 -2
  60. data/test/models_test.rb +9 -76
  61. data/test/orm/active_record.rb +1 -0
  62. data/test/orm/mongo_mapper.rb +0 -1
  63. data/test/rails_app/app/active_record/admin.rb +1 -1
  64. data/test/rails_app/app/active_record/user.rb +2 -1
  65. data/test/rails_app/app/mongo_mapper/admin.rb +1 -1
  66. data/test/rails_app/app/mongo_mapper/user.rb +2 -1
  67. data/test/rails_app/config/initializers/devise.rb +13 -10
  68. data/test/rails_app/config/routes.rb +5 -3
  69. data/test/routes_test.rb +5 -0
  70. data/test/support/integration_tests_helper.rb +1 -0
  71. metadata +16 -12
  72. data/lib/devise/controllers/filters.rb +0 -186
  73. data/lib/devise/models/cookie_serializer.rb +0 -21
  74. data/lib/devise/models/session_serializer.rb +0 -19
  75. data/lib/devise/serializers/base.rb +0 -23
  76. data/lib/devise/serializers/cookie.rb +0 -43
  77. data/lib/devise/serializers/session.rb +0 -22
  78. data/test/controllers/filters_test.rb +0 -177
  79. data/test/rails_app/app/active_record/account.rb +0 -7
  80. data/test/rails_app/app/mongo_mapper/account.rb +0 -9
@@ -0,0 +1,55 @@
1
+ require 'test/test_helper'
2
+
3
+ class MyController < ApplicationController
4
+ include Devise::Controllers::InternalHelpers
5
+ end
6
+
7
+ class HelpersTest < ActionController::TestCase
8
+ tests MyController
9
+
10
+ test 'get resource name from request path' do
11
+ @request.path = '/users/session'
12
+ assert_equal :user, @controller.resource_name
13
+ end
14
+
15
+ test 'get resource name from specific request path' do
16
+ @request.path = '/admin_area/session'
17
+ assert_equal :admin, @controller.resource_name
18
+ end
19
+
20
+ test 'get resource class from request path' do
21
+ @request.path = '/users/session'
22
+ assert_equal User, @controller.resource_class
23
+ end
24
+
25
+ test 'get resource instance variable from request path' do
26
+ @request.path = '/admin_area/session'
27
+ @controller.instance_variable_set(:@admin, admin = Admin.new)
28
+ assert_equal admin, @controller.resource
29
+ end
30
+
31
+ test 'set resource instance variable from request path' do
32
+ @request.path = '/admin_area/session'
33
+
34
+ admin = @controller.send(:resource_class).new
35
+ @controller.send(:resource=, admin)
36
+
37
+ assert_equal admin, @controller.send(:resource)
38
+ assert_equal admin, @controller.instance_variable_get(:@admin)
39
+ end
40
+
41
+ test 'resources methods are not controller actions' do
42
+ assert @controller.class.action_methods.empty?
43
+ end
44
+
45
+ test 'require no authentication tests current mapping' do
46
+ @controller.expects(:resource_name).returns(:user).twice
47
+ @mock_warden.expects(:authenticated?).with(:user).returns(true)
48
+ @controller.expects(:redirect_to).with(root_path)
49
+ @controller.send :require_no_authentication
50
+ end
51
+
52
+ test 'is a devise controller' do
53
+ assert @controller.devise_controller?
54
+ end
55
+ end
@@ -2,7 +2,7 @@ require 'test/test_helper'
2
2
 
3
3
  module Devise
4
4
  def self.clean_warden_config!
5
- @warden_config = nil
5
+ @warden_config = nil
6
6
  end
7
7
  end
8
8
 
@@ -25,10 +25,9 @@ class DeviseTest < ActiveSupport::TestCase
25
25
  Devise.configure_warden(config)
26
26
 
27
27
  assert_equal Devise::FailureApp, config.failure_app
28
- assert_equal [:authenticatable], config.default_strategies
28
+ assert_equal [:rememberable, :authenticatable], config.default_strategies
29
29
  assert_equal :user, config.default_scope
30
30
  assert config.silence_missing_strategies?
31
- assert config.silence_missing_serializers?
32
31
  end
33
32
 
34
33
  test 'warden manager user configuration through a block' do
@@ -45,4 +44,26 @@ class DeviseTest < ActiveSupport::TestCase
45
44
  Devise.clean_warden_config!
46
45
  end
47
46
  end
47
+
48
+ test 'add new module using the helper method' do
49
+ assert_nothing_raised(Exception) { Devise.add_module(:coconut) }
50
+ assert_equal 1, Devise::ALL.select { |v| v == :coconut }.size
51
+ assert_not Devise::STRATEGIES.include?(:coconut)
52
+ assert_not defined?(Devise::Models::Coconut)
53
+ Devise::ALL.delete(:coconut)
54
+
55
+ assert_nothing_raised(Exception) { Devise.add_module(:banana, :strategy => true) }
56
+ assert_equal 1, Devise::STRATEGIES.select { |v| v == :banana }.size
57
+ Devise::ALL.delete(:banana)
58
+ Devise::STRATEGIES.delete(:banana)
59
+
60
+ assert_nothing_raised(Exception) { Devise.add_module(:kivi, :controller => :fruits) }
61
+ assert_not_nil Devise::CONTROLLERS[:fruits]
62
+ assert_equal 1, Devise::CONTROLLERS[:fruits].select { |v| v == :kivi }.size
63
+ Devise::ALL.delete(:kivi)
64
+ Devise::CONTROLLERS.delete(:fruits)
65
+
66
+ assert_nothing_raised(Exception) { Devise.add_module(:authenticatable_again, :model => 'devise/model/authenticatable') }
67
+ assert defined?(Devise::Models::AuthenticatableAgain)
68
+ end
48
69
  end
@@ -1,3 +1,5 @@
1
+ gem 'bcrypt-ruby'
2
+
1
3
  class Encryptors < ActiveSupport::TestCase
2
4
 
3
5
  test 'should match a password created by authlogic' do
@@ -17,7 +19,7 @@ class Encryptors < ActiveSupport::TestCase
17
19
  encryptor = Devise::Encryptors::ClearanceSha1.digest('123mudar', nil, '65c58472c207c829f28c68619d3e3aefed18ab3f', nil)
18
20
  assert_equal clearance, encryptor
19
21
  end
20
-
22
+
21
23
  Devise::ENCRYPTORS_LENGTH.each do |key, value|
22
24
  test "should have length #{value} for #{key.inspect}" do
23
25
  swap Devise, :encryptor => key do
@@ -0,0 +1,83 @@
1
+ require 'test/test_helper'
2
+
3
+ class LockTest < ActionController::IntegrationTest
4
+
5
+ def visit_user_unlock_with_token(unlock_token)
6
+ visit user_unlock_path(:unlock_token => unlock_token)
7
+ end
8
+
9
+ test 'user should be able to request a new unlock token' do
10
+ user = create_user(:locked => true)
11
+ ActionMailer::Base.deliveries.clear
12
+
13
+ visit new_user_session_path
14
+ click_link 'Didn\'t receive unlock instructions?'
15
+
16
+ fill_in 'email', :with => user.email
17
+ click_button 'Resend unlock instructions'
18
+
19
+ assert_template 'sessions/new'
20
+ assert_contain 'You will receive an email with instructions about how to unlock your account in a few minutes'
21
+ assert_equal 1, ActionMailer::Base.deliveries.size
22
+ end
23
+
24
+ test 'unlocked user should not be able to request a unlock token' do
25
+ user = create_user(:locked => false)
26
+ ActionMailer::Base.deliveries.clear
27
+
28
+ visit new_user_session_path
29
+ click_link 'Didn\'t receive unlock instructions?'
30
+
31
+ fill_in 'email', :with => user.email
32
+ click_button 'Resend unlock instructions'
33
+
34
+ assert_template 'unlocks/new'
35
+ assert_contain 'not locked'
36
+ assert_equal 0, ActionMailer::Base.deliveries.size
37
+ end
38
+
39
+ test 'user with invalid unlock token should not be able to unlock an account' do
40
+ visit_user_unlock_with_token('invalid_token')
41
+
42
+ assert_response :success
43
+ assert_template 'unlocks/new'
44
+ assert_have_selector '#errorExplanation'
45
+ assert_contain /Unlock token(.*)invalid/
46
+ end
47
+
48
+ test "locked user should be able to unlock account" do
49
+ user = create_user(:locked => true)
50
+ assert user.locked?
51
+
52
+ visit_user_unlock_with_token(user.unlock_token)
53
+
54
+ assert_template 'home/index'
55
+ assert_contain 'Your account was successfully unlocked.'
56
+
57
+ assert_not user.reload.locked?
58
+ end
59
+
60
+ test "sign in user automatically after unlocking it's account" do
61
+ user = create_user(:locked => true)
62
+ visit_user_unlock_with_token(user.unlock_token)
63
+
64
+ assert warden.authenticated?(:user)
65
+ end
66
+
67
+ test "user should not be able to sign in when locked" do
68
+ user = sign_in_as_user(:locked => true)
69
+ assert_template 'sessions/new'
70
+ assert_contain 'Your account is locked.'
71
+ assert_not warden.authenticated?(:user)
72
+ end
73
+
74
+ test 'error message is configurable by resource name' do
75
+ store_translations :en, :devise => {
76
+ :sessions => { :admin => { :locked => "You are locked!" } }
77
+ } do
78
+ get new_admin_session_path(:locked => true)
79
+ assert_contain 'You are locked!'
80
+ end
81
+ end
82
+
83
+ end
@@ -6,7 +6,7 @@ class RememberMeTest < ActionController::IntegrationTest
6
6
  Devise.remember_for = 1
7
7
  user = create_user
8
8
  user.remember_me!
9
- cookies['warden.user.user.key'] = User.serialize_into_cookie(user) + add_to_token
9
+ cookies['remember_user_token'] = User.serialize_into_cookie(user) + add_to_token
10
10
  user
11
11
  end
12
12
 
@@ -0,0 +1,62 @@
1
+ require 'test/test_helper'
2
+
3
+ class UnlockInstructionsTest < ActionMailer::TestCase
4
+
5
+ def setup
6
+ setup_mailer
7
+ Devise.mailer_sender = 'test@example.com'
8
+ end
9
+
10
+ def user
11
+ @user ||= begin
12
+ user = create_user
13
+ user.lock!
14
+ user
15
+ end
16
+ end
17
+
18
+ def mail
19
+ @mail ||= begin
20
+ user
21
+ ActionMailer::Base.deliveries.last
22
+ end
23
+ end
24
+
25
+ test 'email sent after locking the user' do
26
+ assert_not_nil mail
27
+ end
28
+
29
+ test 'content type should be set to html' do
30
+ assert_equal 'text/html', mail.content_type
31
+ end
32
+
33
+ test 'send unlock instructions to the user email' do
34
+ assert_equal [user.email], mail.to
35
+ end
36
+
37
+ test 'setup sender from configuration' do
38
+ assert_equal ['test@example.com'], mail.from
39
+ end
40
+
41
+ test 'setup subject from I18n' do
42
+ store_translations :en, :devise => { :mailer => { :unlock_instructions => 'Unlock instructions' } } do
43
+ assert_equal 'Unlock instructions', mail.subject
44
+ end
45
+ end
46
+
47
+ test 'subject namespaced by model' do
48
+ store_translations :en, :devise => { :mailer => { :user => { :unlock_instructions => 'User Unlock Instructions' } } } do
49
+ assert_equal 'User Unlock Instructions', mail.subject
50
+ end
51
+ end
52
+
53
+ test 'body should have user info' do
54
+ assert_match /#{user.email}/, mail.body
55
+ end
56
+
57
+ test 'body should have link to unlock the account' do
58
+ host = ActionMailer::Base.default_url_options[:host]
59
+ unlock_url_regexp = %r{<a href=\"http://#{host}/users/unlock\?unlock_token=#{user.unlock_token}">}
60
+ assert_match unlock_url_regexp, mail.body
61
+ end
62
+ end
@@ -130,29 +130,6 @@ class AuthenticatableTest < ActiveSupport::TestCase
130
130
  assert_not_nil Admin.authenticate(:email => admin.email, :password => admin.password)
131
131
  end
132
132
 
133
- test 'should serialize user into session' do
134
- user = create_user
135
- assert_equal [User, user.id], User.serialize_into_session(user)
136
- end
137
-
138
- test 'should serialize user from session' do
139
- user = create_user
140
- assert_equal user.id, User.serialize_from_session([User, user.id]).id
141
- end
142
-
143
- test 'should serialize another klass from session if it is an ancestors' do
144
- user = create_user
145
- klass = Class.new(User)
146
- assert_equal user.id, User.serialize_from_session([klass, user.id]).id
147
- end
148
-
149
- test 'should not serialize another klass from session if not an ancestors' do
150
- user = create_user
151
- assert_raise RuntimeError, /ancestors/ do
152
- User.serialize_from_session([Admin, user.id])
153
- end
154
- end
155
-
156
133
  test 'should respond to old password' do
157
134
  assert new_user.respond_to?(:old_password)
158
135
  end
@@ -0,0 +1,202 @@
1
+ require 'test/test_helper'
2
+
3
+ class LockableTest < ActiveSupport::TestCase
4
+
5
+ def setup
6
+ setup_mailer
7
+ end
8
+
9
+ test "should increment failed attempts on unsuccessful authentication" do
10
+ user = create_user
11
+ assert_equal 0, user.failed_attempts
12
+ authenticated_user = User.authenticate(:email => user.email, :password => "anotherpassword")
13
+ assert_equal 1, user.reload.failed_attempts
14
+ end
15
+
16
+ test "should lock account base on maximum_attempts" do
17
+ user = create_user
18
+ attempts = Devise.maximum_attempts + 1
19
+ attempts.times { authenticated_user = User.authenticate(:email => user.email, :password => "anotherpassword") }
20
+ assert user.reload.locked?
21
+ end
22
+
23
+ test "should respect maximum attempts configuration" do
24
+ user = create_user
25
+ swap Devise, :maximum_attempts => 2 do
26
+ 3.times { authenticated_user = User.authenticate(:email => user.email, :password => "anotherpassword") }
27
+ assert user.reload.locked?
28
+ end
29
+ end
30
+
31
+ test "should clear failed_attempts on successfull sign in" do
32
+ user = create_user
33
+ User.authenticate(:email => user.email, :password => "anotherpassword")
34
+ assert_equal 1, user.reload.failed_attempts
35
+ User.authenticate(:email => user.email, :password => "123456")
36
+ assert_equal 0, user.reload.failed_attempts
37
+ end
38
+
39
+ test "should verify wheter a user is locked or not" do
40
+ user = create_user
41
+ assert_not user.locked?
42
+ user.lock!
43
+ assert user.locked?
44
+ end
45
+
46
+ test "active? should be the opposite of locked?" do
47
+ user = create_user
48
+ user.confirm!
49
+ assert user.active?
50
+ user.lock!
51
+ assert_not user.active?
52
+ end
53
+
54
+ test "should unlock an user by cleaning locked_at, falied_attempts and unlock_token" do
55
+ user = create_user
56
+ user.lock!
57
+ assert_not_nil user.reload.locked_at
58
+ assert_not_nil user.reload.unlock_token
59
+ user.unlock!
60
+ assert_nil user.reload.locked_at
61
+ assert_nil user.reload.unlock_token
62
+ assert 0, user.reload.failed_attempts
63
+ end
64
+
65
+ test 'should not unlcok an unlocked user' do
66
+ user = create_user
67
+ assert_not user.unlock!
68
+ assert_match /not locked/, user.errors[:email]
69
+ end
70
+
71
+ test "new user should not be locked and should have zero failed_attempts" do
72
+ assert_not new_user.locked?
73
+ assert_equal 0, create_user.failed_attempts
74
+ end
75
+
76
+ test "should unlock user after unlock_in period" do
77
+ swap Devise, :unlock_in => 3.hours do
78
+ user = new_user
79
+ user.locked_at = 2.hours.ago
80
+ assert user.locked?
81
+
82
+ Devise.unlock_in = 1.hour
83
+ assert_not user.locked?
84
+ end
85
+ end
86
+
87
+ test "should not unlock in 'unlock_in' if :time unlock strategy is not set" do
88
+ swap Devise, :unlock_strategy => :email do
89
+ user = new_user
90
+ user.locked_at = 2.hours.ago
91
+ assert user.locked?
92
+ end
93
+ end
94
+
95
+ test "should set unlock_token when locking" do
96
+ user = create_user
97
+ assert_nil user.unlock_token
98
+ user.lock!
99
+ assert_not_nil user.unlock_token
100
+ end
101
+
102
+ test 'should not regenerate unlock token if it already exists' do
103
+ user = create_user
104
+ user.lock!
105
+ 3.times do
106
+ token = user.unlock_token
107
+ user.resend_unlock!
108
+ assert_equal token, user.unlock_token
109
+ end
110
+ end
111
+
112
+ test "should never generate the same unlock token for different users" do
113
+ unlock_tokens = []
114
+ 3.times do
115
+ user = create_user
116
+ user.lock!
117
+ token = user.unlock_token
118
+ assert !unlock_tokens.include?(token)
119
+ unlock_tokens << token
120
+ end
121
+ end
122
+
123
+ test "should not generate unlock_token when :email is not an unlock strategy" do
124
+ swap Devise, :unlock_strategy => :time do
125
+ user = create_user
126
+ user.lock!
127
+ assert_nil user.unlock_token
128
+ end
129
+ end
130
+
131
+ test "should send email with unlock instructions when :email is an unlock strategy" do
132
+ swap Devise, :unlock_strategy => :email do
133
+ user = create_user
134
+ assert_email_sent do
135
+ user.lock!
136
+ end
137
+ end
138
+ end
139
+
140
+ test "should not send email with unlock instructions when :email is not an unlock strategy" do
141
+ swap Devise, :unlock_strategy => :time do
142
+ user = create_user
143
+ assert_email_not_sent do
144
+ user.lock!
145
+ end
146
+ end
147
+ end
148
+
149
+ test 'should find and unlock an user automatically' do
150
+ user = create_user
151
+ user.lock!
152
+ locked_user = User.unlock!(:unlock_token => user.unlock_token)
153
+ assert_equal locked_user, user
154
+ assert_not user.reload.locked?
155
+ end
156
+
157
+ test 'should return a new record with errors when a invalid token is given' do
158
+ locked_user = User.unlock!(:unlock_token => 'invalid_token')
159
+ assert locked_user.new_record?
160
+ assert_match /invalid/, locked_user.errors[:unlock_token]
161
+ end
162
+
163
+ test 'should return a new record with errors when a blank token is given' do
164
+ locked_user = User.unlock!(:unlock_token => '')
165
+ assert locked_user.new_record?
166
+ assert_match /blank/, locked_user.errors[:unlock_token]
167
+ end
168
+
169
+ test 'should authenticate a unlocked user' do
170
+ user = create_user
171
+ user.lock!
172
+ user.unlock!
173
+ authenticated_user = User.authenticate(:email => user.email, :password => user.password)
174
+ assert_equal authenticated_user, user
175
+ end
176
+
177
+ test 'should find a user to send unlock instructions' do
178
+ user = create_user
179
+ user.lock!
180
+ unlock_user = User.send_unlock_instructions(:email => user.email)
181
+ assert_equal unlock_user, user
182
+ end
183
+
184
+ test 'should return a new user if no email was found' do
185
+ unlock_user = User.send_unlock_instructions(:email => "invalid@email.com")
186
+ assert unlock_user.new_record?
187
+ end
188
+
189
+ test 'should add error to new user email if no email was found' do
190
+ unlock_user = User.send_unlock_instructions(:email => "invalid@email.com")
191
+ assert unlock_user.errors[:email]
192
+ assert_equal 'not found', unlock_user.errors[:email]
193
+ end
194
+
195
+ test 'should not be able to send instructions if the user is not locked' do
196
+ user = create_user
197
+ assert_not user.resend_unlock!
198
+ assert_not user.locked?
199
+ assert_equal 'not locked', user.errors[:email]
200
+ end
201
+
202
+ end