From d8882c12b7c718075637bb12e8a59f3144cc2988 Mon Sep 17 00:00:00 2001 From: Michael Hartl Date: Sun, 22 Aug 2010 17:02:04 -0700 Subject: [PATCH] Finished the password machinery --- app/models/user.rb | 33 +++++++++++++++ .../20100822233125_add_salt_to_users.rb | 9 ++++ db/schema.rb | 3 +- spec/models/user_spec.rb | 42 +++++++++++++++++++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20100822233125_add_salt_to_users.rb diff --git a/app/models/user.rb b/app/models/user.rb index 086450b..8a7dee0 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -25,4 +25,37 @@ class User < ActiveRecord::Base validates :password, :presence => true, :confirmation => true, :length => { :within => 6..40 } + + before_save :encrypt_password + + def has_password?(submitted_password) + encrypted_password == encrypt(submitted_password) + end + + class << self + def authenticate(email, submitted_password) + user = find_by_email(email) + return nil if user.nil? + return user if user.has_password?(submitted_password) + end + end + + private + + def encrypt_password + self.salt = make_salt if new_record? + self.encrypted_password = encrypt(password) + end + + def encrypt(string) + secure_hash("#{salt}--#{string}") + end + + def make_salt + secure_hash("#{Time.now.utc}--#{password}") + end + + def secure_hash(string) + Digest::SHA2.hexdigest(string) + end end diff --git a/db/migrate/20100822233125_add_salt_to_users.rb b/db/migrate/20100822233125_add_salt_to_users.rb new file mode 100644 index 0000000..11e8f53 --- /dev/null +++ b/db/migrate/20100822233125_add_salt_to_users.rb @@ -0,0 +1,9 @@ +class AddSaltToUsers < ActiveRecord::Migration + def self.up + add_column :users, :salt, :string + end + + def self.down + remove_column :users, :salt + end +end diff --git a/db/schema.rb b/db/schema.rb index aec9a72..7510e46 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20100822204528) do +ActiveRecord::Schema.define(:version => 20100822233125) do create_table "users", :force => true do |t| t.string "name" @@ -18,6 +18,7 @@ t.datetime "created_at" t.datetime "updated_at" t.string "encrypted_password" + t.string "salt" end add_index "users", ["email"], :name => "index_users_on_email", :unique => true diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index b3792d4..bbe6786 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -109,5 +109,47 @@ it "should have an encrypted password attribute" do @user.should respond_to(:encrypted_password) end + + it "should set the encrypted password attribute" do + @user.encrypted_password.should_not be_blank + end + + it "should have a salt" do + @user.should respond_to(:salt) + end + + describe "has_password? method" do + + it "should exist" do + @user.should respond_to(:has_password?) + end + + it "should return true if the passwords match" do + @user.has_password?(@attr[:password]).should be_true + end + + it "should return false if the passwords don't match" do + @user.has_password?("invalid").should be_false + end + end + + describe "authenticate method" do + + it "should exist" do + User.should respond_to(:authenticate) + end + + it "should return nil on email/password mismatch" do + User.authenticate(@attr[:email], "wrongpass").should be_nil + end + + it "should return nil for an email address with no user" do + User.authenticate("bar@foo.com", @attr[:password]).should be_nil + end + + it "should return the user on email/password match" do + User.authenticate(@attr[:email], @attr[:password]).should == @user + end + end end end