How should I check passwords in Ruby? - ruby

I am using Ruby to manage users in a database.
I am using pass = Digest::MD5.hexdigest() to encrypt passwords before they are being added to the database.
I need to create a function to check that a given password matches that stored in the database but I'm not sure how I should do it.
Do I use pass = Digest::MD5.hexdigest() on the user provided password, and then check that against what is returned from the database?
This is correctpassword?:
def correctpassword?(nick, pass)
user = nick
pass = Digest::MD5.hexdigest(pass)
db = SQLite3::Database.new "database.db"
db.execute("SELECT * FROM t1 WHERE user = ? and pass = ?", user, pass)
!results.empty?
end
This is attempting to use correctpassword?:
if clt.registered?(#nick)
if clt.correctpassword?(#nick, #pass)
sv_send 'NOTICE', #nick, ":Correct password."
else
sv_send 'NOTICE', #nick, ":Incorrect password."
end
end
I don't see either notices. Using correctpassword? seems to break things.
This works though:
if clt.registered?(#nick)
sv_send 'NOTICE', #nick, ":This account is registered."
end

There is no assignment for results var. Do results = db.execute("SELECT * FROM t1 WHERE user = ? and pass = ?", user, pass)

MD5 is a one-way hash encryption algorithm. There is no way to directly decrypt a MD5 hash. The algorithm itself uses modular arithmetic to package the serialized string and there is no way to go backwards from that.
So I think you should convert the password to MD5 which user try to enter and compare that hash with stored encrypted password in db.
Eg:
> stored_password_in_db = Digest::MD5.hexdigest('gagan')
#=> "cc18a19beff0bdf874861a4dae6124b6"
> user_enter_password_for_login = Digest::MD5.hexdigest('gagan')
#=> "cc18a19beff0bdf874861a4dae6124b6"
> stored_password_in_db == user_enter_password_for_login
#=> true
> user_enter_password_for_login = Digest::MD5.hexdigest('Gagan')
#=> "f52bb23033354697e8f55abdaed9d94f"
> stored_password_in_db == user_enter_password_for_login
#=> false

Related

Ruby update all same object data in hash array for JSON.parse

So a = first is
=> <Ng::EntityConfiguration id: 15903, entity_id: 1, entity_type: "Ng::Company", key: "wpa2.psk", value: "[{"ssid":"Main-Hall-Staff","password":"abc123","dhcp":"Enabled"},{"ssid":"Main-Hall-Guest","password":"def456","dhcp":"Disabled"}]", created_at: "2016-11-08 11:03:51", updated_at: "2016-11-08 11:03:51", name: "WIFI/Main Hall">
I have a.value which is will return:
"[
{\"ssid\":\"Main-Hall-Staff\",\"password\":\"abc123\"},
{\"ssid\":\"Main-Hall-Guest\",\"password\":\"def456\"}
]"
My question is, how to update both password value and save it?
new_pass1 = 'xyz123'
new_pass2 = 'xyz321'
I have tried code (below) but this will only update first password if i only have one hash_array.
Here is my full code
def encrypt_pass
# get the actual password
parse = JSON.parse(self.value)
get_pass = parse.last['password']
# encrypt the password
crypt = ActiveSupport::MessageEncryptor.new(ENV["SECRET_KEY_BASE"])
encrypted = crypt.encrypt_and_sign(get_pass)
# save the new encrypted password
parse.first['password'] = encrypted
encrypt_pass = parse.to_json
self.value = encrypt_pass
end
Just to be clear, you're trying to update both the Main-Hall-Staff password and the Main-Hall-Guest password (all passwords) from your record to be the encrypted version of themselves? I'm assuming this method is called in a before_save callback of some sort? If you show more code related to the model I can give you more details.
def encrypt_pass
# Changed the name to devises, always use easy to understand naming
# Also rescuing from a JSON parse error, this isnt always recommended
# as it hides other errors that might be unrelated to parsing
devices = JSON.parse(self.value) rescue []
crypt = ActiveSupport::MessageEncryptor.new(ENV["SECRET_KEY_BASE"])
devices.each do |device|
# get the actual password
password = device['password']
# encrypt the password
encrypted_pass = crypt.encrypt_and_sign(password)
# Save the encrypted password
device['password'] = encrypted_pass
end
self.value = devices.to_json
end
Hopefully you have some logic surrounding when this method is called as you dont want to encrypt an already encrypted password.

Ruby BCrypt hash comparison not working

I am a new comer to Ruby, so apologies if this question has already been answered. I have read the other questions and still cannot figure out what I am doing wrong.
I am creating hashed passwords for storing in a db like this:
new_user.password = BCrypt::Password.create(unhashed_password)
# Write the user to database
new_user.store_user
I then retrieve the user from the db by checking against the inputed user name, and then check the password like this:
# Get user from the database
def self.get_user(check_user_name)
db = User.open_db
user = User.new
user_arr = db.execute("SELECT * FROM user_data WHERE user_name = ?", check_user_name).first
db.close
# if the user exists check the password
if user_arr.size != 0
print "Enter your password : "
# Get password from user
user_input_password_attempt = gets.chomp
end
# Parse the db user into a user class if password guess is correct
stored_password = BCrypt::Password.new(user_arr[2])
if user_input_password_attempt == stored_password
##users_logged_in += 1
user.user_id = user_arr[0]
user.user_name = user_arr[1]
user.password = user_arr[2]
return user
end
:no_user
end
My problem is that the var stored_password is returning a hash and != user_input_password_attempt
I have read the Ruby-Doc and googled this extensively
When you use == you are actually calling the == method defined on the object on the left hand side, passing the right hand side as argument:
a == b
is equivalent to
a.==(b)
Depending on the object you call the == method you might receive a different result. In other words:
a == b
might or might not return a different result than
b == a
While personally I think this is nonsense and equality operators should be transitive, symetric and reflexive the BCrypt people have decided to implement it in another way:
def ==(secret)
super(BCrypt::Engine.hash_secret(secret, #salt))
end
(taken from http://bcrypt-ruby.rubyforge.org/classes/BCrypt/Password.html#M000009)
This means that you have to write:
stored_password = BCrypt::Password.new(user_arr[2])
if stored_password == user_input_password_attempt
...
end
in order to call the == method on the Password instance.

Looping ruby hash and output specific element

I am trying to loop through a hash for specific data to output. If I want to output all usernames. This is how I can do it one at a time but its not what I want.
puts username = json["users"][0]["username"]
puts username = json["users"][1]["username"]
also tried
json.each { |x| puts json["users"][x]["username"]}
This is the hash structure
{"success"=>true, "users"=>[{"id"=>"1523493", "username"=>"myname","age"=>"21"},{"id"=>"653172", "username"=>"anothername","age"=>"65"}]}
sorry I didnt make my question clear enough. I am wanting to iterate the hash for "username" and then i can loop through each username and output specific data before moving to next username
You can loop your json like this
json["users"].each do |u|
username = u["username"]
#Do some logic with username
#like user = User.find_by_username(username)
end
You can get all the usernames in one go by doing something like this:
json = { "users" => [{"id"=>"1523493", "username"=>"myname"},{"id"=>"653172", "username"=>"anothername"}] }
json["users"].map { |user| user["username"] }
# => ["username", "anothername"]
The above will provide you with an array of usernames to do with as you see fit. :)
Hope it helps!
h = {"success"=>true,
"users"=>[{"id"=>"1523493", "username"=>"myname","age"=>"21"},
{"id"=>"653172", "username"=>"anothername","age"=>"65"}]}
h["users"].map { |user| user["username"] }
#=> ["myname", "anothername"]

Get index of database iteration on ruby

I'm trying to iterate through database file with gdbm, create objects with values I get and assign them to an array. The problem is I can't seem to get index of iteration and I need it for my array. Here is the code:
bots_directory = "../data/bots.db"
bots = Array.new
GDBM.new(bots_directory).each_pair.with_index do |nickname, password, index|
bots[index] = Bot.new(nickname, password)
end
Error I get:
`[]=': no implicit conversion from nil to integer (TypeError)
Also, will database file close after the block is executed?
I would use each_with_index instead of each_pair.with_index:
bots_directory = "../data/bots.db"
bots = []
GDBM.new(bots_directory).each_with_index do |(nickname, password), index|
bots[index] = Bot.new(nickname, password)
end
Or even simpler, since the index starts from 0 and increases by 1 anyway:
bots_directory = "../data/bots.db"
bots = []
GDBM.new(bots_directory).each_pair do |nickname, password|
bots << Bot.new(nickname, password)
end
Perhaps map is also an option?
bots_directory = "../data/bots.db"
bots = GDBM.new(bots_directory).map do |nickname, password|
Bot.new(nickname, password)
end

Ruby BCrypt hash comparison

I'm trying to implement what seems like a very simple authentication approach using Sinatra and BCrypt but clearly I'm missing something...
Users are preassigned a temporary password which is stored in plaintext in the db.
I authenticate against the temp password and then create both a salt and password_hash and write them as strings to the db (mongo in this case).
To authenticate I fetch the salt from the db and user password to compare.
post "/password_reset" do
user = User.first(:email => params[:email], :temp_password => params[:temp_password])
if dealer != nil then
password_salt = BCrypt::Engine.generate_salt
password_hash = BCrypt::Engine.hash_secret(params[:password], password_salt)
user.set(:password_hash => password_hash)
user.set(:password_salt => password_salt)
end
end
post "/auth" do
#user = User.first(:email => params[:email])
#user_hash = BCrypt::Password.new(#user.password_hash) #because the password_hash is stored in the db as a string, I cast it as a BCrypt::Password for comparison
if #user_hash == BCrypt::Engine.hash_secret(params[:password], #user.password_salt.to_s) then
auth = true
else
auth = false
end
end
The value returned by BCrypt::Engine.hash_secret(params[:password], password_salt) is different than what is stored in the db (both are of class BCrypt::Password, but they don't match).
What am I missing here? Many thanks in advance for any insight!
Marc
BCrypt::Password is a subclass of String, and it overrides the == method to make checking passwords easier. When you do
if #user_hash == BCrypt::Engine.hash_secret(params[:password], #user.password_salt.to_s)
you end up performing the hash twice, and so they don’t match. If you compared directly with #user.password_hash rather than using BCrypt::Password.new you should see that they match.
The more “correct” way to use bcrypt-ruby for passwords is to not use the Engine class at all, just the Password class. You don’t need to manage the salt yourself, bcrypt takes care of that and includes it in the password hash string:
password_salt = BCrypt::Engine.generate_salt
password_hash = BCrypt::Engine.hash_secret("s3kr1t!", password_salt)
puts password_salt
puts password_hash
produces something like this:
$2a$10$4H0VpZjyQO9SoAGdfEB5j.
$2a$10$4H0VpZjyQO9SoAGdfEB5j.oanIOc4zp3jsdTra02SkdmhAVpGK8Z6
You’ll get something slightly different if you run it, since a different salt will be generated, but you can see that the password hash includes the salt.
In your case, you want something like this:
post "/password_reset" do
user = User.first(:email => params[:email], :temp_password => params[:temp_password])
if dealer != nil then
password_hash = BCrypt::Password.create(params[:password])
user.set(:password_hash => password_hash) # no need to store the salt separately in the database
end
end
post "/auth" do
#user = User.first(:email => params[:email])
#user_hash = BCrypt::Password.new(#user.password_hash)
if #user_hash == params[:password] then # overridden == method performs hashing for us
auth = true
else
auth = false
end
end

Resources