1

I've tried this many ways but it seems BCrypt is encrypting a users submitted password twice.

When a user signs up- Bcrypt works great, and I am able to sign in. But when I try and update their password in my password_resets_controller, I'm no longer able to log in. My database shows that the password is being updated and hashed, but I can't sign in.

I even removed the line @customer.save, yet my database is still showing that the password is being updated !

Is something being updated under the hood I'm not aware of? See relatd SO thread: Updating password with BCrypt

In my Customer.rb

require 'bcrypt'
class Customer < ActiveRecord::Base
  include BCrypt

  def password
    @password ||= Password.new(password_hash)
  end

  def password=(new_password)
    @password = Password.create(new_password)
    self.password_hash = @password
  end

  def self.authenticate(email, password)
    @customer = Customer.find_by_email(email)
    if @customer && @customer.password == password
      return @customer
    else
      return nil
    end
  end
end

In my customer_controller, the create code that actually works

  require 'bcrypt'
 class CustomersController < ApplicationController

  def create_customer_account_iphone
  @customer_count = Customer.where(email: params[:email]).size rescue nil
  if(@customer_count == 0 || @customer_count == nil ||)
    @customer = Customer.new(first_name: params[:first_name], email: params[:email])
    @customer.password = params[:password] //this calls my model methods
    @customer.save  //here I am saving
    unless (!@customer.save)
     respond_to do |format|
      msg = {:status => "SUCCESS", :messages => "Customer created", :data => @customer.as_json}
      format.json  { render :json => msg } # don't do msg.to_json
    end
  else
    respond_to do |format|
      msg = {:status => "FAILED", :messages => "Customer Not Saved"}
      format.json  { render :json => msg } # don't do msg.to_json
    end
  end


def sign_in_iphone
@customer = Customer.authenticate(params[:email], params[:password])
unless (@customer == 0 || @customer == nil)
  respond_to do |format|
    msg = {:status => "SUCCESS", :message => "CUSTOMER", :data => @customer.as_json}
    format.json  { render :json => msg } # don't do msg.to_json
  end
  else
    respond_to do |format|
      msg = {:status => "FAILED"}
      format.json  { render :json => msg } # don't do msg.to_json
    end
  end
end

In my password_reset_controller

class CustomerPasswordResetsController < ApplicationController

   def edit
 @customer = Customer.find_by_password_reset_token!(params[:id])
end


def update
@customer = Customer.find_by_password_reset_token!(params[:id])
if @customer.password_reset_sent_at < 2.hours.ago
  redirect_to new_customer_password_reset_path, :alert => "Password  reset has expired."
else
  @customer.password_hash = BCrypt::Password.create(params[:password])
  # @customer.save
  unless !@customer.save
    redirect_to new_customer_password_reset_path, :alert => "Password has been reset!"
  else
    render :edit
  end
 end
end

In my password_reset.html.erb

<%= form_for @customer, :url => customer_password_reset_path(params[:id]), :method => :patch  do |f| %>
<% if @customer.errors.any? %>
    <div class="error_messages">
      <h2>Form is invalid</h2>
      <ul>
        <% for message in @customer.errors.full_messages %>
            <li><%= message %></li>
        <% end %>
      </ul>
    </div>
<% end %>
<div class="field">
  <%= f.label :password %>
  <%= f.password_field :password %>
</div>
<div class="field">
  <%= f.label :password_confirmation %>
  <%= f.password_field :password_confirmation %>
</div>
<div class="actions"><%= f.submit "Update Password" %></div>
Community
  • 1
  • 1
DaynaJuliana
  • 1,144
  • 1
  • 14
  • 33

2 Answers2

3

Given your form the new password will be in params[:customer][:password] not params[:password] - your existing code always sets the password to nil.

Changing the password resets controller update action to instead do

 @customer.password = params[:customer][:password]

should do the trick. As a side note the commented out customer.save doesn't matter because you save again on the next line.

Next time something like this happens consider using the debugger to examine what is happening in your action - it would be easy enough to spot that the password was being set to nil. The debugging guide has lots more tip on this.

Frederick Cheung
  • 83,189
  • 8
  • 152
  • 174
1

It's possible that you're assigning password as well as doing some post-processing with password_hash. The way this is intended to be used is via password alone if you have the model code with that password= method. This means you won't need to do any additional work beyond simply assigning it.

What you want in your password_reset method is:

@customer.password = params[:password]
@customer.save!

That should take care of it by running it through the appropriate model code.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • Unfortunately I tried this first and it didn't work. Just reset it to this and it still doesn't work. For refernce I essentially copied the 2nd half of this railscast with the Bcrypt gem intsructions http://railscasts.com/episodes/274-remember-me-reset-password & https://github.com/codahale/bcrypt-ruby – DaynaJuliana Feb 12 '15 at 16:07
  • Also the .save isn't even necessary ! It saves regardless. I find this odd and a sign some callbacks is affecting this. Would ` before_action :set_customer, only: [:show, :edit, :update, :destroy]` affect anything – DaynaJuliana Feb 12 '15 at 16:08
  • The first thing to check, as always, is if there's anything interesting in `log/development.log`. A `save!` should be required since I don't see anything in the `password=` method that does that. – tadman Feb 12 '15 at 16:24
  • I agree, but I just removed the .save! and the password in the DB still changes to a new hash. Would the `patch` method having something to do with this ? – DaynaJuliana Feb 12 '15 at 16:30
  • I also just added my sign in method (I'm using my models `authenticate` method. This only works when I create an account. Once I update the password It always returns `FAILED` – DaynaJuliana Feb 12 '15 at 16:40
  • The method used only triggers different actions, but not how the records are handled. You really need to look more closely at `log/development.log` to see what's going on in there, in particular the queries that are or aren't being run, and the actions being executed. – tadman Feb 12 '15 at 16:57