Skip to content

appoxy/open_id_authentication

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

60 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OpenIdAuthentication

Same as forked version, but modified for SimpleDB.

Provides a thin wrapper around the excellent ruby-openid gem from JanRan.

To understand what OpenID is about and how it works, it helps to read the documentation for lib/openid/consumer.rb from that gem.

The specification used is http://openid.net/specs/openid-authentication-2_0.html.

Prerequisites

OpenID authentication uses the session, so be sure that you haven't turned that off. It also relies on a number of database tables to store the authentication keys.

This particular plugin also relies on the fact that the authentication action allows for both POST and GET operations. If you're using RESTful authentication, you'll need to explicitly allow for this in your routes.rb.

The plugin also expects to find a root_url method that points to the home page of your site. You can accomplish this by using a root route in config/routes.rb:

map.root :controller => 'articles'

The root_url will be used as the default return_to and realm value for OpenID. If you'd like to specify a different realm, just pass in :realm=>"http://*.mydomain.com" in the options for authenticate_with_open_id.

Installation

gem install openid_auth

Example

  • NOTE: These examples may need some updating! *

This example is just to meant to demonstrate how you could use OpenID authentication. You might well want to add salted hash logins instead of plain text passwords and other requirements on top of this. Treat it as a starting point, not a destination.

Note that the User model referenced in the simple example below has an 'identity_url' attribute. You will want to add the same or similar field to whatever model you are using for authentication.

Also of note is the following code block used in the example below:

authenticate_with_open_id do |result, identity_url| ... end

In the above code block, 'identity_url' will need to match user.identity_url exactly. 'identity_url' will be a string in the form of 'http://example.com' - If you are storing just 'example.com' with your user, the lookup will fail.

There is a handy method in this plugin called 'normalize_url' that will help with validating OpenID URLs.

OpenIdAuthentication.normalize_url(user.identity_url)

The above will return a standardized version of the OpenID URL - the above called with 'example.com' will return 'http://example.com/' It will also raise an InvalidOpenId exception if the URL is determined to not be valid. Use the above code in your User model and validate OpenID URLs before saving them.

config/routes.rb

map.root :controller => 'articles' map.resource :session

app/views/sessions/new.erb

<% form_tag(session_url) do %>

Username: <%= text_field_tag "name" %>

<p>
  <label for="password">Password:</label>
  <%= password_field_tag %>
</p>

<p>
  ...or use:
</p>

<p>
  <label for="openid_identifier">OpenID:</label>
  <%= text_field_tag "openid_identifier" %>
</p>

<p>
  <%= submit_tag 'Sign in', :disable_with => "Signing in&hellip;" %>
</p>

<% end %>

app/controllers/sessions_controller.rb class SessionsController < ApplicationController def create if using_open_id? open_id_authentication else password_authentication(params[:name], params[:password]) end end

protected
  def password_authentication(name, password)
    if @current_user = @account.users.authenticate(params[:name], params[:password])
      successful_login
    else
      failed_login "Sorry, that username/password doesn't work"
    end
  end

  def open_id_authentication
    authenticate_with_open_id do |result, identity_url|
      if result.successful?
        if @current_user = @account.users.find_by_identity_url(identity_url)
          successful_login
        else
          failed_login "Sorry, no user by that identity URL exists (#{identity_url})"
        end
      else
        failed_login result.message
      end
    end
  end


private
  def successful_login
    session[:user_id] = @current_user.id
    redirect_to(root_url)
  end

  def failed_login(message)
    flash[:error] = message
    redirect_to(new_session_url)
  end

end

If you're fine with the result messages above and don't need individual logic on a per-failure basis, you can collapse the case into a mere boolean:

def open_id_authentication
  authenticate_with_open_id do |result, identity_url|
    if result.successful? && @current_user = @account.users.find_by_identity_url(identity_url)
      successful_login
    else
      failed_login(result.message || "Sorry, no user by that identity URL exists (#{identity_url})")
    end
  end
end

Simple Registration OpenID Extension

Some OpenID Providers support this lightweight profile exchange protocol. See more: http://www.openidenabled.com/openid/simple-registration-extension

You can support it in your app by changing #open_id_authentication

  def open_id_authentication(identity_url)
    # Pass optional :required and :optional keys to specify what sreg fields you want.
    # Be sure to yield registration, a third argument in the #authenticate_with_open_id block.
    authenticate_with_open_id(identity_url, 
        :required => [ :nickname, :email ],
        :optional => :fullname) do |result, identity_url, registration|
      case result.status
      when :missing
        failed_login "Sorry, the OpenID server couldn't be found"
      when :invalid
        failed_login "Sorry, but this does not appear to be a valid OpenID"
      when :canceled
        failed_login "OpenID verification was canceled"
      when :failed
        failed_login "Sorry, the OpenID verification failed"
      when :successful
        if @current_user = @account.users.find_by_identity_url(identity_url)
          assign_registration_attributes!(registration)

          if current_user.save
            successful_login
          else
            failed_login "Your OpenID profile registration failed: " +
              @current_user.errors.full_messages.to_sentence
          end
        else
          failed_login "Sorry, no user by that identity URL exists"
        end
      end
    end
  end
  
  # registration is a hash containing the valid sreg keys given above
  # use this to map them to fields of your user model
  def assign_registration_attributes!(registration)
    model_to_registration_mapping.each do |model_attribute, registration_attribute|
      unless registration[registration_attribute].blank?
        @current_user.send("#{model_attribute}=", registration[registration_attribute])
      end
    end
  end

  def model_to_registration_mapping
    { :login => 'nickname', :email => 'email', :display_name => 'fullname' }
  end

Attribute Exchange OpenID Extension

Some OpenID providers also support the OpenID AX (attribute exchange) protocol for exchanging identity information between endpoints. See more: http://openid.net/specs/openid-attribute-exchange-1_0.html

Accessing AX data is very similar to the Simple Registration process, described above -- just add the URI identifier for the AX field to your :optional or :required parameters. For example:

    authenticate_with_open_id(identity_url, 
        :required => [ :email, 'http://schema.openid.net/birthDate' ]) do |result, identity_url, registration|

This would provide the sreg data for :email, and the AX data for 'http://schema.openid.net/birthDate'

Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license

Releases

No releases published

Packages

No packages published

Languages

  • Ruby 100.0%