Compare token plain text with token encrypted from Devise , Rails 5 - ruby-on-rails

I have app - Rails 5 with Devise. When user request new password, Devise generates token (plain text) which is send to the user email. After that Devise encrypt this token and save it to the database.
What I want is when user clicks to the link with token (plain text) for changing password, to compare this token from GET variable with this saved in the database (which is encrypted).
I see that Devise has method for this (validating URL token with encrypted in the database):
resource_class.confirm_by_token(params[:confirmation_token])
, but it is for registration (when user validates his email - confirmation link).
What I am trying is:
token_hash = BCrypt::Password.create(params[:reset_password_token])
user = User.find_by({reset_password_token: token_hash})
params[:reset_password_token] is the right value, but it returns nil.
The token is valid, because after that I can change the password.
If I do:
user = User.find_by_email('some email') # because I know which email is
token = BCrypt::Password.new(user.reset_password_token)
I am getting this error:
BCrypt::Errors::InvalidHash Exception: invalid hash
, but same code works, with user.encrypted_password.
I know how to get token from the URL, but how to compare it with this one saved in the database, which is encrypted ?

Devise gem encryption and decryption of password token
Devise gem has TokenGenerator class.Whenever you send reset_password_instructions
it generates friendly_token and corresponding encrypted token.It sends friendly_tokens in the email and stores encrypted token in Table.Now, whenever you submit that token It will encrypt your password token and compares it with one that is stored in your table.
Below example will elaborate more
Encryption
syntax:
Devise.token_generator.generate(class_name,column_name)
Example:
Devise.token_generator.generate(User,:reset_password_token)
["J9SkM77VENGQRZirVnoq", "2942dd29f8ddbd96ff59373a92bd3430e437f038efb81639532311a8d3a83467"]
So, *generate* method returns array with friendly_token at index 0 which will be sent to your email and a encrypted token at index 1 which will be stored in Table.
Decryption
syntax:
Devise.token_generator.digest(class_name,column_name, password_token)
Example
Devise.token_generator.digest(User,:reset_password_token, "J9SkM77VENGQRZirVnoq")
"2942dd29f8ddbd96ff59373a92bd3430e437f038efb81639532311a8d3a83467"

Related

Devise finding user by reset token

I'm trying to make an api for resetting password, I made devise handle the part when the user press on forgot password and sending him an email with a token but I tried to change it in the other part I needed to look up user using that token when he reset his password but Devise reset_password_token of the user (in the DB) is not like the token sent in the email, I only receive token, password, password_confirmation to make that API work, So I need to find that user using token sent in the email(User.where(reset_password_token: TOKEN)), Is there a way to convert token in the email to the one I have in the DB.
You have to check the reset_password_by_token class method which contains the logic. But you can use it directly:
User.reset_password_by_token({
reset_password_token: token,
password: password,
password_confirmation: password_confirmation
})
Link to current master code here

Fetch the Password and confirmation field of a Model object in Rails

Is there any way to fetch the password and password_confirmation field of a Model object in Rails.? Say for example, I have an user object
user = User.find(1)
Now, I want to fetch the value of the password field like this.
password = user.password
confirmation = user.password_confirmation.
I tried this, but it is returning nil.
I know, this is a security issue if they allow these fields to be accessible., But, I want to fetch these values for a feature to be implemented in our application.
Assuming you are using Devise, the only attribute related to the user's password is encrypted_password, it will return the BCrypt encrypted password. You can also read the password_salt User attribute.
You can see all Devise User Model attributes with: User.column_names

Secure Handling of Auth Tokens with Rails

I'm working on a new rails api project, and I'm trying to get to the best usability/security balance.
The user will establish a session by posting username/password to api/v1/sessions. For a valid user, it will create an authentication token, which is it's own activerecord model, associated by the polymorphic relationship authenticatable, giving me the flexibility to have multiple user models if I need to.
class AuthenticationToken < ActiveRecord::Base
before_create :digest_token
def self.from_authenticatable(authenticatable)
self.create(authenticatable: authenticatable, token: generate_token)
end
end
The undigested token (SecureRandom.hex) gets rendered back to the client via JSON to authenticate future requests. The token gets salted and digested for storage in the database using BCrypt and a configured work factor.
The client will provide the raw auth token and an identity (can be username or password) to load the user record. Authentication will be handled by authenticate_with_http_token
def authenticate_token
authenticate_with_http_token do |token, options|
user = User.identified_by(options["identity"])
user.authentication_tokens.any? do |auth_token|
#current_user = user if auth_token.secure_compare(token)
end
end
end
Auth tokens are compared via a constant time alogrithm lifted from devise.
If current user is not successfully set, I render 401 unauthorized.
I feel like this is reasonably secure, and the only thing I really want to do is add some more fields to the auth token to track where it was last used (user agent) to allow the user to revoke some of the auth tokens if they like.
Are there any major holes with this approach? Anything else I should consider?

validate client id before granting access token with authentication using user credentials oauth2+doorkeeper+rails

I have implemented oauth2 token request with username and password but I need to make client_id and secret validation before authentication. If there is no client_id or secret it should return an error message like "Invalid application". Is there any way to make client_id and secret a required field before authenticated with username and password.
you could use before_save at the top of your rb file and check to see if the params exist?
before_save :validate_stuff
def validate_stuff
unless params[:client_id].present? && params[:secret].present?
raise "Please enter all the info."
end
end
That will fire every time you try to save your object

Rails3 User Changed Password, how do I change the current session password?

I have the need to let the user change their password. I'd like to switch the password in the session to reflect this new password, without logging them out.
def set_auth username, password
# test username and password here?
auth_object = AuthCookie.new
auth_object.set_username username
auth_object.set_password password
session[:user_login] = auth_object
end
I use something like the above, but it doesn't seem to work in changing the current session's password to the new one the use just entered.
What am I doing wrong?
Don't save your whole auth object in the session, the most important thing is you should not save password info in the session. Rails default session storage is cookie based, just base64 encode string. So if you save user password info in the session, there is security problem.
Just put the user identify in the session, for example, the user_id. session[:user_id] = user_id

Resources