README
222 lines
| 8.0 KiB
| text/plain
|
TextLexer
|
r2377 | 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 | |||
============= | |||
|
r9346 | OpenID authentication uses the session, so be sure that you haven't turned that off. | |
|
r2377 | ||
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. | |||
|
r9346 | If you're using RESTful authentication, you'll need to explicitly allow for this in your routes.rb. | |
|
r2377 | ||
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 | |||
|
r9346 | ||
|
r2377 | 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…" %> | |||
</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 | |||
|
r9346 | ||
|
r2377 | 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. | |||
|
r9346 | authenticate_with_open_id(identity_url, | |
|
r2377 | :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 | |||
|
r9346 | ||
|
r2377 | # 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: | |||
|
r9346 | authenticate_with_open_id(identity_url, | |
|
r2377 | :required => [ :email, 'http://schema.openid.net/birthDate' ]) do |result, identity_url, registration| | |
|
r9346 | ||
|
r2377 | 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 |