To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / .svn / pristine / bc / bcf601e4c2eab267682f5366299899e20f6d08d2.svn-base @ 1297:0a574315af3e

History | View | Annotate | Download (7.95 KB)

1 1296:038ba2d95de8 Chris
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