github
Advanced Search
  • Home
  • Pricing and Signup
  • Explore GitHub
  • Blog
  • Login

rails / open_id_authentication

  • Admin
  • Watch Unwatch
  • Fork
  • Your Fork
  • Pull Request
  • Download Source
    • 312
    • 37
  • Source
  • Commits
  • Network (37)
  • Graphs
  • Branch: master

click here to add a description

click here to add a homepage

  • Branches (1)
    • master ✓
  • Tags (0)
Sending Request…
Enable Donations

Pledgie Donations

Once activated, we'll place the following badge in your repository's detail box:
Pledgie_example
This service is courtesy of Pledgie.

OpenID authentication plugin — Read more

  cancel

http://rubyonrails.org

  cancel
  • Private
  • Read-Only
  • HTTP Read-Only

This URL has Read+Write access

Warn if inmemory store is used 
josh (author)
Thu Jan 21 12:00:06 -0800 2010
commit  8b97cd2e9e3bbe1650ea526b6be3555b159f5ad4
tree    ea11e21033c86c78a3ed51b9bfcffe37afd5c301
parent  e3be4f290cebed9f840831a703185fcc21263567
open_id_authentication /
name age
history
message
file CHANGELOG Wed Jan 13 08:32:09 -0800 2010 Note rack branch merge in CHANGELOG [josh]
file README Wed Jan 13 08:09:45 -0800 2010 Axe DB store, use memcache. [josh]
file init.rb Thu Jan 21 11:42:55 -0800 2010 require open_id_authentication from plugin init [josh]
directory lib/ Thu Jan 21 12:00:06 -0800 2010 Warn if inmemory store is used [josh]
README
OpenIdAuthentication
====================

Provides a thin wrapper around the excellent ruby-openid gem from JanRan. Be sure to install that first:

  gem install ruby-openid

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.

Alternatively, you can use the file-based store, which just relies on on tmp/openids being present in RAILS_ROOT. But be 
aware that this store only works if you have a single application server. And it's not safe to use across NFS. It's 
recommended that you use the database store if at all possible. To use the file-based store, you'll also have to add 
this line to your config/environment.rb:

  OpenIdAuthentication.store = :file

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'

This plugin relies on Rails Edge revision 6317 or newer.


Example
=======

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 %>
    <p>
      <label for="name">Username:</label>
      <%= text_field_tag "name" %>
    </p>

    <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
Blog | Support | Training | Contact | API | Status | Twitter | Help | Security
© 2010 GitHub Inc. All rights reserved. | Terms of Service | Privacy Policy
Powered by the Dedicated Servers and
Cloud Computing of Rackspace Hosting®
Dedicated Server