Links
Open Id Authentication
Categories
Open Id Authentication
Provides a thin wrapper around the excellent ruby-openid gem from JanRain. 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.
Prerequisites
OpenID authentication uses the session, so be sure that you haven’t turned that off. It also relies on tmp/openids being present in RAILS_ROOT. The install.rb should install that automatically as you get the plugin, but if not, be sure to do that yourself.
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.
Example
This example is just to meant to demonstrate how you could use OpenID authentication. You’ll 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.
config/routes.rb
map.open_id_complete 'session', :controller => "session", :action => "create", :requirements => { :method => :get }
map.resource :session
app/controllers/session_controller.rb
class SessionController < ApplicationController
def create
if open_id?(params[:name])
open_id_authentication(params[:name])
else
password_authentication(params[:name], params[:password])
end
end
protected
def password_authentication(name, password)
if @current_user = @account.users.find_by_name_and_password(params[:name], params[:password])
successful_login
else
failed_login "Sorry, that username/password doesn't work"
end
end
def open_id_authentication(identity_url)
authenticate_with_open_id(identity_url) do |status, identity_url|
case status
when :missing
failed_login "Sorry, the OpenID server couldn't be found"
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)
successful_login
else
failed_login "Sorry, no user by that identity URL exists"
end
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
# Set #root_url if your root url has a different named route.
#
# map.home '', :controller => ..., :action => ...
#
# Otherwise, name the route 'root' and leave this method out.
def root_url
home_url
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 |status, identity_url, registration|
case status
when :missing
failed_login "Sorry, the OpenID server couldn't be found"
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)
# registration is a hash containing the valid sreg keys given above
# use this to map them to fields of your user model
{'login=' => 'nickname', 'email=' => 'email', 'display_name=' => 'fullname'}.each do |attr, reg|
current_user.send(attr, registration[reg]) unless registration[reg].blank?
end
unless current_user.save
flash[:error] = "Error saving the fields from your OpenID profile: #{current_user.errors.full_messages.to_sentence}"
end
successful_login
else
failed_login "Sorry, no user by that identity URL exists"
end
end
end
end
Copyright © 2007 David Heinemeier Hansson, released under the MIT license
Vitals
| Home | http://github.com/rails/open_id_authentication/tree/master |
|---|---|
| Repository | git://github.com/rails/open_id_authentication.git |
| License | Rails' (MIT) |
| Tags |
-v auth authentication ddd dg dhh identity it nraghusingh openid
|
| Rating | (52 votes) |
| Owner | David Heinemeier Hansson |
| Created | 27 February 2007 |
Comments
-
I have noticed that nothing is mentioned on this page about making it so the user can be logged in automatically in the future. There is no 'remember' option.
I am trying to implement OpenID on a new app of mine, and require a 'remember me' option.
I am thinking that the best way to go is to set a cookie that is the OpenID when someone logs in. Then when they return to the page after their session has expired, initiate a new openid request and try to do it immediately.
However, this check for whether or not the cookie is set needs to be done in 'application.rb', so it can be available to all controllers, not just the logging in controller. But, then all controllers can no longer access the 'open_id_authentication' method from SessionController. This is a problem. Currently, my solution is to have it redirect to the 'create' action in SessionController.
I am looking for a more elegant solution. I would prefer to not to have to do the extra redirect to the 'create' action in SessionController and just start the openid request right there. BUT the OpenID code shouldn't go in 'application.rb'.
One solution would be to just not reinitiate an OpenID login from the cookie and instead store some sort of salted hash, but it seems to me that is would be most secure to verify that this site is still allowed to use that particular OpenID. Because of the 'immediate' option with OpenID, this shouldn't cause too much of a delay for accessing the site.
Any thoughts?
-
I'm sure I'm missing something here, but the example didn't work that much for me. POST parameters are not provided after the authentication, so I couldn't just use the same params[:name] again. Also I needed to change "case status" to status.instancevariableget(:@code)
-
There's a bug in the case statement. Ruby calls the === operator on the objects in the when clause, passing the object at the head of the case statement as a parameter. The === operator has been overloaded on the OpenIdAuthentication::Result class to allow for case statements using symbols like that used in the example. But the === method is never called on this class. To fix it, expose the @code member on Result (attr_accessor :code) and change the case statement from
case status when :missing ... end
to
case status.code when :missing ... end
-
A full working sample application with restfulauthentication + openid_authenication is available at http://www.bencurtis.com/archives/2007/05/openid-sample-application/
-
Does the ":requirements => { :method => :get }" bit really work out of the box in any recent version of Rails? Doesn't break anything, but neither does it seem to actually limit the request methods you can use.
Something similar <http://dev.rubyonrails.org/changeset/4209> was built-in once, but I don't think it is anymore -- to my knowledge, you need the Request Routing plugin <http://agilewebdevelopment.com/plugins/request_routing>.
Unless I'm mistaken, the README should be updated to reflect this.
-
After researching it further, it seems routing by method _is_ possible, but you need ":conditions => { :method => :get }" rather than ":requirements ..." as the README claims.
-
There is a bug in the return URL generation in the plugin.
def open_id_redirect_url(open_id_response) open_id_response.redirect_url( request.protocol + request.host_with_port + "/", open_id_response.return_to("#{request.url}?open_id_complete=1") ) endshould take into account that request.uri (which itself isn't in the version of Rails I'm using) might already include parameters. If it does, Rails attaches "?open_id_complete=1" to the last parameter, like so: Parameters: {"format"=>"html?openid_complete=1", "openid.mode"=>"idres", "openid.return_to"=> ... }
My suggestion is the following: def openid_redirecturl(open_id_response) return_url = request.url returnurl << returnurl.include?('?') ? '&' : '?' returnurl << openid_complete=1
open_id_response.redirect_url( request.protocol + request.host_with_port + "/", open_id_response.return_to(return_url) )end
-
I've run into a wall with this. I have followed the tutorial at http://www.bencurtis.com/archives/2007/03/rails-openid-and-acts-as-authenticated/ and it works perfectly in development mode. If the account doesn't exist, my app goes out and checks that the openid account authorizes the login and then creates a new account with only the identity_url field filled in. If the account already exists, it simply logs the person in. Flawless and beautiful. Love it!
As soon as I switch to production mode, it's a less enjoyable ride. First let me say that I made sure my databases were identical and I had full access to both. I even entered myappname_production into the development area in database.yml and it works perfectly. Database ok? check! OSX: 10.4.10 Rails: 1.2.3 Ruby: 1.8.6 ruby-openid: 1.1.4 ruby-yadis: 0.3.4 OpenIdAuthentication plugin: can't find a version # acts_as_authenticated: can't find version # changelog stops at 1 aug 2006
Here are the lines from my development log file that are missing from my production log: OpenIdAuthentication::Nonce Columns (0.004343) SHOW FIELDS FROM openid_authenticationnonces OpenIdAuthentication::Nonce Load (0.004212) SELECT * FROM openid_authenticationnonces WHERE (openid_authenticationnonces. 'nonce' = '8noyAML7') LIMIT 1 SQL (0.000420) BEGIN SQL (0.000843) INSERT INTO openid_authenticationnonces ('created', 'nonce') VALUES(1184979407, '8noyAML7') SQL (0.001165) COMMIT OpenIdAuthentication::Association Columns (0.005295) SHOW FIELDS FROM openid_authenticationassociations OpenIdAuthentication::Association Load (0.004116) SELECT * FROM openid_authenticationassociations WHERE (openid_authenticationassociations.'server_url' = 'http://www.myopenid.com/server'
There are more of the same after a bit, all dealing with the OpenIdAuthentication routines. Why would the OpenIdAuthentication code fire when in development mode and not in production mode? I'm lost as to where to look as I've never experienced a plugin only working in one mode and not the other.
-
I have installed "sudo gem install ruby-openid" successfully then installed the plugin.
"script/plugin install http://svn.rubyonrails.org/rails/plugins/open_id_authentication/"
the error i get is "no such file to load -- openid/extensions/sreg" and in the console "Install the ruby-openid gem to enable OpenID support"
i'm using rails 2.0.2 and open-id 2.0.4.
in script/console "puts OpenID::VERSION" yeilds "2.0.4"
"puts OpenID::SRed" yeilds "nil"
yet when i "open /opt/local/lib/ruby/gems/1.8/gems/ruby-openid-2.0.4/lib/openid/extensions"
i clearly see sreg.rb in the folder
a few people have mentioned the need to patch the plugin using "http://dev.rubyonrails.org/ticket/10604" though I think this is only for openid authentication plugin's that are pre 2.0, and i have no idea how to implement the patch if i did indeed need it.
If anyone else had the same problem and fixed it, or if you need some more info about my setup before you can help, then please let me know!!
-
Benjamin,
Why do you ever need to expire the session if you are just going to log the user in automatically when they come back?

