I'm getting a similar error to this post Ruby on Rails Authlogic password not valid "Password is not valid" which never seemed to be resolved
in the script/console if I create a new user:
myval = "foo#example.com"
u = User.create(:email => myval, :password => myval, :password_confirmation => myval)
u.valid?
>> true
u.save
>> true
u.valid_password?(myval)
>>false
if i set in my user.rb:
acts_as_authentic do |c|
c.validate_password_field = false
end
i get the same response. Any suggestions?
I just took a dig through the AuthLogic code and it looks like setting validate_password_field to false only prevents Rails from running the default validations. It has no effect on the valid_password? method.
There are a number of other factors that appear to cause it to return false. These include but may not be limited to:
Checking for a blank password
The crypted password is blank
The password doesn't match. (This one is a bit complicated because there are a variety of factors involved in this, including the CryptoProvider and whether or not you're using RestfulAuthentication style passwords.)
To give a more definitive answer, I probably need some more information on your exact setup.
I had a similar problem to this, turns out the old Restful Authentication password fields are migrated at 40 characters in length when Authlogic requires 255.
In my case it was just a messed up data base migration. rake db:migrate VERSION=0 && rake db:migrate solved this problem for me.
try to remark "before_save :encrypt_password" in user.rb if you have.
# before_save :encrypt_password
Related
I'm currently going through Michael Hartl's book (Ruby on Rails tutorial 3rd edition) and he uses password_digest with his authentication model, I checked out Pragmatic Studio's Rails course and in their sample video, they use passowrd_hash/password_salt in their authentication model. From wikipediaing, it seems that salt is a standard use in cryptography and has a variety of uses for security. All I could really find on password_digest is it works with a rails method has_secure_password.
Is one preferred over the other or do they serve different purposes ultimately?
when using the has_secure_password a lot of the encryption magic is done automatically for you, and a few functions are exposed that make it easier for you to verify the password of a User.
As taken from the has_secure_password documentation:
# Schema: User(name:string, password_digest:string)
class User < ActiveRecord::Base
has_secure_password
end
user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
user.save
# => false, password required
user.password = 'mUc3m00RsqyRe'
user.save
# => false, confirmation doesn't match
user.password_confirmation = 'mUc3m00RsqyRe'
user.save
# => true
user.authenticate('notright')
# => false
user.authenticate('mUc3m00RsqyRe')
# => user
User.find_by(name: 'david').try(:authenticate, 'notright')
# => false
User.find_by(name: 'david').try(:authenticate, 'mUc3m00RsqyRe')
# => user
Both systems you mentioned will work, it just comes down on what you wish to use, what options you have available etc.
Manually building a salted hash (based on e.g. SHA1) was indeed a long time the default way to store passwords. However, since a couple of years, it became clear that there need to be better (i.e. more secure) ways to store a password which ensure that even if an attacker could gain access to the raw hashes, they could not easily brute-force them.
As such, in newer Rails versions, passwords are by default saved with has_secure_password using the Bcrypt algorithm which is much more suitable for password storage than a simple salted hash. Note that Bcrypt also uses a salt internally. You just don't have to deal with it yourself.
The method Hartl uses, has_secure_password, uses an algorithm called Bcrypt to salt and hash a password, producing a password_digest string that has three components:
A flag that indicates that the string is a Bcrypt hash
The (unhashed) salt
The result of hashing password+salt
I'm not familiar with the Pragmatic Studio course, but it sounds like they're storing the salt and hash in different attributes.
I'm using Clearance for authentication in my Rails application.
I'm using the default Minitest stack. Clearance by default only use email and password fields so i add a name field and now i want to unit test the model to do some checks.
This is my test so far.
test "should not save without name" do
user = User.new
user.email = "john#sample.com"
user.password = "foobar"
assert_not user.valid?
end
And this is my model validation.
validates :name, presence: true
Everything works great and the test fails as expected. The problem is that i wanted to use a user fixture to clean a little my test.
One viable approach could be
john:
name: John
email: john#sample.com
password: foobar
But then the test execution fails saying that there isn't a field called password. Indeed the field is called encrypted_password. I can create one using the BCrypt::Password.create method but again, another error raises telling me that remember_token can't be null, i suspect that the same happens with the confirmation_token field.
So my question is.
Is there any way that i can create a rails fixture to use those data in my test using the clearance authentication library ?
Update:
To clarify the fixture example due to the correct answer the result fixture is:
john:
name: John
email: john#sample.com
encrypted_password: <%= BCrypt::Password.create("foobar", cost: 4) %>
remember_token: <%= Clearance::Token.new %>
And that's it, it works like charm.
When the User ActiveRecord API is used to create the object, all of the required fields should be set appropriately. Unfortunately, it doesn't look like this happens with fixtures - or at least it's not happening for you (I don't use fixtures, so I'm not sure).
You can set any required tokens to: Clearance::Token.new, which is what Clearance uses to generate tokens.
So I wrote an app before that allowed for the standard way of encrypting a password using this and it worked fine:
before_save :create_hashed_password
Then:
def create_hashed_password
# validation code not shown
self.password = Digest::SHA1.hexdigest(password)
end
The problem is now in this app is that I have other user attributes I want to edit and every time I edit and save, I am hashing the already hashed password, thus making login impossible after updating.
I tested this in irb and it works:
irb(main):008:0> t.password = 'password'
=> "password"
irb(main):009:0> t.password_changed?
=> true
But when I use this line in the before filter:
before_save :create_hashed_password if password_changed?
It fails with the following error:
NoMethodError: undefined method `password_changed?' for User(no database connection):Class
(And before you ask, yes I do have a db connection, it's just with the User model because the before filter is there)
BTW I'm on Rails 4.
Try with:
before_save :create_hashed_password, if: :password_changed?
Short explanation: in your current syntax, the if part is not a param to the before_save method, this is why you need to add the coma, to send it as a parameter. Now it tries to call a class method: User.password_changed?, this doesn't make sense since you need to perform an instance method against a user object.
Try this:
before_save :create_hashed_password, if: Proc.new { &:password_changed? }
Hope this helps, happy coding
I'm trying to migrate a ton of users from an old database. To do this, I'm using activerecord-import and trying to save all my user data directly to DB (bypassing the User model).
My issue: I need to take the old user's plain-text password, encrypt it, and store directly to the DB. I know how to generate a password using Devise, but am wondering if there's a way to get a hashed password that I can store directly to the database.
Hoping to do:
new_hashed_password = Devise.awesome_encrypting_method(old_user.password)
Then store "new_hashed_password" directly into the DB without going through the model. I dug around in Devise and found this:
def password_digest(password)
::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s
end
##stretches defaults to 10 (lib/devise.rb:71) and isn't overridden by my initializer
##pepper defaults to nil (lib/devise.rb:148) and isn't overridden by my initializer
I thought I could manually re-create password_digest() but I think I'm missing something fundamental about Bcrypt because even with setting password and stretches, the resulting hash is different every time.
Any ideas? Thanks for your help!
You should do it like this:
password = 'the secret password'
new_hashed_password = User.new(:password => password).encrypted_password
This is much better than using BCrypt directly as it abstracts away how passwords are generated from your code, making it easier to understand, and also immune to changes in how devise constructs encrypted passwords. Your code should not, and has no reason to know anything about that.
Good news and bad news.
Good news:
The following works to create your user's password manually.
pepper = nil
cost = 10
encrypted_password = ::BCrypt::Password.create("#{password}#{pepper}", :cost => cost).to_s
You can find your pepper and cost in your devise initializer. This method was confirmed using Devise's "valid_password?" method.
Bad news:
The entire reason I was trying to avoid "User.new(password: password).encrypted_password" was because of speed. It's terribly slow. With all my other pieces of my import task, I've intentionally avoided this.
But as it turns out, the major cost here is not instantiating a User object -- but BCrypt itself. There is very little noticeable speed boost when using BCrypt directly because it's intentionally designed to be slow.
My final answer: suck it up, run the rake script, go find a beverage.
None of the other answers above worked for me, so here is what I did:
user.valid_password?(plain_password)
https://github.com/plataformatec/devise/blob/d293e00ef5f431129108c1cbebe942b32e6ba616/lib/devise/models/database_authenticatable.rb#L44
An alternative method is: User.new.send(:password_digest, 'xxx')
Assuming you have a mysql database with a "users" table and a "password" column
And an ActiveRecord model class called "user" that is hooked up to devise
Create an ActiveRecord model class in your app
app/models/old_user.rb
OldUser < ActiveRecord::Base
set_table :users
establish_connection :database => "old_database", :user => "old user", :adapter => "mysql"
end
then create a rake task:
app/lib/tasks/migrate_users.rake
task :migrate_users => :environment do
OldUser.find_each do |old_user|
u = User.new(:email => old_user.email, :password => old_user.password, :password_confirmation => old_user.password);
#if your using confirmation
u.skip_confirmation!
u.save!
end
end
Modify as necessary (make sure you're saving any app-specific user attributes)
Then$ rake migrate_users
I am trying out how Devise works with one of my projects for user authentication. There is a user requirement that their admin should be able to generate a batch of username and user's password from time to time, and then the admin will email the new username and password to his users.
Assume the admin has the knowledge of direct SQL on the MySQL database, how can the generated usernames/passwords recognized by Devise? Thanks!
Use the Devise.friendly_token method:
password_length = 6
password = Devise.friendly_token.first(password_length)
User.create!(:email => 'someone#something.com', :password => password, :password_confirmation => password)
FYI: Devise.friendly_token returns a 20 character token. In the example above, we're chopping off the first password_length characters of the generated token by using the String#first method that Rails provides.
One option would be to use the Devise.generate_token. I.e.
password = User.generate_token('password')
User.create!(:email => 'someone#something.com', :password => password, :password_confirmation => password)
This option has not been available in Devise for quite a while. Please refer to the other answer (friendly_token).
I'm using devise-security gem and have specefic password_complexity requirements as follows:
config.password_complexity = { digit: 1, lower: 1, upper: 1 }
If you use this code: Devise.friendly_token.first(password_length) to generate the password, you are not always guaranteed to get a password that matches your complexity.
So I wrote a password generator that will respect your password_complexity and will generate a random complaint password:
class PasswordGenerator
include ActiveModel::Validations
validates :password, presence: true, 'devise_security/password_complexity': Devise.password_complexity
attr_reader :password
def initialize
#password = Devise.friendly_token.first(Devise.password_length.first) until valid?
end
end
You can use it as follows:
PasswordGenerator.new.password # "qHc165ku"
(quick caveat: I'm a rails newb)
I tried the generate_token but it doesn't do what you think (look at the docs)
(I'm using rails 3.0.5, and devise 1.1.7)
What I found is that Devise will generate all that stuff for you in the background when you do:
User.create!(:email => "me#example.com", :password => "password")
Devise should create the encrypted_password, and salt for you. (pop open a console and try it out there)