Yesterday’s Thoughts

February 21, 2006

Bug in acts_as_authenticated

I found a bug in the acts_as_authenticated plugin. The activate method in User fails to update the user record when using both activate and 2-way reversible encryption. The symptom that I was is that @user.save was false in the controller.

It fails at this line:

update_attributes(:activated_at => Time.now.utc, :activation_code => nil)

This fails because there are a series of validations on saving the model. These on save validations on password_confirmation work (assuming correct values) when the user is created and when the password is changed, but fail on other saves of the user, particularly on activation, but would also fail if acts_as_authenticated had an edit method, or a last_seen method, or any other method that changed the user without also changing the password with a confirmation.

The rails wiki has a proposed fix, which works for activate only if not also using 2-way reversible encryption. The fix causes these validations to be attempted only if password_required, which in turn tests if password.blank? is false.

Two-way reversible encryption populates the model with the value of password, so that password.blank? is always false and password_required is always true.

I resolved the problem in acts_as_authenticated by making the following changes:

validates_presence_of :password_confirmation, 
                 :if => :confirmation_required? # not :password_required
validates_confirmation_of :password, 
                 :if => :confirmation_required? #ditto

And then I added the following:

after_save '@confirm_password = false'
	
def initialize(attributes = nil)
  super
  @confirm_password = true
end

def change_password(pass, confirm = nil)
  self.password = pass
  self.password_confirmation = confirm.nil? ? pass : confirm
  @confirm_password = true
end

protected

def confirmation_required?
  @confirm_password
end

Hope that helps.

1 Comment(s)

  1. Taryn East | May 25, 2007 | Reply

    I had a similar issue with that line failing validations. Can’t remember what set it off (I doubt it was two-way encryption).
    I resolved it by separating the “update_attributes” call into two update_attribute calls. That bypasses the validations.

Post a Comment