openid_auth 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,35 @@
1
+ * Fake HTTP method from OpenID server since they only support a GET. Eliminates the need to set an extra route to match the server's reply. [Josh Peek]
2
+
3
+ * OpenID 2.0 recommends that forms should use the field name "openid_identifier" rather than "openid_url" [Josh Peek]
4
+
5
+ * Return open_id_response.display_identifier to the application instead of .endpoints.claimed_id. [nbibler]
6
+
7
+ * Add Timeout protection [Rick]
8
+
9
+ * An invalid identity url passed through authenticate_with_open_id will no longer raise an InvalidOpenId exception. Instead it will return Result[:missing] to the completion block.
10
+
11
+ * Allow a return_to option to be used instead of the requested url [Josh Peek]
12
+
13
+ * Updated plugin to use Ruby OpenID 2.x.x [Josh Peek]
14
+
15
+ * Tied plugin to ruby-openid 1.1.4 gem until we can make it compatible with 2.x [DHH]
16
+
17
+ * Use URI instead of regexps to normalize the URL and gain free, better matching #8136 [dkubb]
18
+
19
+ * Allow -'s in #normalize_url [Rick]
20
+
21
+ * remove instance of mattr_accessor, it was breaking tests since they don't load ActiveSupport. Fix Timeout test [Rick]
22
+
23
+ * Throw a InvalidOpenId exception instead of just a RuntimeError when the URL can't be normalized [DHH]
24
+
25
+ * Just use the path for the return URL, so extra query parameters don't interfere [DHH]
26
+
27
+ * Added a new default database-backed store after experiencing trouble with the filestore on NFS. The file store is still available as an option [DHH]
28
+
29
+ * Added normalize_url and applied it to all operations going through the plugin [DHH]
30
+
31
+ * Removed open_id? as the idea of using the same input box for both OpenID and username has died -- use using_open_id? instead (which checks for the presence of params[:openid_url] by default) [DHH]
32
+
33
+ * Added OpenIdAuthentication::Result to make it easier to deal with default situations where you don't care to do something particular for each error state [DHH]
34
+
35
+ * Stop relying on root_url being defined, we can just grab the current url instead [DHH]
data/README.markdown ADDED
@@ -0,0 +1,222 @@
1
+ OpenIdAuthentication
2
+ ====================
3
+
4
+ Same as forked version, but modified for SimpleDB.
5
+
6
+ Provides a thin wrapper around the excellent ruby-openid gem from JanRan. Be sure to install that first:
7
+
8
+ gem install ruby-openid
9
+
10
+ To understand what OpenID is about and how it works, it helps to read the documentation for lib/openid/consumer.rb
11
+ from that gem.
12
+
13
+ The specification used is http://openid.net/specs/openid-authentication-2_0.html.
14
+
15
+
16
+ Prerequisites
17
+ =============
18
+
19
+ OpenID authentication uses the session, so be sure that you haven't turned that off. It also relies on a number of
20
+ database tables to store the authentication keys.
21
+
22
+ This particular plugin also relies on the fact that the authentication action allows for both POST and GET operations.
23
+ If you're using RESTful authentication, you'll need to explicitly allow for this in your routes.rb.
24
+
25
+ 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:
26
+
27
+ map.root :controller => 'articles'
28
+
29
+ The root_url will be used as the default return_to and realm value for OpenID. If you'd like to specify a different
30
+ realm, just pass in :realm=>"http://*.mydomain.com" in the options for authenticate_with_open_id.
31
+
32
+ Example
33
+ =======
34
+
35
+ This example is just to meant to demonstrate how you could use OpenID authentication. You might well want to add
36
+ salted hash logins instead of plain text passwords and other requirements on top of this. Treat it as a starting point,
37
+ not a destination.
38
+
39
+ 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
40
+ model you are using for authentication.
41
+
42
+ Also of note is the following code block used in the example below:
43
+
44
+ authenticate_with_open_id do |result, identity_url|
45
+ ...
46
+ end
47
+
48
+ 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' -
49
+ If you are storing just 'example.com' with your user, the lookup will fail.
50
+
51
+ There is a handy method in this plugin called 'normalize_url' that will help with validating OpenID URLs.
52
+
53
+ OpenIdAuthentication.normalize_url(user.identity_url)
54
+
55
+ The above will return a standardized version of the OpenID URL - the above called with 'example.com' will return 'http://example.com/'
56
+ It will also raise an InvalidOpenId exception if the URL is determined to not be valid.
57
+ Use the above code in your User model and validate OpenID URLs before saving them.
58
+
59
+ config/routes.rb
60
+
61
+ map.root :controller => 'articles'
62
+ map.resource :session
63
+
64
+
65
+ app/views/sessions/new.erb
66
+
67
+ <% form_tag(session_url) do %>
68
+ <p>
69
+ <label for="name">Username:</label>
70
+ <%= text_field_tag "name" %>
71
+ </p>
72
+
73
+ <p>
74
+ <label for="password">Password:</label>
75
+ <%= password_field_tag %>
76
+ </p>
77
+
78
+ <p>
79
+ ...or use:
80
+ </p>
81
+
82
+ <p>
83
+ <label for="openid_identifier">OpenID:</label>
84
+ <%= text_field_tag "openid_identifier" %>
85
+ </p>
86
+
87
+ <p>
88
+ <%= submit_tag 'Sign in', :disable_with => "Signing in&hellip;" %>
89
+ </p>
90
+ <% end %>
91
+
92
+ app/controllers/sessions_controller.rb
93
+ class SessionsController < ApplicationController
94
+ def create
95
+ if using_open_id?
96
+ open_id_authentication
97
+ else
98
+ password_authentication(params[:name], params[:password])
99
+ end
100
+ end
101
+
102
+
103
+ protected
104
+ def password_authentication(name, password)
105
+ if @current_user = @account.users.authenticate(params[:name], params[:password])
106
+ successful_login
107
+ else
108
+ failed_login "Sorry, that username/password doesn't work"
109
+ end
110
+ end
111
+
112
+ def open_id_authentication
113
+ authenticate_with_open_id do |result, identity_url|
114
+ if result.successful?
115
+ if @current_user = @account.users.find_by_identity_url(identity_url)
116
+ successful_login
117
+ else
118
+ failed_login "Sorry, no user by that identity URL exists (#{identity_url})"
119
+ end
120
+ else
121
+ failed_login result.message
122
+ end
123
+ end
124
+ end
125
+
126
+
127
+ private
128
+ def successful_login
129
+ session[:user_id] = @current_user.id
130
+ redirect_to(root_url)
131
+ end
132
+
133
+ def failed_login(message)
134
+ flash[:error] = message
135
+ redirect_to(new_session_url)
136
+ end
137
+ end
138
+
139
+
140
+
141
+ If you're fine with the result messages above and don't need individual logic on a per-failure basis,
142
+ you can collapse the case into a mere boolean:
143
+
144
+ def open_id_authentication
145
+ authenticate_with_open_id do |result, identity_url|
146
+ if result.successful? && @current_user = @account.users.find_by_identity_url(identity_url)
147
+ successful_login
148
+ else
149
+ failed_login(result.message || "Sorry, no user by that identity URL exists (#{identity_url})")
150
+ end
151
+ end
152
+ end
153
+
154
+
155
+ Simple Registration OpenID Extension
156
+ ====================================
157
+
158
+ Some OpenID Providers support this lightweight profile exchange protocol. See more: http://www.openidenabled.com/openid/simple-registration-extension
159
+
160
+ You can support it in your app by changing #open_id_authentication
161
+
162
+ def open_id_authentication(identity_url)
163
+ # Pass optional :required and :optional keys to specify what sreg fields you want.
164
+ # Be sure to yield registration, a third argument in the #authenticate_with_open_id block.
165
+ authenticate_with_open_id(identity_url,
166
+ :required => [ :nickname, :email ],
167
+ :optional => :fullname) do |result, identity_url, registration|
168
+ case result.status
169
+ when :missing
170
+ failed_login "Sorry, the OpenID server couldn't be found"
171
+ when :invalid
172
+ failed_login "Sorry, but this does not appear to be a valid OpenID"
173
+ when :canceled
174
+ failed_login "OpenID verification was canceled"
175
+ when :failed
176
+ failed_login "Sorry, the OpenID verification failed"
177
+ when :successful
178
+ if @current_user = @account.users.find_by_identity_url(identity_url)
179
+ assign_registration_attributes!(registration)
180
+
181
+ if current_user.save
182
+ successful_login
183
+ else
184
+ failed_login "Your OpenID profile registration failed: " +
185
+ @current_user.errors.full_messages.to_sentence
186
+ end
187
+ else
188
+ failed_login "Sorry, no user by that identity URL exists"
189
+ end
190
+ end
191
+ end
192
+ end
193
+
194
+ # registration is a hash containing the valid sreg keys given above
195
+ # use this to map them to fields of your user model
196
+ def assign_registration_attributes!(registration)
197
+ model_to_registration_mapping.each do |model_attribute, registration_attribute|
198
+ unless registration[registration_attribute].blank?
199
+ @current_user.send("#{model_attribute}=", registration[registration_attribute])
200
+ end
201
+ end
202
+ end
203
+
204
+ def model_to_registration_mapping
205
+ { :login => 'nickname', :email => 'email', :display_name => 'fullname' }
206
+ end
207
+
208
+ Attribute Exchange OpenID Extension
209
+ ===================================
210
+
211
+ 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
212
+
213
+ 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:
214
+
215
+ authenticate_with_open_id(identity_url,
216
+ :required => [ :email, 'http://schema.openid.net/birthDate' ]) do |result, identity_url, registration|
217
+
218
+ This would provide the sreg data for :email, and the AX data for 'http://schema.openid.net/birthDate'
219
+
220
+
221
+
222
+ Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
@@ -0,0 +1,17 @@
1
+ require 'base64'
2
+ module OpenIdAuthentication
3
+ class Association < SimpleRecord::Base
4
+
5
+ set_table_name :open_id_authentication_associations
6
+
7
+ has_attributes :handle,
8
+ :secret,
9
+ :assoc_type, :server_url
10
+
11
+ has_ints :issued, :lifetime
12
+
13
+ def from_record
14
+ OpenID::Association.new(handle, Base64.decode64(secret), issued, lifetime, assoc_type)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,63 @@
1
+ require 'openid/store/interface'
2
+ require 'base64'
3
+
4
+ module OpenIdAuthentication
5
+ class DbStore < OpenID::Store::Interface
6
+ def self.cleanup_nonces
7
+ puts 'deleting nonces'
8
+ now = Time.now.to_i
9
+ Nonce.delete_all(["timestamp > ? OR timestamp < ?", now + OpenID::Nonce.skew, now - OpenID::Nonce.skew])
10
+ puts 'done'
11
+ end
12
+
13
+ def self.cleanup_associations
14
+ now = Time.now.to_i
15
+ Association.delete_all(:all, :conditions => ['issued + lifetime > ?', now])
16
+ end
17
+
18
+ def store_association(server_url, assoc)
19
+ remove_association(server_url, assoc.handle)
20
+ Association.create(:server_url => server_url,
21
+ :handle => assoc.handle,
22
+ :secret => Base64.encode64(assoc.secret),
23
+ :issued => Time.now.to_i, # assoc.issued,
24
+ :lifetime => assoc.lifetime,
25
+ :assoc_type => assoc.assoc_type)
26
+ end
27
+
28
+ def get_association(server_url, handle = nil)
29
+ assocs = if handle.blank?
30
+ Association.find_all_by_server_url(server_url)
31
+ else
32
+ Association.find_all_by_server_url_and_handle(server_url, handle)
33
+ end
34
+
35
+ assocs.each do |assoc|
36
+ a = assoc.from_record
37
+ if a.expires_in.to_i == 0
38
+ assoc.destroy
39
+ else
40
+ return a
41
+ end
42
+ end if assocs.any?
43
+
44
+ return nil
45
+ end
46
+
47
+ def remove_association(server_url, handle)
48
+
49
+ as = Association.find(:all, :conditions => ['server_url = ? AND handle = ?', server_url, handle])
50
+ as.each do |a|
51
+ a.delete
52
+ end
53
+ return as.size > 0
54
+ end
55
+
56
+ def use_nonce(server_url, timestamp, salt)
57
+ return false if Nonce.find_by_server_url_and_timestamp_and_salt(server_url, timestamp, salt)
58
+ return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew
59
+ Nonce.create(:server_url => server_url, :timestamp => timestamp, :salt => salt)
60
+ return true
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,9 @@
1
+ module OpenIdAuthentication
2
+ class Nonce < SimpleRecord::Base
3
+ set_table_name :open_id_authentication_nonces
4
+
5
+ has_attributes :timestamp,
6
+ :salt,
7
+ :server_url
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ module OpenIdAuthentication
2
+ module Request
3
+ def self.included(base)
4
+ base.alias_method_chain :request_method, :openid
5
+ end
6
+
7
+ def request_method_with_openid
8
+ if !parameters[:_method].blank? && parameters[:open_id_complete] == '1'
9
+ parameters[:_method].to_sym
10
+ else
11
+ request_method_without_openid
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ # In Rails 2.3, the request object has been renamed
18
+ # from AbstractRequest to Request
19
+ if defined? ActionController::Request
20
+ ActionController::Request.send :include, OpenIdAuthentication::Request
21
+ else
22
+ ActionController::AbstractRequest.send :include, OpenIdAuthentication::Request
23
+ end
@@ -0,0 +1,20 @@
1
+ # http://trac.openidenabled.com/trac/ticket/156
2
+ module OpenID
3
+ @@timeout_threshold = 20
4
+
5
+ def self.timeout_threshold
6
+ @@timeout_threshold
7
+ end
8
+
9
+ def self.timeout_threshold=(value)
10
+ @@timeout_threshold = value
11
+ end
12
+
13
+ class StandardFetcher
14
+ def make_http(uri)
15
+ http = @proxy.new(uri.host, uri.port)
16
+ http.read_timeout = http.open_timeout = OpenID.timeout_threshold
17
+ http
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,242 @@
1
+ require 'uri'
2
+ require 'openid/extensions/sreg'
3
+ require 'openid/extensions/ax'
4
+ require 'openid/store/filesystem'
5
+
6
+ require File.dirname(__FILE__) + '/open_id_authentication/association'
7
+ require File.dirname(__FILE__) + '/open_id_authentication/nonce'
8
+ require File.dirname(__FILE__) + '/open_id_authentication/db_store'
9
+ require File.dirname(__FILE__) + '/open_id_authentication/request'
10
+ require File.dirname(__FILE__) + '/open_id_authentication/timeout_fixes' if OpenID::VERSION == "2.0.4"
11
+
12
+ module OpenIdAuthentication
13
+ OPEN_ID_AUTHENTICATION_DIR = RAILS_ROOT + "/tmp/openids"
14
+
15
+ def self.store
16
+ @@store
17
+ end
18
+
19
+ def self.store=(*store_option)
20
+ store, *parameters = *([ store_option ].flatten)
21
+
22
+ @@store = case store
23
+ when :db
24
+ OpenIdAuthentication::DbStore.new
25
+ when :file
26
+ OpenID::Store::Filesystem.new(OPEN_ID_AUTHENTICATION_DIR)
27
+ else
28
+ store
29
+ end
30
+ end
31
+
32
+ self.store = :db
33
+
34
+ class InvalidOpenId < StandardError
35
+ end
36
+
37
+ class Result
38
+ ERROR_MESSAGES = {
39
+ :missing => "Sorry, the OpenID server couldn't be found",
40
+ :invalid => "Sorry, but this does not appear to be a valid OpenID",
41
+ :canceled => "OpenID verification was canceled",
42
+ :failed => "OpenID verification failed",
43
+ :setup_needed => "OpenID verification needs setup"
44
+ }
45
+
46
+ def self.[](code)
47
+ new(code)
48
+ end
49
+
50
+ def initialize(code)
51
+ @code = code
52
+ end
53
+
54
+ def status
55
+ @code
56
+ end
57
+
58
+ ERROR_MESSAGES.keys.each { |state| define_method("#{state}?") { @code == state } }
59
+
60
+ def successful?
61
+ @code == :successful
62
+ end
63
+
64
+ def unsuccessful?
65
+ ERROR_MESSAGES.keys.include?(@code)
66
+ end
67
+
68
+ def message
69
+ ERROR_MESSAGES[@code]
70
+ end
71
+ end
72
+
73
+ # normalizes an OpenID according to http://openid.net/specs/openid-authentication-2_0.html#normalization
74
+ def self.normalize_identifier(identifier)
75
+ # clean up whitespace
76
+ identifier = identifier.to_s.strip
77
+
78
+ # if an XRI has a prefix, strip it.
79
+ identifier.gsub!(/xri:\/\//i, '')
80
+
81
+ # dodge XRIs -- TODO: validate, don't just skip.
82
+ unless ['=', '@', '+', '$', '!', '('].include?(identifier.at(0))
83
+ # does it begin with http? if not, add it.
84
+ identifier = "http://#{identifier}" unless identifier =~ /^http/i
85
+
86
+ # strip any fragments
87
+ identifier.gsub!(/\#(.*)$/, '')
88
+
89
+ begin
90
+ uri = URI.parse(identifier)
91
+ uri.scheme = uri.scheme.downcase # URI should do this
92
+ identifier = uri.normalize.to_s
93
+ rescue URI::InvalidURIError
94
+ raise InvalidOpenId.new("#{identifier} is not an OpenID identifier")
95
+ end
96
+ end
97
+
98
+ return identifier
99
+ end
100
+
101
+ # deprecated for OpenID 2.0, where not all OpenIDs are URLs
102
+ def self.normalize_url(url)
103
+ ActiveSupport::Deprecation.warn "normalize_url has been deprecated, use normalize_identifier instead"
104
+ self.normalize_identifier(url)
105
+ end
106
+
107
+ protected
108
+ def normalize_url(url)
109
+ OpenIdAuthentication.normalize_url(url)
110
+ end
111
+
112
+ def normalize_identifier(url)
113
+ OpenIdAuthentication.normalize_identifier(url)
114
+ end
115
+
116
+ # The parameter name of "openid_identifier" is used rather than the Rails convention "open_id_identifier"
117
+ # because that's what the specification dictates in order to get browser auto-complete working across sites
118
+ def using_open_id?(identity_url = nil) #:doc:
119
+ identity_url ||= params[:openid_identifier] || params[:openid_url]
120
+ !identity_url.blank? || params[:open_id_complete]
121
+ end
122
+
123
+ def authenticate_with_open_id(identity_url = nil, options = {}, &block) #:doc:
124
+ identity_url ||= params[:openid_identifier] || params[:openid_url]
125
+
126
+ if params[:open_id_complete].nil?
127
+ begin_open_id_authentication(identity_url, options, &block)
128
+ else
129
+ complete_open_id_authentication(&block)
130
+ end
131
+ end
132
+
133
+ private
134
+ def begin_open_id_authentication(identity_url, options = {})
135
+ identity_url = normalize_identifier(identity_url)
136
+ return_to = options.delete(:return_to)
137
+ method = options.delete(:method)
138
+
139
+ options[:required] ||= [] # reduces validation later
140
+ options[:optional] ||= []
141
+
142
+ open_id_request = open_id_consumer.begin(identity_url)
143
+ add_simple_registration_fields(open_id_request, options)
144
+ add_ax_fields(open_id_request, options)
145
+ # puts 'OPENID url=' + open_id_redirect_url(open_id_request, return_to, method)
146
+ redirect_to(open_id_redirect_url(open_id_request, return_to, method, options))
147
+ rescue OpenIdAuthentication::InvalidOpenId => e
148
+ yield Result[:invalid], identity_url, nil
149
+ rescue OpenID::OpenIDError, Timeout::Error => e
150
+ logger.error("[OPENID] #{e}")
151
+ yield Result[:missing], identity_url, nil
152
+ end
153
+
154
+
155
+ def complete_open_id_authentication
156
+ params_with_path = params.reject { |key, value| request.path_parameters[key] }
157
+ params_with_path.delete(:format)
158
+ open_id_response = timeout_protection_from_identity_server { open_id_consumer.complete(params_with_path, requested_url) }
159
+ identity_url = normalize_identifier(open_id_response.display_identifier) if open_id_response.display_identifier
160
+
161
+ case open_id_response.status
162
+ when OpenID::Consumer::SUCCESS
163
+ profile_data = {}
164
+
165
+ # merge the SReg data and the AX data into a single hash of profile data
166
+ [ OpenID::SReg::Response, OpenID::AX::FetchResponse ].each do |data_response|
167
+ if data_response.from_success_response( open_id_response )
168
+ profile_data.merge! data_response.from_success_response( open_id_response ).data
169
+ end
170
+ end
171
+
172
+ yield Result[:successful], identity_url, profile_data
173
+ when OpenID::Consumer::CANCEL
174
+ yield Result[:canceled], identity_url, nil
175
+ when OpenID::Consumer::FAILURE
176
+ yield Result[:failed], identity_url, nil
177
+ when OpenID::Consumer::SETUP_NEEDED
178
+ yield Result[:setup_needed], open_id_response.setup_url, nil
179
+ end
180
+ end
181
+
182
+ def open_id_consumer
183
+ OpenID::Consumer.new(session, OpenIdAuthentication.store)
184
+ end
185
+
186
+ def add_simple_registration_fields(open_id_request, fields)
187
+ sreg_request = OpenID::SReg::Request.new
188
+
189
+ # filter out AX identifiers (URIs)
190
+ required_fields = fields[:required].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact
191
+ optional_fields = fields[:optional].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact
192
+
193
+ sreg_request.request_fields(required_fields, true) unless required_fields.blank?
194
+ sreg_request.request_fields(optional_fields, false) unless optional_fields.blank?
195
+ sreg_request.policy_url = fields[:policy_url] if fields[:policy_url]
196
+ open_id_request.add_extension(sreg_request)
197
+ end
198
+
199
+ def add_ax_fields( open_id_request, fields )
200
+ ax_request = OpenID::AX::FetchRequest.new
201
+
202
+ # look through the :required and :optional fields for URIs (AX identifiers)
203
+ fields[:required].each do |f|
204
+ next unless f =~ /^https?:\/\//
205
+ ax_request.add( OpenID::AX::AttrInfo.new( f, nil, true ) )
206
+ end
207
+
208
+ fields[:optional].each do |f|
209
+ next unless f =~ /^https?:\/\//
210
+ ax_request.add( OpenID::AX::AttrInfo.new( f, nil, false ) )
211
+ end
212
+
213
+ open_id_request.add_extension( ax_request )
214
+ end
215
+
216
+ def open_id_redirect_url(open_id_request, return_to = nil, method = nil, options={})
217
+ open_id_request.return_to_args['_method'] = (method || request.method).to_s
218
+ open_id_request.return_to_args['open_id_complete'] = '1'
219
+ open_id_request.redirect_url(options[:realm] || root_url, return_to || requested_url)
220
+ end
221
+
222
+ def requested_url
223
+ relative_url_root = self.class.respond_to?(:relative_url_root) ?
224
+ self.class.relative_url_root.to_s :
225
+ request.relative_url_root
226
+ "#{request.protocol}#{request.host_with_port}#{ActionController::Base.relative_url_root}#{request.path}"
227
+ end
228
+
229
+ def timeout_protection_from_identity_server
230
+ yield
231
+ rescue Timeout::Error
232
+ Class.new do
233
+ def status
234
+ OpenID::FAILURE
235
+ end
236
+
237
+ def msg
238
+ "Identity server timed out"
239
+ end
240
+ end.new
241
+ end
242
+ end
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class NormalizeTest < Test::Unit::TestCase
4
+ include OpenIdAuthentication
5
+
6
+ NORMALIZATIONS = {
7
+ "openid.aol.com/nextangler" => "http://openid.aol.com/nextangler",
8
+ "http://openid.aol.com/nextangler" => "http://openid.aol.com/nextangler",
9
+ "https://openid.aol.com/nextangler" => "https://openid.aol.com/nextangler",
10
+ "HTTP://OPENID.AOL.COM/NEXTANGLER" => "http://openid.aol.com/NEXTANGLER",
11
+ "HTTPS://OPENID.AOL.COM/NEXTANGLER" => "https://openid.aol.com/NEXTANGLER",
12
+ "loudthinking.com" => "http://loudthinking.com/",
13
+ "http://loudthinking.com" => "http://loudthinking.com/",
14
+ "http://loudthinking.com:80" => "http://loudthinking.com/",
15
+ "https://loudthinking.com:443" => "https://loudthinking.com/",
16
+ "http://loudthinking.com:8080" => "http://loudthinking.com:8080/",
17
+ "techno-weenie.net" => "http://techno-weenie.net/",
18
+ "http://techno-weenie.net" => "http://techno-weenie.net/",
19
+ "http://techno-weenie.net " => "http://techno-weenie.net/",
20
+ "=name" => "=name"
21
+ }
22
+
23
+ def test_normalizations
24
+ NORMALIZATIONS.each do |from, to|
25
+ assert_equal to, normalize_identifier(from)
26
+ end
27
+ end
28
+
29
+ def test_broken_open_id
30
+ assert_raises(InvalidOpenId) { normalize_identifier(nil) }
31
+ end
32
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class OpenIdAuthenticationTest < Test::Unit::TestCase
4
+ def setup
5
+ @controller = Class.new do
6
+ include OpenIdAuthentication
7
+ def params() {} end
8
+ end.new
9
+ end
10
+
11
+ def test_authentication_should_fail_when_the_identity_server_is_missing
12
+ open_id_consumer = mock()
13
+ open_id_consumer.expects(:begin).raises(OpenID::OpenIDError)
14
+ @controller.expects(:open_id_consumer).returns(open_id_consumer)
15
+ @controller.expects(:logger).returns(mock(:error => true))
16
+
17
+ @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url|
18
+ assert result.missing?
19
+ assert_equal "Sorry, the OpenID server couldn't be found", result.message
20
+ end
21
+ end
22
+
23
+ def test_authentication_should_be_invalid_when_the_identity_url_is_invalid
24
+ @controller.send(:authenticate_with_open_id, "!") do |result, identity_url|
25
+ assert result.invalid?, "Result expected to be invalid but was not"
26
+ assert_equal "Sorry, but this does not appear to be a valid OpenID", result.message
27
+ end
28
+ end
29
+
30
+ def test_authentication_should_fail_when_the_identity_server_times_out
31
+ open_id_consumer = mock()
32
+ open_id_consumer.expects(:begin).raises(Timeout::Error, "Identity Server took too long.")
33
+ @controller.expects(:open_id_consumer).returns(open_id_consumer)
34
+ @controller.expects(:logger).returns(mock(:error => true))
35
+
36
+ @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url|
37
+ assert result.missing?
38
+ assert_equal "Sorry, the OpenID server couldn't be found", result.message
39
+ end
40
+ end
41
+
42
+ def test_authentication_should_begin_when_the_identity_server_is_present
43
+ @controller.expects(:begin_open_id_authentication)
44
+ @controller.send(:authenticate_with_open_id, "http://someone.example.com")
45
+ end
46
+ end
@@ -0,0 +1,14 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class StatusTest < Test::Unit::TestCase
4
+ include OpenIdAuthentication
5
+
6
+ def test_state_conditional
7
+ assert Result[:missing].missing?
8
+ assert Result[:missing].unsuccessful?
9
+ assert !Result[:missing].successful?
10
+
11
+ assert Result[:successful].successful?
12
+ assert !Result[:successful].unsuccessful?
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+
4
+ gem 'activesupport'
5
+ require 'active_support'
6
+
7
+ gem 'actionpack'
8
+ require 'action_controller'
9
+
10
+ gem 'mocha'
11
+ require 'mocha'
12
+
13
+ gem 'ruby-openid'
14
+ require 'openid'
15
+
16
+ RAILS_ROOT = File.dirname(__FILE__) unless defined? RAILS_ROOT
17
+ require File.dirname(__FILE__) + "/../lib/open_id_authentication"
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: openid_auth
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Travis Reeder
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-02 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ruby-openid
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: Simple way to add openid to rails apps.
26
+ email: travis@appoxy.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - CHANGELOG
33
+ - README.markdown
34
+ files:
35
+ - lib/open_id_authentication.rb
36
+ - lib/open_id_authentication/association.rb
37
+ - lib/open_id_authentication/db_store.rb
38
+ - lib/open_id_authentication/nonce.rb
39
+ - lib/open_id_authentication/request.rb
40
+ - lib/open_id_authentication/timeout_fixes.rb
41
+ - CHANGELOG
42
+ - README.markdown
43
+ has_rdoc: true
44
+ homepage: http://github.com/appoxy/open_id_authentication
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --charset=UTF-8
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.3.5
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: Simple way to add openid to rails apps.
71
+ test_files:
72
+ - test/normalize_test.rb
73
+ - test/open_id_authentication_test.rb
74
+ - test/status_test.rb
75
+ - test/test_helper.rb