Register now and start sharing your code snippets.

How to add OpenID support to your Rails application with the open_id_authentication plugin

Ruby posted 5 months ago by christian

These instructions have been tested with Rails 2.0.2 and ruby-openid 2.0.4. The snippet is an adaptation of the instructions in Ryan Bates’ screencast on how to integrate OpenID with Rails.

Installing and configuring the restful_authentication plugin

Follow these instructions: How to install and use the restful_authentication Rails plugin.

Installing the ruby-openid gem

   1  gem install ruby-openid

Installing the open_id_authentication Rails plugin

   1  script/plugin source http://svn.techno-weenie.net/projects/plugins/
   2  script/plugin install open_id_authentication

Create the migration files

   1  rake open_id_authentication:db:create

Add the following to the self.up method in 002_add_open_id_authentication_tables.rb:

   1  add_column :users, :identity_url, :string

Configuring the routes

   1  map.open_id_complete 'session', :controller => "sessions", :action => "create", :requirements => { :method => :get }

Protect the identity_url field

Next protect the identity_url field, by adding the following to user.rb, account.rb or your custom user model:

   1  attr_accessible :login, :email, :password, :password_confirmation, :identity_url

Add the following to the self.down method in 002_add_open_id_authentication_tables.rb:

   1  remove_column :users, :identity_url

Integrating Open-id with the login page

Add the following to sessions/new.html.erb:

   1  <label for="openid_url">OpenID URL</label><br />
   2  <%= text_field_tag "openid_url" %>

Make sure you’re showing flash messages, otherwise you won’t see the error messages:

   1  <html>
   2    <head></head>
   3    <body>
   4      <%= [:notice, :error].collect {|type| content_tag('div', flash[type], :id => type) if flash[type] } %>
   5  
   6      <%= yield %>
   7    </body>
   8  </html>

Modifying the sessions controller

Copy & paste the following code in app/controllers/sessions_controller.rb:

   1  class SessionsController < ApplicationController
   2    # Hack to fix: No action responded to show
   3    def show
   4      create
   5    end
   6  
   7    def create
   8      if using_open_id?
   9        open_id_authentication(params[:openid_url])
  10      else
  11        password_authentication(params[:login], params[:password])
  12      end
  13    end
  14  
  15    def destroy
  16      self.current_user.forget_me if logged_in?
  17      cookies.delete :auth_token
  18      reset_session
  19      flash[:notice] = "You have been logged out."
  20      redirect_back_or_default('/')
  21    end
  22  
  23    protected
  24  
  25    def open_id_authentication(openid_url)
  26      authenticate_with_open_id(openid_url, :required => [:nickname, :email]) do |result, identity_url, registration|
  27        if result.successful?
  28          @user = User.find_or_initialize_by_identity_url(identity_url)
  29          if @user.new_record?
  30            @user.login = registration['nickname']
  31            @user.email = registration['email']
  32            @user.save(false)
  33          end
  34          self.current_user = @user
  35          successful_login
  36        else
  37          failed_login result.message
  38        end
  39      end
  40    end
  41  
  42    def password_authentication(login, password)
  43      self.current_user = User.authenticate(login, password)
  44      if logged_in?
  45        successful_login
  46      else
  47        failed_login
  48      end
  49    end
  50  
  51    def failed_login(message = "Authentication failed.")
  52      flash.now[:error] = message
  53      render :action => 'new'
  54    end
  55  
  56    def successful_login
  57      if params[:remember_me] == "1"
  58        self.current_user.remember_me
  59        cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
  60      end
  61      redirect_back_or_default('/')
  62      flash[:notice] = "Logged in successfully"
  63    end
  64  end

OpenID authentication from behind a proxy

First, set the HTTP _PROXY environment variable to the proxy URL :

   1  export HTTP_PROXY=http://proxy.aktagon.com:8080/

Then add the following to environment.rb:

   1  OpenID::fetcher_use_env_http_proxy

Tagged openid, authentication, rails, ruby, plugin, restful_authentication

How to install and use the restful_authentication Rails plugin

Ruby posted 5 months ago by christian

This is an adaptation of the restful_authentication screencast by Ryan Bates, which has an issue with Rails 2.0.3 that throws the following error:

   1  NameError (uninitialized constant SessionsController):
   2      /usr/local/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:266:in `load_missing_constant'
   3      /usr/local/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:453:in `const_missing'
   4      /usr/local/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:465:in `const_missing'
   5      /usr/local/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/inflector.rb:257:in `constantize'

Installing the restful_authentication plugin

   1  script/plugin source http://svn.techno-weenie.net/projects/plugins/
   2  script/plugin install restful_authentication

Generating the model and controller

   1  script/generate authenticated user sessions

Now run the migration:

   1  rake db:migrate

Configure routing

Open config/routes.rb and add the following routes:

   1  map.resources :users
   2  map.resource  :session
   3  
   4  map.signup '/signup', :controller => 'users', :action => 'new'
   5  map.login  '/login', :controller => 'sessions', :action => 'new'
   6  map.logout '/logout', :controller => 'sessions', :action => 'destroy'

Include restful_authentication in ApplicationController

First remove these lines from the users and sessions controllers:

   1  # Be sure to include AuthenticationSystem in Application Controller instead
   2    include AuthenticatedSystem

Now include restful_authentication in the application controller:

   1  class ApplicationController < ActionController::Base
   2    include AuthenticatedSystem

Integrate restful_authentication with your views

First let’s create a controller and view by executing the generate script:

   1  script/generate controller home index

Modify index.html.erb as follows:

   1  <h1>Welcome</h1>
   2  
   3  <% if logged_in? %>
   4    <p><strong>You are logged in as <%=h current_user.login %></strong></p>
   5    <p><%= link_to 'Logout', logout_path %></p>
   6  <% else %>
   7    <p><strong>You are currently not logged in.</strong></p>
   8    <p>
   9      <%= link_to 'Login', login_path %> or
  10      <%= link_to 'Sign Up', signup_path %>
  11    </p>
  12  <% end %>

Start Rails and access your application. If needed, add the following to config/routes.rb to make the home controller the default:

   1  map.root :controller => "home"

Login, sign up and logout should work.

Tagged rails, ruby, authentication, restful_authentication

How to install the exception_logger Rails plugin and protect the logs with basic authentication

Ruby posted 11 months ago by christian

This snippet explains how to install and use the Rails exception_logger plugin. I’ll also show you how to protect your logs by extending the plugin with basic authentication.

   1  script/plugin source http://svn.techno-weenie.net/projects/plugins
   2  script/plugin install exception_logger

I’m using Rails Edge on this project, so I had to install classic pagination also:

   1  script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination

Next create and execute the migration file:

   1  ./script/generate exception_migration
   2  rake db:migrate

Before starting the server we need to setup the routes:

   1  map.exceptions '/logged_exceptions/:action/:id', :controller => 'logged_exceptions', :action => 'index', :id => nil 

You also need to include the ExceptionLoggable in your ApplicationController:

   1  class ApplicationController < ActionController::Base
   2    include ExceptionLoggable
   3  ...

Start your server and access the exception log at /logged_exceptions.

Exceptions can contain email addresses, passwords, credit card numbers, so you’ll want to protect /logged_exceptions from the public. This can be done by adding the following code to the end of environment.rb:

   1  config.after_initialize do
   2    require 'application' unless Object.const_defined?(:ApplicationController)
   3    LoggedExceptionsController.class_eval do
   4      before_filter :authenticate
   5  
   6      protected
   7  
   8      def authenticate
   9        authenticate_or_request_with_http_basic do |username, password|
  10          username == "foo" && password == "bar"
  11        end
  12      end
  13    end
  14  end

With this code we add a before filter that shows a login dialog to anyone trying to access /logged_exception/. Note that this requires Rails 2.0 basic authentication to work, so make sure you have the proper version installed.

Tagged ruby, exception_logger, install, routes, rails, basic, authentication