Reputation: 147
I'm trying to use BCrypt in my rails app to save user's passwords securely. I'm able to save the encrypted password just fine and even compare it against the original plain text string to successfully verify it. The problem seems to be that every time I encrypt the password I get a different output (I'm assuming due to some salt or something) and the verification doesn't hold up after being saved to the database (I'm saving in an sqlite3 database if it makes a difference).
For example (in a Rails console):
2.1.2 :001 > u = User.new
=> #<User id: nil, created_at: nil, updated_at: nil, username: nil, password: nil>
2.1.2 :002 > u.username = "jdoe"
=> "jdoe"
2.1.2 :002 > u.password = BCrypt::Password.create("snoopy")
=> "$2a$10$jJpHrgUmAh.YULY9CJUDjOSb9audpeD3Hx.66uVhix.WEDDB0HO.y"
2.1.2 :003 > u.password == "snoopy"
=> true
2.1.2 :004 > u.save
=> true
u2 = User.find_by_username("jdoe")
=> [user "jdoe" is found here]
2.1.2 :006 > u2.password == "snoopy"
=> false
I know there are ready made solutions like has_secure_password, but I'd like to implement this manually to really understand what's going on.
Upvotes: 1
Views: 3396
Reputation: 12986
When you set the password, you are setting it to a BCrypt::Password object. I guess that when you load it from the database it is loaded as a simple string, so ==
will not encrypt the given string with the original salt.
Try the following:
(...)
u.save
u2 = User.find_by_username("jdoe")
BCrypt::Password.new(u2.password) == "snoopy"
It seems Rails provides a after_find
callback so if you define something like this
class User < ActiveRecord::Base
after_find do |user|
user.password = BCrypt::Password.new(user.password)
end
end
it should work as you intended.
Upvotes: 1