How to check that old password is equal to that one in database - ruby-on-rails

I want to make a change password in rails i want to enter the old password as a string and check it with the encrypted one in the database i am using Devise gem how can i do this

You want Devise's valid_password? method.
> user = User.find(1)
> user.valid_password?('invalidpassword')
=> false
> user.valid_password?('therealpassword')
=> true

Devise already provides you with this functionality. It should probably work out of the box using the edit_user_registration_path.
Have a look at https://github.com/plataformatec/devise/wiki/How-To%3a-Allow-users-to-edit-their-password to find some more information.

Related

Ruby on Rails - Devise welcome email to new users with reset password in Active Admin

Im using RoR 3.2.3 and Devise and Active Admin is working great.
However, there is something I am not getting.
In my app, users cannot register themselves, only an Admin can register other users.
This is all working, the Admin goes into the Active Admin panel->Users->New and fills the username and email and clicks "Create".
In order to give the customer the option of clreating his new password I'm using in mt AA user model:
after_create { |user| user.send_reset_password_instructions }
def password_required?
new_record? ? false : super
end
However, I don't want the email to send the text that devise uses, but rather a welcoming text and not something like "A link to change your password has been requested..." as there was no password to begin with.
In short, I want to use the send_reset_password_instructionsdevise method without using it's devise/mailer/reset_password_instructions view for when a new user is created.
However if the user forgets his password then he clicks the "Forgot Password" link and an email is to be sent with that default text already provided by Devise.
Any tips on how to make this work?
Thanks in advance,
Regards
Its very simple actually, set config.scoped_views = true in config/initializers/devise.rb
Then run
rails g devise:views users
this will generate all the views files devise uses, you can make changes to the
app/views/users/mailer/reset_password_instructions.html.erb file to what you need or any other file you wish to change.

How do I reset a user password from the console in Hobo/Rails

The rails framework Hobo is brilliant and automatically creates the first user as the admin user (unless you ask it not to). The problem I have is that running rails in development I can't remember what the password was. This should be trivial because I just run rails console, find the user admin = User.find :first and reset the password (trying)
admin.password = 'Anything1234'
admin.password_confirmation = admin.password
admin.save
>false
admin.errors
>{:current_password=>["is not correct"]}
I.e. the implication is that the variable current_password needs to be set correctly before I can change the existing password.
I'm afraid the Hobo documentation doesn't help in this case. Does anyone know the how to drive the Hobo user model to reset the password?
4 possible solutions:
1: run your app, and click on the forgot password link. The message will appear in your logs, so you don't need a mailer set up.
2: Just save without doing any validations:
admin.save(false)
EDIT: in Rails 3 this is
admin.save(:validate => false)
3: Another option is just to delete all users so you get your initial user entry screen back.
4: If you really want to run the validations, you can trigger the request_password_reset lifecycle:
admin.lifecycle.request_password_reset!(Guest.new)
then look in development log for the reset password key
u.lifecycle.reset_password!(Guest.new, :key => 'a0a2db1035065fa7ad5d46d35669d206aee73668', :password=>"test123", :password_confirmation=>"test123")
Yes, you need to set the current_password before you set the password and password_confirmation fields. This is to stop the user from changing the password without originally knowing the password.
Therefore, you would need to do something like this:
admin.current_password = 'password'
admin.password = 'Anything1234'
admin.password_confirmation = admin.password
admin.save

Encrypting Passwords to match stored encrypted passwords.

I started working on a project which had a lot of code already in place. It is a Ruby on Rail application that uses Devise for user authentication. One of the requirements of the application is that when a user changes their password, they are not allowed to use the same password as the last three passwords they previously used. To acomplish this, there is a table that contains a history of passwords for a given user. These passwords are copies of the encrypted passwords that existed prior to any password change on the user.
Here is where the problem comes in. We have a password change form that collects the new password for a given user. I need to be able to take the new password and encrypt it so that I can match the encrypted value of the new password against encrypted values of the old passwords in history.
Technical Stuff
Rails version 3.0.9
Devise version 1.3.4
Using standard BCrypt with Devise. bcrypt_ruby version 2.1.4
To do this we are overrriding the reset_password method supported by Devise. This allows us to introduce our own method, has_repeated_password in the user controller.
The version of has_repeated_password I started with is below:
def has_repeated_password?
return false if self.new_record? || self.version == 1
histories = self.versions.find(:all, :order => 'version DESC', :limit => 3)
histories.detect do |history|
history.encrypted_password == self.class.encryptor_class.digest(self.password, self.class.stretches, history.password_salt, self.class.pepper)
end
end
The problem here is that the encryptor class is never defined, causing an error every time this routine runs. Even through there are many examples that claim this works, I cannot get it to work when Devise is using the default encryption.
A second attempt at this is the following code:
def has_repeated_password?<br>
return false if self.new_record? || self.version == 1
histories = self.versions.find(:all, :order => 'version DESC', :limit => 3)
histories.detect do |history|
pwd = self.password_digest(self.password)
history.encrypted_password == pwd
end
end
In this case, I never get a password that matches any of the stored passwords, even though I have verified that the password in the database is what I expect.
I have been trying to dig through the Devise code to see what I can find there. I know that the autentication has to do this somehow when it matches passwords collected from users against the stored password.
Any help would be appreciated.
I think I found a solution to my own problem. The key sticking point of this was that I was trying to get an encrypted password that was not part of the user model (any more) tied to Devise. This solution does assume that Devise will be using Bcrypt as the standard encryption tool (can't remember which version of Devise made the move). Bcrypt/Devise actually buries the salt for the password in the encrypted password. If you have the salt and the pepper, you can get the same password to generate the same encrypted value.
So here is the updated code for the routine refernced above:
def has_repeated_password?
return false if self.new_record? || self.version == 1
histories = self.versions.find(:all, :order => 'version DESC', :limit => 3)
histories.detect do |history|
bcrypt = ::BCrypt::Password.new(history.encrypted_password)
password = ::BCrypt::Engine.hash_secret("#{self.password}#{self.class.pepper}", bcrypt.salt)
password == history.encrypted_password
end
end
The key here is that the Bcyrpt object has to be created with an existing encrypted password using the same salt that generated the original password. That is accomplished by giving it my stored historical encrypted password (history.encrypted_password). One of the other key elements is that both the history passwords and the proposed new password use the same pepper, which is managed by Devise. So by using the Engne.has_secret call with the intended new password, it can be compared with the history password.
I had to move the bcrypt code into here because all the password methods supported by Devise assume that you want to act on the user password of the current user object.

OmniAuth and Devise, how to set optional passwords

I am using OmniAuth and Devise to authenticate users. I would like users that have signed up using OmniAuth providers to be able to set an optional password (needed for API authentication) but I'm running into a wall.
If a user creates an account via OmniAuth and tries to set a password they get the following error:
BCrypt::Errors::InvalidHash in RegistrationsController#update
I believe this is because the password is blank. What's a good way around this? I've thought about generating a random password but the problem with that approach is the user needs to know the current password in order to edit settings.
Edit:
I looked at allowing the user to change settings without requiring a current password and that's what I would like to do only if the user didn't have a password initially.
An alternative is to add the following into your 'user' model class to bypass password verification if there is no password to verify, where provider is some field that is set when using external authentication.
def valid_password?(password)
!provider.nil? || super(password)
end
I assume you don't want the easy way out which would be to simply reset the password if they wanted to set it?
user.send_reset_password_instructions
This comes a bit late but it might help someone else, with Andrew's answer you can in create a password and store it in the database, but you can't login using your email and your new password, solved this by setting:
def valid_password
!provider.nil? && !encrypted_password.present? || super
end
Another alternative. You don't have to include a new field. Just catch the exception raised and return false. Here is the code.
def valid_password?(password)
begin
super(password)
rescue BCrypt::Errors::InvalidHash
return false
end
end
This should do the job.

Set Authlogic validate_login_field to false on user update

We have a current database of users who can have any symbol in their username. We have started using authlogic for authentication. So, any current users updating any of their information fail validations because their login has unaccepted characters.
We want to prevent new users signing up from using symbols not accepted by authlogic, but those who have them already in their login to continue using them.
I know that I need to use something like this:
acts_as_authentic do |c|
c.validate_login_field = false
end
My questions is how do I set validate_login_field to false for already existing users but leave it to default value of true for new users signing up? Thanks.
I would suggest forgetting about that particular validation feature in Authlogic for your particular case (i.e. keep it as c.validate_login_field = false) and use validates_format_of setting a :with clause to a regex to ensure Authlogic valid user names and an :if clause to some proc or method private method which returns true if the validation should be done at all (using some application specific logic of your own design)
Or you can not to turn of validate_login_field and add :if option to validates_format_of_login_field_options
UPDATE:
Actually forget, it's a bad idea, because in that case you have to provide :if option for every possible validation.
Not only for validates_format_of_login_field_options, but for validates_length_of_login_field_options and validates_uniqueness_of_login_field_options

Resources