I've a password stored in a database.
The user should be able to set a new one.
I've also used attr_encrypted gem to store it as encrypted text (symmetric because i need it back to connect to other services and not just to login) but this is another story.
When I show the form, the default behavior of ruby helpers is to not send back the password to the browser for obvious security reasons.
Here is the code:
<%= f.input :app_password, :as => :password %>
this behavior might be ok, nevertheless some issues arise from it.
if the user saves the form with null password, the password will be erased. I should test and avoid null-password savings but in some application null password is acceptable and doing so i would prevent this possibility.
it doesn't provide a visual feedback to the user on the fact that he or she has compiled the password field.
it doesn't play very well with validations
What are my options here in order to obtain the most standard possible behavior (that is, no 'change password' checkboxes)?
Please, in forms include password fields this way:
<%= f.password_field :app_password %>
The standard use and set of password is:
Add to your user model a call to has_secure_password
Add field to users for store an encripted password, migration: add_column :users, :auth_token, :string
Before create generate a token:
begin
self.auth_token = SecureRandom.urlsafe_base64
end while User.exists?(auth_token: self.auth_token)
Authenticate your users with #user.authenticate(params[:password])
Update password at another form with 3 fields, old_password, password, and password_confirmation.
Related
in devise rails gem, what is the difference between these two?
I have seen the :encrypted_password field in the generated schema but not :password field.
Any explanations if these two are interconnected with each other?
Devise::Models::DatabaseAuthenticatable has a setter for that:
def password=(new_password)
#password = new_password
self.encrypted_password = password_digest(#password) if #password.present?
end
So you should set the password as if there was a password field, devise will take care of encrypting it.
As #spickermann already pointed out - plain text password should never be stored anywhere and should filtered out from logs/error messages and so on, because this produces a huge security risk: the encrypted password leak is not totally harmless, but not dangerous that much.
password is the plain text the user set as his password (and plain text password should never be stored anywhere). encrypted_password this the encrypted version of this password.
You might want to read SecurePassword.
:password is the password that a user sets through a form.
:encrypted_password is what is stored in your database and retrieved to create a user session.
Essentially, :encrypted_password is a hashed and salted version of :password that can be safely stored in your database. See this answer if you need more information on why you shouldn't store plain text passwords in your database.
Is there a way I can tell Devise not to use a password? I'm using Devise with LDAP so the encrypted password field is a wasted column (the password is stored in the LDAP directory). If I delete the encrypted_password column and then add some dummy accessors on my models
def encrypted_password
""
end
def encrypted_password=dummy
end
I can at least get rid of the column in the database. However, when I create new users I still have to supply a dummy password
User.create(:first_name => "Dummy", :password => "dummyPass1", :password_confirmation => "dummyPass1")
Is there a setting somewhere that would make this cleaner?
You can take "database_authenticatable" out of the devise config line in your User model, and drop the encrypted_password field entirely.
attr_accessible :email, :password, :password_confirmation
If not, can you please give example of method which prevents 'undefined' error when attr_accessible is removed.
It is safe. Attr_accessible is only dangerous for attributes that control your application logic. For example, if you have a flag that says "yes I've checked this user is an admin", and it can be set by the user instead, because it's attr_accessible, then it's a vulnerability.
Since the password is a piece of information that is provided by the user anyway, making it settable by the same user does not change anything.
If you are security paranoid, you could do this is defining the method password:
def password
self.password
end
this way the password can't be set by hand.
But you shouldn’t worry about it because many login gems like devise needs password in attr_accessible.
I'm using the "has_secure_password" way to store a secure password in the database. When creating an user by the admin (in my app users are created, users can't create an account themselves), in the user model the password_digest is filled by a method to create a random password (see code). When the record is then saved, it is saved secure. So the user method is creating a password_digest say "TY5665^%^", then it is saved in the database say "Y^6&$d%$56GFT". Great!
before_validation :create_random_password, :on => :create
def create_random_password
self.password_digest = SecureRandom.hex(5)
end
But when the new user logs in and changes his password in his profile, the new password gets saved OK, but unsecured! Say the user is changing it to "password1", it also gets saved as "password1" in the database. So why is the secure password working on create, but not on update?
Without seeing your update code, make sure your update is to :password, not :password_digest. The magic behind the creation of a password hash to go into :password_digest only starts with :password.
Surprised that you can save your own password directly onto :password_digest and it would work when authenticating. I'd think it would take the password provided by the user, hash it, and then compare the hash to :password_digest (which couldn't be their password).
This is what I do, which may solve the issue:
before_create :set_temporary_password
def set_temporary_password
self.temporary_password = SecureRandom.hex(5)
end
Send the user self.temporary_password, and when they update it, change temporary_password to nil. Then you can know when a user has a temporary password that requires changing.
For the sign-up form for my website I don't require that users confirm their passwords so there isn't a password confirmation field.
However when a user resets their password and they click the link in their email and then taken to a change password page I require they confirm their password and provide a field for them to do this.
My question is how can I add password confirmation and min and max lengths for passwords with out it affecting my sign up form because they use they same model. For my signup form I have min and max length validation rules and want these to apply to the change password form but also include password confirmation.
What is the best and most convenient way to do this in your opinion?
If password confirmation should only be done for users already created, the simplest solution is :
class User < ActiveRecord::Base
validates_confirmation_of :password, :unless => :new_record?
end
So it will only call the validation when setting the value for new users and not for users trying to sign up.
You can create your own methods to validate model data, something like this:
class User < ActiveRecord::Base
validate :user_data_validation
def user_data_validation
errors.add(:password_confirmation, "error in the password confirmation") if
!password.blank? and password != password_confirm
end
end
On the other hand you can use control-level validations, but:
Controller-level validations can be tempting to use, but often become
unwieldy and difficult to test and maintain. Whenever possible, it’s a
good idea to keep your controllers skinny, as it will make your
application a pleasure to work with in the long run. (c)