Sterling Duchess
Sterling Duchess

Reputation: 2080

Rails > Devise password encryption

I'm trying to implement a method to allow password to be changed from another service outside devise anyhow.

# Profile password change
def change_password(oldpass, newpass)
    pepper  = nil
    cost    = 10

    # Encrypt plain text passwords
    encrypt_old     = ::BCrypt::Password.create("#{oldpass}#{pepper}", :cost => cost).to_s

    # Validate old
    if self.encrypted_password == encrypt_old
        encrypt_new     = ::BCrypt::Password.create("#{newpass}#{pepper}", :cost => cost).to_s
        self.encrypted_password = encrypt_new
        self.save
    else
        Logger.new("Wrong old password!")
    end
end

It seems i got the password encryption wrong oldpass contains a plain text of old password i need to hash it see if it matches the current password then allow new password to be stored. However all that i'm getting is wrong password.

Reworked:

def change_password(oldpass, newpass)
    if valid_password?(oldpass)
        password = newpass
        save
        return true
    else
        return false
    end
end

Upvotes: 5

Views: 13380

Answers (2)

joshhepworth
joshhepworth

Reputation: 3066

With Devise, you don't need to handle using bcrypt yourself. By default, it handles this and the change password method. You can look at source here or just look in config/intitalizers/devise.rb in your Rails app.

Also, if you use the #update_with_password method provided by Devise, then you can pass it a hash like this:

{ :current_password => 'pass', :password => 'pass_new', :password_confirmation => 'pass_new' }

Or you can omit :password_confirmation if you don't want the user to have to provide a confirmation.

EDIT: I used the wrong field; it should have been 'current_password' instead of 'old_password'.

Here's the method in question in the source for Devise:

  # Update record attributes when :current_password matches, otherwise returns
  # error on :current_password. It also automatically rejects :password and
  # :password_confirmation if they are blank.
  def update_with_password(params, *options)
    current_password = params.delete(:current_password)

    if params[:password].blank?
      params.delete(:password)
      params.delete(:password_confirmation) if params[:password_confirmation].blank?
    end

    result = if valid_password?(current_password)
      update_attributes(params, *options)
    else
      self.assign_attributes(params, *options)
      self.valid?
      self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
      false
    end

    clean_up_passwords
    result
  end

View on GitHub

Upvotes: 3

You don't need to encrypt the password yourself, if you are in the application or in Rails console.

Just update the user following way and Devise will take care of it itself.

user.password = new_password
user.save

Devise will then encrypt the password and store it. You just need to ensure that user.password_confirmation is nil. If password_confirmation is anything else, it will be matched against password.

EDIT

You can check the existing password with: user.valid_password?(old_password)

Upvotes: 11

Related Questions