Separating perishable token into confirmation and reset_password tokens. Adding confirmation_sent_at attribute.

This commit is contained in:
Carlos A. da Silva
2009-10-18 09:14:52 -02:00
parent bc825d3b23
commit 75e98d3041
19 changed files with 210 additions and 200 deletions

View File

@@ -17,20 +17,20 @@ class ConfirmationTest < ActionController::IntegrationTest
assert_equal 1, ActionMailer::Base.deliveries.size
end
test 'user with invalid perishable token should not be able to confirm an account' do
visit user_confirmation_path(:perishable_token => 'invalid_perishable')
test 'user with invalid confirmation token should not be able to confirm an account' do
visit user_confirmation_path(:confirmation_token => 'invalid_confirmation')
assert_response :success
assert_template 'confirmations/new'
assert_have_selector '#errorExplanation'
assert_contain 'invalid confirmation'
assert_contain 'Confirmation token is invalid'
end
test 'user with valid perishable token should be able to confirm an account' do
test 'user with valid confirmation token should be able to confirm an account' do
user = create_user(:confirm => false)
assert_not user.confirmed?
visit user_confirmation_path(:perishable_token => user.perishable_token)
visit user_confirmation_path(:confirmation_token => user.confirmation_token)
assert_template 'sessions/new'
assert_contain 'Your account was successfully confirmed!'
@@ -40,7 +40,7 @@ class ConfirmationTest < ActionController::IntegrationTest
test 'user already confirmed user should not be able to confirm the account again' do
user = create_user
visit user_confirmation_path(:perishable_token => user.perishable_token)
visit user_confirmation_path(:confirmation_token => user.confirmation_token)
assert_template 'confirmations/new'
assert_have_selector '#errorExplanation'

View File

@@ -20,7 +20,7 @@ class PasswordTest < ActionController::IntegrationTest
end
def reset_password(options={}, &block)
visit edit_user_password_path(:perishable_token => options[:perishable_token])
visit edit_user_password_path(:reset_password_token => options[:reset_password_token])
assert_response :success
assert_template 'passwords/edit'
@@ -69,21 +69,21 @@ class PasswordTest < ActionController::IntegrationTest
assert warden.authenticated?(:user)
end
test 'not authenticated user with invalid perishable token should not be able to change his password' do
test 'not authenticated user with invalid reset password token should not be able to change his password' do
user = create_user
reset_password :perishable_token => 'invalid_perishable'
reset_password :reset_password_token => 'invalid_reset_password'
assert_response :success
assert_template 'passwords/edit'
assert_have_selector '#errorExplanation'
assert_contain 'invalid confirmation'
assert_contain 'Reset password token is invalid'
assert_not user.reload.valid_password?('987654321')
end
test 'not authenticated user with valid perisable token but invalid password should not be able to change his password' do
test 'not authenticated user with valid reset password token but invalid password should not be able to change his password' do
user = create_user
request_forgot_password
reset_password :perishable_token => user.reload.perishable_token do
reset_password :reset_password_token => user.reload.reset_password_token do
fill_in 'Password confirmation', :with => 'other_password'
end
@@ -97,7 +97,7 @@ class PasswordTest < ActionController::IntegrationTest
test 'not authenticated user with valid data should be able to change his password' do
user = create_user
request_forgot_password
reset_password :perishable_token => user.reload.perishable_token
reset_password :reset_password_token => user.reload.reset_password_token
assert_template 'sessions/new'
assert_contain 'Your password was changed successfully.'

View File

@@ -36,7 +36,7 @@ class ConfirmationInstructionsTest < ActionMailer::TestCase
test 'body should have link to confirm the account' do
host = ActionMailer::Base.default_url_options[:host]
confirmation_url_regexp = %r{<a href=\"http://#{host}/users/confirmation\?perishable_token=#{@user.perishable_token}">}
confirmation_url_regexp = %r{<a href=\"http://#{host}/users/confirmation\?confirmation_token=#{@user.confirmation_token}">}
assert_match confirmation_url_regexp, @mail.body
end
end

View File

@@ -7,7 +7,8 @@ class ResetPasswordInstructionsTest < ActionMailer::TestCase
I18n.backend.store_translations :en, {:devise => { :notifier => { :reset_password_instructions => 'Reset instructions' } }}
Notifier.sender = 'test@example.com'
@user = create_user
@mail = Notifier.deliver_reset_password_instructions(@user)
@user.send_reset_password_instructions
@mail = ActionMailer::Base.deliveries.last
end
test 'email sent after reseting the user password' do
@@ -36,7 +37,7 @@ class ResetPasswordInstructionsTest < ActionMailer::TestCase
test 'body should have link to confirm the account' do
host = ActionMailer::Base.default_url_options[:host]
confirmation_url_regexp = %r{<a href=\"http://#{host}/users/password/edit\?perishable_token=#{@user.perishable_token}">}
confirmation_url_regexp = %r{<a href=\"http://#{host}/users/password/edit\?reset_password_token=#{@user.reset_password_token}">}
assert_match confirmation_url_regexp, @mail.body
end
end

View File

@@ -10,6 +10,37 @@ class ConfirmableTest < ActiveSupport::TestCase
assert_not field_accessible?(:confirmed_at)
end
test 'should not have confirmation token accessible' do
assert_not field_accessible?(:confirmation_token)
end
test 'should not have confirmation sent at accessible' do
assert_not field_accessible?(:confirmation_sent_at)
end
test 'should generate confirmation token after creating a record' do
assert_nil new_user.confirmation_token
assert_not_nil create_user.confirmation_token
end
test 'should regenerate confirmation token each time' do
user = create_user
3.times do
token = user.confirmation_token
user.reset_confirmation!
assert_not_equal token, user.confirmation_token
end
end
test 'should never generate the same confirmation token for different users' do
confirmation_tokens = []
10.times do
token = create_user.confirmation_token
assert !confirmation_tokens.include?(token)
confirmation_tokens << token
end
end
test 'should confirm a user updating confirmed at' do
user = create_user
assert_nil user.confirmed_at
@@ -17,11 +48,11 @@ class ConfirmableTest < ActiveSupport::TestCase
assert_not_nil user.confirmed_at
end
test 'should clear perishable token while confirming a user' do
test 'should clear confirmation token while confirming a user' do
user = create_user
assert_present user.perishable_token
assert_present user.confirmation_token
user.confirm!
assert_nil user.perishable_token
assert_nil user.confirmation_token
end
test 'should verify whether a user is confirmed or not' do
@@ -43,27 +74,27 @@ class ConfirmableTest < ActiveSupport::TestCase
test 'should find and confirm an user automatically' do
user = create_user
confirmed_user = User.confirm!(:perishable_token => user.perishable_token)
confirmed_user = User.confirm!(:confirmation_token => user.confirmation_token)
assert_not_nil confirmed_user
assert_equal confirmed_user, user
assert user.reload.confirmed?
end
test 'should return a new user with errors if no user exists while trying to confirm' do
confirmed_user = User.confirm!(:perishable_token => 'invalid_perishable_token')
confirmed_user = User.confirm!(:confirmation_token => 'invalid_confirmation_token')
assert confirmed_user.new_record?
end
test 'should return errors for a new user when trying to confirm' do
confirmed_user = User.confirm!(:perishable_token => 'invalid_perishable_token')
assert_not_nil confirmed_user.errors[:perishable_token]
assert_equal "invalid confirmation", confirmed_user.errors[:perishable_token]
confirmed_user = User.confirm!(:confirmation_token => 'invalid_confirmation_token')
assert_not_nil confirmed_user.errors[:confirmation_token]
assert_equal 'is invalid', confirmed_user.errors[:confirmation_token]
end
test 'should generate errors for a user email if user is already confirmed' do
user = create_user
user.confirm!
confirmed_user = User.confirm!(:perishable_token => user.perishable_token)
confirmed_user = User.confirm!(:confirmation_token => user.confirmation_token)
assert confirmed_user.confirmed?
assert confirmed_user.errors[:email]
end
@@ -109,11 +140,11 @@ class ConfirmableTest < ActiveSupport::TestCase
assert_equal 'not found', confirmation_user.errors[:email]
end
test 'should reset perishable token before send the confirmation instructions email' do
test 'should reset confirmation token before send the confirmation instructions email' do
user = create_user
token = user.perishable_token
token = user.confirmation_token
confirmation_user = User.send_confirmation_instructions(:email => user.email)
assert_not_equal token, user.reload.perishable_token
assert_not_equal token, user.reload.confirmation_token
end
test 'should reset confirmation status when sending the confirmation instructions' do
@@ -156,12 +187,12 @@ class ConfirmableTest < ActiveSupport::TestCase
assert_not user.reload.confirmed?
end
test 'should reset perishable token when updating email' do
test 'should reset confirmation token when updating email' do
user = create_user
token = user.perishable_token
token = user.confirmation_token
user.email = 'new_test@example.com'
user.save!
assert_not_equal token, user.reload.perishable_token
assert_not_equal token, user.reload.confirmation_token
end
test 'should not be able to send instructions if the user is already confirmed' do

View File

@@ -1,58 +0,0 @@
require 'test/test_helper'
class PerishableTest < ActiveSupport::TestCase
test 'should not have perishable token accessible' do
assert_not field_accessible?(:perishable_token)
end
test 'should generate perishable token after creating a record' do
assert_nil new_user.perishable_token
assert_not_nil create_user.perishable_token
end
test 'should reset perisable token each time' do
user = new_user
3.times do
token = user.perishable_token
user.reset_perishable_token
assert_not_equal token, user.perishable_token
end
end
test 'should reset perishable token and save the record' do
user = new_user
assert_nil user.perishable_token
user.reset_perishable_token!
assert_not_nil user.perishable_token
assert !user.new_record?
end
test 'should save without validations when reseting perisable token' do
user = new_user
user.expects(:valid?).never
user.reset_perishable_token!
end
test 'should never generate the same perishable token for different users' do
perishable_tokens = []
10.times do
token = create_user.perishable_token
assert !perishable_tokens.include?(token)
perishable_tokens << token
end
end
test 'should not change perishable token when updating' do
user = create_user
token = user.perishable_token
user.expects(:perishable_token=).never
user.save!
assert_equal token, user.perishable_token
end
test 'should generate a sha1 hash for perishable token' do
ActiveSupport::SecureRandom.expects(:base64).with(15).twice.returns('perishable token')
assert_equal 'perishable token', create_user.perishable_token
end
end

View File

@@ -6,6 +6,35 @@ class RecoverableTest < ActiveSupport::TestCase
setup_mailer
end
test 'should not have reset password token accessible' do
assert_not field_accessible?(:reset_password_token)
end
test 'should not generate reset password token after creating a record' do
assert_nil new_user.reset_password_token
assert_nil create_user.reset_password_token
end
test 'should regenerate reset password token each time' do
user = create_user
3.times do
token = user.reset_password_token
user.send_reset_password_instructions
assert_not_equal token, user.reset_password_token
end
end
test 'should never generate the same reset password token for different users' do
reset_password_tokens = []
10.times do
user = create_user
user.send_reset_password_instructions
token = user.reset_password_token
assert !reset_password_tokens.include?(token)
reset_password_tokens << token
end
end
test 'should reset password and password confirmation from params' do
user = create_user
user.reset_password('123456789', '987654321')
@@ -17,11 +46,13 @@ class RecoverableTest < ActiveSupport::TestCase
assert create_user.reset_password!('123456789', '123456789')
end
test 'should clear perishable token while reseting the password' do
test 'should clear reset password token while reseting the password' do
user = create_user
assert_present user.perishable_token
assert_nil user.reset_password_token
user.send_reset_password_instructions
assert_present user.reset_password_token
user.reset_password!('123456789', '123456789')
assert_nil user.perishable_token
assert_nil user.reset_password_token
end
test 'should not reset password with invalid data' do
@@ -30,12 +61,12 @@ class RecoverableTest < ActiveSupport::TestCase
assert_not user.reset_password!('123456789', '987654321')
end
test 'should reset perishable token and send instructions by email' do
test 'should reset reset password token and send instructions by email' do
user = create_user
assert_email_sent do
token = user.perishable_token
token = user.reset_password_token
user.send_reset_password_instructions
assert_not_equal token, user.perishable_token
assert_not_equal token, user.reset_password_token
end
end
@@ -58,11 +89,11 @@ class RecoverableTest < ActiveSupport::TestCase
assert_equal 'not found', reset_password_user.errors[:email]
end
test 'should reset perishable token before send the reset instructions email' do
test 'should reset reset password token before send the reset instructions email' do
user = create_user
token = user.perishable_token
token = user.reset_password_token
reset_password_user = User.send_reset_password_instructions(:email => user.email)
assert_not_equal token, user.reload.perishable_token
assert_not_equal token, user.reload.reset_password_token
end
test 'should send email instructions to the user reset it\'s password' do
@@ -72,30 +103,30 @@ class RecoverableTest < ActiveSupport::TestCase
end
end
test 'should find a user to reset it\'s password based on perishable_token' do
test 'should find a user to reset it\'s password based on reset_password_token' do
user = create_user
reset_password_user = User.reset_password!(:perishable_token => user.perishable_token)
reset_password_user = User.reset_password!(:reset_password_token => user.reset_password_token)
assert_not_nil reset_password_user
assert_equal reset_password_user, user
end
test 'should return a new user when trying to reset it\'s password if no perishable_token is found' do
reset_password_user = User.reset_password!(:perishable_token => 'invalid_token')
test 'should return a new user when trying to reset it\'s password if no reset_password_token is found' do
reset_password_user = User.reset_password!(:reset_password_token => 'invalid_token')
assert_not_nil reset_password_user
assert reset_password_user.new_record?
end
test 'should add error to new user email if no perishable token was found' do
reset_password_user = User.reset_password!(:perishable_token => "invalid_token")
assert reset_password_user.errors[:perishable_token]
assert_equal 'invalid confirmation', reset_password_user.errors[:perishable_token]
test 'should add error to new user email if no reset password token was found' do
reset_password_user = User.reset_password!(:reset_password_token => "invalid_token")
assert reset_password_user.errors[:reset_password_token]
assert_equal 'is invalid', reset_password_user.errors[:reset_password_token]
end
test 'should reset successfully user password given the new password and confirmation' do
user = create_user
old_password = user.password
reset_password_user = User.reset_password!(
:perishable_token => user.perishable_token,
:reset_password_token => user.reset_password_token,
:password => 'new_password',
:password_confirmation => 'new_password'
)

View File

@@ -16,11 +16,13 @@ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":me
ActiveRecord::Schema.define(:version => 1) do
[:users, :admins].each do |table|
create_table table do |t|
t.string :email, :null => false
t.string :encrypted_password, :null => false
t.string :password_salt, :null => false
t.string :perishable_token
t.string :email, :null => false
t.string :encrypted_password, :null => false
t.string :password_salt, :null => false
t.string :confirmation_token
t.datetime :confirmation_sent_at
t.datetime :confirmed_at
t.string :reset_password_token
end
end
end