Adding More Elaborate Authentication Using the Login Engine

Problem

Your application needs a complete authentication system. This system should include features such as email notifications, and the ability for users to reset their passwords. While the Salted Login Generator gem can handle these tasks, you don't want a solution that adds a lot of source files to your application. You prefer a cleaner solution, such as an engine.

Solution

Install and configure the login_engine plug-in to add a secure and complete authentication system to your Rails application.

Here's how to install the plug-in:

$ ruby script/plugin source http://svn.rails-engines.org/plugins
$ ruby script/plugin install login_engine

Because the login_engine plug-in is an engine, it requires that the engines plug-in be installed. The install.rb script automatically installs the engines plug-in if it isn't already.

If you're running Edge Rails, it's recommended that you install the latest development version of the engines plug-in. You can do this in Subversion by exporting the latest source into your application's vendor/plugins directory.

$ cd vendor/plugins/
$ svn export http://svn.rails-engines.org/engines/trunk/ \
 engines

Also, you need to tell the engines plug-in if you expect it to perform with Edge behavior. This is done by adding the following lines at the very top of config/environment.rb:

module Engines
 EdgeRails = true end


After the plug-in has been installed, you need to go through several steps to get authentication working. Email notifications are an important feature of this plug-in; they may be enable or disabled. This solution assumes you want email enabled.

The first step is to include a users table in your model. This table is defined by a migration that's included with the plug-in. If you have an existing table that stores users, you may need to alter the migration to update your users table appropriately. It's okay if your users table is named something other than "users," you'll have an opportunity to declare an alternative name when configuring the plug-in. Examine the following table creation statement from the provided migration, and make sure that running it won't clobber your existing database:

create_table LoginEngine.config(:user_table), :force => true do |t|
 t.column "login", :string, :limit => 80, :default => "", :null => false
 t.column "salted_password", :string, :limit => 40, 
 :default => "", :null => false
 t.column "email", :string, :limit => 60, :default => "", :null => false
 t.column "firstname", :string, :limit => 40
 t.column "lastname", :string, :limit => 40
 t.column "salt", :string, :limit => 40, :default => "", :null => false
 t.column "verified", :integer, :default => 0
 t.column "role", :string, :limit => 40
 t.column "security_token", :string, :limit => 40
 t.column "token_expiry", :datetime
 t.column "created_at", :datetime
 t.column "updated_at", :datetime
 t.column "logged_in_at", :datetime
 t.column "deleted", :integer, :default => 0
 t.column "delete_after", :datetime end

Once you've confirmed that the migration is safe and won't damage your database tables (perhaps after some modification), run the migration:

$ rake db:migrate:engines ENGINE=login

Next, add the following lines to the end of environment.rb:

module LoginEngine
 config :salt, "site-specific-salt"
 config :user_table, "your_table_name"
end Engines.start :login

The config method sets various configuration options of the login_engine module. Add your own "salt" string to the:salt configuration option to increase the security of your encrypted passwords. The :user_table option is only necessary if you need to change the name of the users table to match your application.

Next, modify application.rb to include the login_engine module.

app/controllers/application.rb:

require 'login_engine'
class ApplicationController < ActionController::Base
 include LoginEngine
 helper :user end

Now, add the following to your application-wide helper:

app/helpers/application_helper.rb:

module ApplicationHelper
 include LoginEngine
end

To allow your application to send email notifications, specify the method by which email is to be sent. On Unix systems, you can use your locally installed sendmail program. Otherwise, specify external SMTP server settings. For development, add these email configurations to development.rb under your config/environments directory:

config/environments/development.rb:

# on Unix-like systems:
ActionMailer::Base.delivery_method = :sendmail

If you're not on a Unix-like machine, or want to use an external mail server for sending mail, replace the Action Mailer line in development.rb with the specifics of your outgoing mail server's settings:

ActionMailer::Base.server_settings = {
 :address => "mail.example.com",
 :port => 25,
 :domain => "mail.example.com",
 :user_name => "your_username",
 :password => "your_username",
 :authentication => :login
}

The final step is to specify which controllers and actions require authentication. Assume you have an application that serves up reports, some of which contain sensitive data that should only be viewed by authenticated users. To require authentication for the view action of a Reports controller (and no other actions), add the following before_filter:

./app/controllers/reports_controller.rb:

class ReportsController < ApplicationController
 before_filter :login_required, :only => :view
 def index
 #...
 end
 def view
 #...
 end end

Now, add this before_filter to any controllers that need it. If you simply want application-wide authentication, add one before_filter to application.rb; for example:

./app/controllers/application.rb:

require 'login_engine'
class ApplicationController < ActionController::Base
 include LoginEngine
 helper :user
 before_filter :login_required
end

Discussion

The login_engine is almost a direct port of the Salted Login Generator from a gem to a Rails engine. Originally, this system was installed as two separate gems, each providing generators that would copy source code into your application. This solution, using the login_engine, is a more elegant way to get most of the same features as the original gem. One component of the original Salted Login Generator was localization (also known as L10N). The engine version has omitted localization.

See Also