Home
openid_enabled is a plugin to ease the development of openid authentication. Currently, the identification proces of a user can be done through this system.
A quick user login writeup
This is just a very quick example that uses all the features in the library. It shows you how to use the plugin for some very simple user registration.
Theoretical
This is something I wrote a bit earlier about this plugin. It talks about how I would handle user-creation. This tutorial follows that structure for user-creation.
I haven’t tested this, but the nicest way to create new users, is probably by letting them identify them first by their OpenID service. This would set the session[:users_controller_openid_url]. It is best to set that as the openid_url in the user-model (a migration has been generated to add that variable to the User model) like @user.openid_url = session[:users_controller_openid_url] . You must ensure the user has logged in first, otherwise that session variable will be nil, and the user will not be able to identify himself by it. You can use new_user_path just like you used to do, just set the openid_url to the user-object in the controller each time he tries to save.
Create a new rails project
rails stereo -d mysql
Setup the database
> mysql -u root -p
>> create schema stereo_development;
>> grant all on stereo_development.* to 'stereodev'@'localhost' identified by 'password';
> edit config/database.yml to reflect this user
Get the sweetest plugin in the world
> gem install 'ruby-openid' # credit should actually go to the guys that made this ruby gem ^_^
> cd vendor/plugins/
> git clone git://github.com/madnificent/openid_enabled.git
Use the generators
script/generate scaffold User name:string
script/generate openid_support User UsersController
This last command is where the magic happens, this generates everything we’ll need to be able to do OpenID authentication. You may remove the stuff it generated by running script/destroy openid_support User UsersController. What is not noted elsewhere in this tutorial are the named paths. You can see how to do your own login form in the _login_form.html.erb partial that has been generated too.
Update the index view
In the index view, we’ll add some output and a login form:
<h1>Login here</h1>
<% if session[:user_openid_url] -%>
You are currently identified by <%= session[:user_openid_url] %>.
<% if @logged_in_user -%>
Which belongs to <%= @logged_in_user.name %>
<% end -%>
<% end -%>
<%= render :partial => 'login_form' %>
Update the controllers
index
We need to give access to the @logged_in_user variable through the controller to get our index-view to work again. In the index-action we add:
@logged_in_user = logged_in_user
The method logged_in_user is given, because the controller calls the openid_enabled “User” method at the top.
create
set the openid_url for the currently logged-in user:
@user = User.new(params[:user])
@user.openid_url = session[:user_openid_url]
You should do some validations in the model to ensure that the openid_url is there AND that a user only has a single openid_url. (Perhaps the task generator should do that too?)
update
ensure users can only update their own user
if @user.openid_url != session[:user_openid_url]
flash[:notice] = "Not your user!"
redirect_to users_url
return
end
destroy
Only destroy yourself!
@user.destroy unless @user.openid_url != session[:user_openid_url]
Test-run!
This should be it… your application should be up-and-running by now. OpenID has never been this simple :)
Extra
In the latest master, there are some extras. These aren’t incorporated in this manual just yet.
talks_openid
You can add
talks_openid Userto a controller, which will give you the method logged_in_user. It does not add any of the methods openid_enabled adds to the controller, except for this single helper-method.
has_openid
You can add
has_openid Userwhich is just an alias for openid_enabled. It just looks somewhat better.
redirection after logging in
There are currently two ways to handle redirection on a per-controller basis and one way to do it on a per-form basis. This section describes the controller-wide specification. There is an easy way, and a nifty way.
The easy way out
Since 74d23ab34fe96aa11f901385f446b835ac1d1bdf it is possible to redirect to a different action than index after a successful or failed login. Rails does not allow you to use the url_for helper or friends for this (which is a bit sad), since the routes aren’t initialized at this stage. When the parameters aren’t given, all logins (successful and failed ones) redirect to the index action.
has_openid User, :login_redirects_to => '/music', :failed_login_redirects_to => 'http://foo.com/bar'
You can skip either of those variables, in which case the system will fall back to default-redirection. This currently redirects the user to the index-action of the current controller.
The nifty way out
The other possibility you have, is to create methods in which you define where the user should be redirected to. There are two methods that can be defined.
The first one is named login_redirect and it receives the openid_url that was successfully identified.
def login_redirect( openid_url )
user = User.find_by_openid_url( openid_url )
user ? edit_user_path( user ) : users_path
end
The second one is the failed_login_redirect, which takes an error (OpenID::OpenIDError) or a status (defined in OpenID::Consumer) or nil. The error resembles the failure of finding an OpenID service. Nil resembles an empty openid_url. The returned status would be the status returned by the complete-request in the library. The important statuses are:
- OpenID::Consumer::FAILURE
- OpenID::Consumer::SETUP_NEEDED
- OpenID::Consumer::CANCEL
We could send our users to claimid.com if the service gave us an error, or if the user didn’t enter a valid openid_url. Upon any other failure, we’ll send them to the index-action again.
def failed_login_redirect( state )
if state.nil? || state.class == OpenID.OpenIDError
"http://www.claimid.com"
else
url_for :action => "index"
end
end
Since these methods can play with everything your controller knows, they are very flexible at the cost of some added complexity.
redirection on a per-form basis
Since c8fa4fce99f1c25519ae0182b0558028b23e5aa7 it is possible to send the user to a location after logging in on a per-form basis. What you need for this, are some post-variables in the login-form. A login-form could look like this:
<% form_tag start_login_users_path, :method => :get do -%>
<%= text_field_tag :openid_url %>
<%= hidden_field_tag 'login_redirects_to', cities_path %>
<%= hidden_field_tag 'failed_login_redirects_to', users_path %>
<%= submit_tag 'OpenIDfy me!' %>
<% end -%>
The login_redirects_to tag stores where the user will be redirected to after a successful login, failed_login_redirects_to is the redirects-target for a failed login. You can skip either of those variables, in which case the system will fall-back to the system described in ‘redirection after logging in’.
