tvalent2
tvalent2

Reputation: 5009

User Authentication: Providing separate errors for invalid email/password entry

In my Rails app I'm trying to produce a separate flash.now[:alert] for invalid :email and :password, respectively. So if a user enters the correct email but wrong password, the :alert warns the user of an invalid password and vice versa. Here's what I have in my SessionsController:

def create
  if user = User.authenticate(params[:email], params[:password])
    session[:user_id] = user.id
    redirect_to user.profile, :notice => "Logged in successfully"
  elsif user.email != params[:email]
    session[:email] = @user.email
    flash.now[:alert] = "Invalid email. Try again!"
    render :action => 'new'
  else
    session[:password] = @user.password
    flash.now[:alert] = "Invalid password. Try again!"
    render :action => 'new'
  end
end

Rendering this gives me an undefined method for email. Can anyone help me figure out what I'm doing wrong?

Upvotes: 1

Views: 711

Answers (1)

Maurício Linhares
Maurício Linhares

Reputation: 40333

DISCLAIMER: Obviously this is a really bad idea as an attacker could keep on trying emails until he found one that did match and then he could start trying passwords for this email he knows exists at your database, but you're asking, so it's up to you deciding to do this or not.

Your authenticate method obviously only returns the user if the email and password did match, change your authenticate method to return a boolean and a user if there is any available. It would look somewhat like this:

def authenticate(email, password)
  u = first(:conditions => {:email => email, :state => 'active'})
  u && u.authenticated?(password) ? [true, u] : [false, u]
end

Then, at your controller:

def create
  result , user = User.authenticate(params[:email], params[:password])
  if result 
    session[:user_id] = user.id
    redirect_to user.profile, :notice => "Logged in successfully"
  elsif user
    session[:email] = @user.email
    flash.now[:alert] = "Invalid email. Try again!"
    render :action => 'new'
  else
    session[:password] = @user.password
    flash.now[:alert] = "Invalid password. Try again!"
    render :action => 'new'
  end
end

And this should work.

Upvotes: 2

Related Questions