rubysinatrabcrypt-ruby

Password Authentication using BCrypt


I'm trying to build a very simple login page with username and password authentication using BCrypt.

There are two features, the first is to create a username and password, and the second is authenticate using login page. (create a new user, login with that user)

Below is the controller and User model code for creating a username and password. View model is not included, but it includes a simple form asking the user to create a username, password and confirm password

Controller:

get '/new_user' do 
    erb :new_user
end 

post '/new_user' do
    if @password == @password_confirm
        new_user = User.new(username: params[:username])
        new_user.password = params[:password]
        new_user.insert_user
        redirect '/index'
    else
        redirect '/new_user'
    end 
end 

Model:

def initialize(params = {})
    @username = params.fetch(:username, "test")
    @password = params.fetch(:password, "test")
end 

def password=(new_password)
    @password = BCrypt::Password.create(new_password)
    @db_password = BCrypt::Password.new(@password)
end 

def insert_user
    db = SQLite3::Database.open("helper_database")
    db_results_as_hash = true
    db.execute("INSERT INTO users (username, password) VALUES (?,?)", [@username, @db_password])
end 

In the above, a new instance is created to pass username and password. If password and confirm password match, the password method will create an encrypted password, and the insert method will insert username and the encrypted password into the database using simple SQL command.

After the username and encrypted password have been inserted into the database. I want to use the login page to validate. I create a new User instance, passing the username and password params to the authentication method shown below. The method will look up the password corresponding the params username and evaluate the params password against the encrypted password.

Below is the controller and User model for Login

Controller:

get '/login' do 
 erb :login
end 

post '/login' do 
    @user = User.new(username: params[:username], password: params[:password])
    if @user.authenticate()
        redirect '/index'
    else 
        erb :login
    end 
end 

Model:

    def authenticate
        db = SQLite3::Database.open("helper_database")
        db.results_as_hash = true
        password = db.execute("SELECT password FROM users WHERE username = '#{@username}'")
        password = password[0]["password"]
        password = BCrypt::Password.new(password)
        @password == password
  end 

Above, I'm attempting to retrieve the encrypted password (string format) from SQL, convert to a Bcrypt object and validate the password against it. Theoretically, the method should return true assuming the entered password is correct, but it returns false.

What might the issue be?


Solution

  • You don’t appear to be hashing the incoming password when you authenticate. This is because you’re doing @password == password where @password is the plain-text String password (from User#initialize from post '/login').

    You should flip the comparison so it uses BCrypt::Password#==: password == @password.