]> git.openstreetmap.org Git - rails.git/blob - vendor/plugins/open_id_authentication/README
Merge branch 'master' into openid
[rails.git] / vendor / plugins / open_id_authentication / README
1 OpenIdAuthentication
2 ====================
3
4 Provides a thin wrapper around the excellent ruby-openid gem from JanRan. Be sure to install that first:
5
6   gem install ruby-openid
7
8 To understand what OpenID is about and how it works, it helps to read the documentation for lib/openid/consumer.rb
9 from that gem.
10
11 The specification used is http://openid.net/specs/openid-authentication-2_0.html.
12
13
14 Prerequisites
15 =============
16
17 OpenID authentication uses the session, so be sure that you haven't turned that off.
18
19 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:
20
21   OpenIdAuthentication.store = :file
22
23 This particular plugin also relies on the fact that the authentication action allows for both POST and GET operations.
24 If you're using RESTful authentication, you'll need to explicitly allow for this in your routes.rb.
25
26 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:
27
28   map.root :controller => 'articles'
29
30 This plugin relies on Rails Edge revision 6317 or newer.
31
32
33 Example
34 =======
35
36 This example is just to meant to demonstrate how you could use OpenID authentication. You might well want to add
37 salted hash logins instead of plain text passwords and other requirements on top of this. Treat it as a starting point,
38 not a destination.
39
40 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
41 model you are using for authentication.
42
43 Also of note is the following code block used in the example below:
44
45   authenticate_with_open_id do |result, identity_url|
46     ...
47   end
48
49 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' -
50 If you are storing just 'example.com' with your user, the lookup will fail.
51
52 There is a handy method in this plugin called 'normalize_url' that will help with validating OpenID URLs.
53
54   OpenIdAuthentication.normalize_url(user.identity_url)
55
56 The above will return a standardized version of the OpenID URL - the above called with 'example.com' will return 'http://example.com/'
57 It will also raise an InvalidOpenId exception if the URL is determined to not be valid.
58 Use the above code in your User model and validate OpenID URLs before saving them.
59
60 config/routes.rb
61
62   map.root :controller => 'articles'
63   map.resource :session
64
65
66 app/views/sessions/new.erb
67
68   <% form_tag(session_url) do %>
69     <p>
70       <label for="name">Username:</label>
71       <%= text_field_tag "name" %>
72     </p>
73
74     <p>
75       <label for="password">Password:</label>
76       <%= password_field_tag %>
77     </p>
78
79     <p>
80       ...or use:
81     </p>
82
83     <p>
84       <label for="openid_identifier">OpenID:</label>
85       <%= text_field_tag "openid_identifier" %>
86     </p>
87
88     <p>
89       <%= submit_tag 'Sign in', :disable_with => "Signing in&hellip;" %>
90     </p>
91   <% end %>
92
93 app/controllers/sessions_controller.rb
94   class SessionsController < ApplicationController
95     def create
96       if using_open_id?
97         open_id_authentication
98       else
99         password_authentication(params[:name], params[:password])
100       end
101     end
102
103
104     protected
105       def password_authentication(name, password)
106         if @current_user = @account.users.authenticate(params[:name], params[:password])
107           successful_login
108         else
109           failed_login "Sorry, that username/password doesn't work"
110         end
111       end
112
113       def open_id_authentication
114         authenticate_with_open_id do |result, identity_url|
115           if result.successful?
116             if @current_user = @account.users.find_by_identity_url(identity_url)
117               successful_login
118             else
119               failed_login "Sorry, no user by that identity URL exists (#{identity_url})"
120             end
121           else
122             failed_login result.message
123           end
124         end
125       end
126
127
128     private
129       def successful_login
130         session[:user_id] = @current_user.id
131         redirect_to(root_url)
132       end
133
134       def failed_login(message)
135         flash[:error] = message
136         redirect_to(new_session_url)
137       end
138   end
139
140
141
142 If you're fine with the result messages above and don't need individual logic on a per-failure basis,
143 you can collapse the case into a mere boolean:
144
145     def open_id_authentication
146       authenticate_with_open_id do |result, identity_url|
147         if result.successful? && @current_user = @account.users.find_by_identity_url(identity_url)
148           successful_login
149         else
150           failed_login(result.message || "Sorry, no user by that identity URL exists (#{identity_url})")
151         end
152       end
153     end
154
155
156 Simple Registration OpenID Extension
157 ====================================
158
159 Some OpenID Providers support this lightweight profile exchange protocol.  See more: http://www.openidenabled.com/openid/simple-registration-extension
160
161 You can support it in your app by changing #open_id_authentication
162
163       def open_id_authentication(identity_url)
164         # Pass optional :required and :optional keys to specify what sreg fields you want.
165         # Be sure to yield registration, a third argument in the #authenticate_with_open_id block.
166         authenticate_with_open_id(identity_url,
167             :required => [ :nickname, :email ],
168             :optional => :fullname) do |result, identity_url, registration|
169           case result.status
170           when :missing
171             failed_login "Sorry, the OpenID server couldn't be found"
172           when :invalid
173             failed_login "Sorry, but this does not appear to be a valid OpenID"
174           when :canceled
175             failed_login "OpenID verification was canceled"
176           when :failed
177             failed_login "Sorry, the OpenID verification failed"
178           when :successful
179             if @current_user = @account.users.find_by_identity_url(identity_url)
180               assign_registration_attributes!(registration)
181
182               if current_user.save
183                 successful_login
184               else
185                 failed_login "Your OpenID profile registration failed: " +
186                   @current_user.errors.full_messages.to_sentence
187               end
188             else
189               failed_login "Sorry, no user by that identity URL exists"
190             end
191           end
192         end
193       end
194
195       # registration is a hash containing the valid sreg keys given above
196       # use this to map them to fields of your user model
197       def assign_registration_attributes!(registration)
198         model_to_registration_mapping.each do |model_attribute, registration_attribute|
199           unless registration[registration_attribute].blank?
200             @current_user.send("#{model_attribute}=", registration[registration_attribute])
201           end
202         end
203       end
204
205       def model_to_registration_mapping
206         { :login => 'nickname', :email => 'email', :display_name => 'fullname' }
207       end
208
209 Attribute Exchange OpenID Extension
210 ===================================
211
212 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
213
214 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:
215
216         authenticate_with_open_id(identity_url,
217             :required => [ :email, 'http://schema.openid.net/birthDate' ]) do |result, identity_url, registration|
218
219 This would provide the sreg data for :email, and the AX data for 'http://schema.openid.net/birthDate'
220
221
222
223 Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license