Ruby-on-Rails
  Home arrow Ruby-on-Rails arrow Page 2 - Login Systems and More with Ruby on Rails
Dev Articles Forums 
ADO.NET  
Apache  
ASP  
ASP.NET  
C#  
C++  
ColdFusion  
COM/COM+  
Delphi-Kylix  
Design Usability  
Development Cycles  
DHTML  
Embedded Tools  
Flash  
Graphic Design  
HTML  
IIS  
Interviews  
Java  
JavaScript  
MySQL  
Oracle  
Photoshop  
PHP  
Reviews  
Ruby-on-Rails  
SQL  
SQL Server  
Style Sheets  
VB.Net  
Visual Basic  
Web Authoring  
Web Services  
Web Standards  
XML  
Mobile Linux 
App Generation ROI 
IBM® developerWorks 
Sun Developer Network 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
RUBY-ON-RAILS

Login Systems and More with Ruby on Rails
By: O'Reilly Media
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 4 stars4 stars4 stars4 stars4 stars / 11
    2007-04-05

    Table of Contents:
  • Login Systems and More with Ruby on Rails
  • 15.9 Storing Hashed User Passwords in the Database
  • 15.10 Escaping HTML and JavaScript for Display
  • 15.11 Setting and Retrieving Session Information

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     
    ADVERTISEMENT


    Login Systems and More with Ruby on Rails - 15.9 Storing Hashed User Passwords in the Database


    (Page 2 of 4 )

    Problem

    The database table defined in Recipe 15.8 stores users' passwords as plain text. This is a bad idea: if someone compromises the database, she will have all of your users' passwords. It's best to store a secure hash of the password instead. That way, you don't have the password (so no one can steal it), but you can verify that a user knows his password.

    Solution

    Recreate the users table from Recipe 15.8 so that instead of a password field, it has a hashed_password field. Here's some MySQL code to do that:

      use mywebapp_development;
      DROP TABLE IF EXISTS `users`;
      CREATE TABLE `users` (
        
    `id` INT(11) NOT NULL AUTO_INCREMENT,
       
    `username` VARCHAR(255) NOT NULL,
       
    `hashed_password` VARCHAR(40) NOT NULL,
       
    PRIMARY KEY (id)
      );

    Open the file app/models/user.rb created in Recipe 15.8, and edit it to look like this:

      require 'sha1'

      class User < ActiveRecord::Base
       
    attr_accessor :password
       
    attr_protected :hashed_password
       
    validates_uniqueness_of :username
        validates_confirmation_of :password,
          :if => lambda { |user| user.new_record? or not user.password.blank? }
        validates_length_of :password, :within => 5..40,
          :if => lambda { |user| user.new_record? or not user.password.blank? }
     

        def self.hashed(str)
          SHA1.new(str).to_s
        end

        # If a user matching the credentials is found, returns the User object.
        # If no matching user is found, returns nil.
        def self.authenticate(user_info)
         
    user = find_by_username(user_info[:username])
          if user && user.hashed_password == hashed(user_info[:password])
            return user
          end
        end

        private
        before_save :update_password

        # Updates the hashed_password if a plain password was provided.
        def update_password
          if not password.blank?
            self.hashed_password = self.class.hashed(password)
          end
        end
      end

    Once you do this, your application will work as before (though you'll have to convert any preexisting user accounts to the new password format). You don't need to modify any of the controller or view code, because the User.authenticate method works the same way it did before. This is one of the benefits of separating business logic from presentation logic.

    Discussion

    There are now three pieces to our user model. The first is the enhanced validation code. The user model now:

    1. Provides getters and setters for the password attribute.
    2. Makes sure that the hashed_password field in the database can't be accessed from the outside.
    3. Ensures that each user has a unique username.

    When a new user is created, or when the password is changed, User ensures:

    • That the value of the password_confirmation attribute is equal to the value of the password attribute.
    • That the password is between 5 and 40 characters long.

    The second section of code defines User class methods as before. We add one new class-level method, hashed, which performs the hashing function on a plaintext password. If we want to change hashing mechanisms in the future, we only have to change this method (and migrate any existing passwords).

    The third piece of code in the model is a private instance method, update_password, which synchronizes the plaintext password attribute with the hashed version in the database. The call to before_save sets up this method to be called before a User object is saved to the database. This way you can change a user's password by setting password to its plaintext value, instead of doing the hash yourself.

    See Also

    1. Recipe 13.14, "Validating Data with ActiveRecord"
    2. Recipe 15.8, "Creating a Login System"

    More Ruby-on-Rails Articles
    More By O'Reilly Media


       · This article is an excerpt from the "Ruby Cookbook," published by O'Reilly. We hope...
     

    Buy this book now. This article is excerpted from chapter 15 of the Ruby Cookbook, written by Lucas Carlson and Leonard Richardson (O'Reilly, 2006; ISBN: 0596523696). Check it out today at your favorite bookstore. Buy this book now.

    RUBY-ON-RAILS ARTICLES

    - Iterating and Incrementing Strings in Ruby
    - Comparing and Manipulating Strings in Ruby
    - Strings in Ruby
    - Ruby On Rails: Making Your First Dynamic Site
    - Ruby on Rails: Beginning Rails
    - Ruby: Modules, Mixins, Fixins, and Rails
    - Controlling Information Access with the Rail...
    - URLs, Filters and the Rails Action Controller
    - Flash and the Rails Action Controller
    - Rails Action Controller
    - Dropping and Sorting with AJAX and script.ac...
    - Drag and Drop with script.aculo.us and Rails
    - Introducing script.aculo.us
    - Ruby Classes and Objects
    - Ruby Loops






    © 2003-2008 by Developer Shed. All rights reserved. DS Cluster 2 hosted by Hostway
    Stay green...Green IT