jacobat-authlogic-oid 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ .DS_Store
2
+ *.log
3
+ *.sqlite3
4
+ pkg/*
5
+ coverage/*
6
+ doc/*
7
+ benchmarks/*
8
+ authlogic-oid.gemspec
9
+ .source_index
@@ -0,0 +1,25 @@
1
+ == 1.0.4 released 2009-5-14
2
+
3
+ * Only authenticate with OpenID for models when a block is passed.
4
+ * Check for the existence of an openid_identifier field before including the model. Allowing this library to only be activated when present.
5
+ * Change required_field and optional_fields to openid_required_field and openid_optional_fields
6
+
7
+ == 1.0.3 released 2009-4-3
8
+
9
+ * Added find_by_openid_identifier config option for AuthlogicOpenid::Session.
10
+ * Set the openid_identifier by the one passed back by the provider in AuthlogicOpenid::ActsAsAuthentic.
11
+ * Added required_fields and optional_fields config options for AuthlogicOpenid::ActsAsAuthentic.
12
+ * Added map_openid_registration, attributes_to_save, and map_saved_attributes methods to customize how attributes are set for AuthlogicOpenid::ActsAsAuthentic.
13
+ * Make authenticating_with_openid? method a little more stringent to avoid trying to double authenticate. Ex: finding a session in the save block during a successful save.
14
+
15
+ == 1.0.2 released 2009-3-30
16
+
17
+ * Remove config block in initializer.
18
+
19
+ == 1.0.1 released 2009-3-30
20
+
21
+ * Change password validation option when included, and prepend the OpenID module.
22
+
23
+ == 1.0.0 released 2009-3-30
24
+
25
+ * Initial release
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Ben Johnson of Binary Logic (binarylogic.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,38 @@
1
+ CHANGELOG.rdoc
2
+ MIT-LICENSE
3
+ Manifest.txt
4
+ README.rdoc
5
+ Rakefile
6
+ init.rb
7
+ lib/authlogic_openid.rb
8
+ lib/authlogic_openid/acts_as_authentic.rb
9
+ lib/authlogic_openid/session.rb
10
+ lib/authlogic_openid/version.rb
11
+ test/acts_as_authentic_test.rb
12
+ test/fixtures/users.yml
13
+ test/libs/open_id_authentication/CHANGELOG
14
+ test/libs/open_id_authentication/README
15
+ test/libs/open_id_authentication/Rakefile
16
+ test/libs/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb
17
+ test/libs/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb
18
+ test/libs/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb
19
+ test/libs/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb
20
+ test/libs/open_id_authentication/init.rb
21
+ test/libs/open_id_authentication/lib/open_id_authentication.rb
22
+ test/libs/open_id_authentication/lib/open_id_authentication/association.rb
23
+ test/libs/open_id_authentication/lib/open_id_authentication/db_store.rb
24
+ test/libs/open_id_authentication/lib/open_id_authentication/mem_cache_store.rb
25
+ test/libs/open_id_authentication/lib/open_id_authentication/nonce.rb
26
+ test/libs/open_id_authentication/lib/open_id_authentication/request.rb
27
+ test/libs/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb
28
+ test/libs/open_id_authentication/tasks/open_id_authentication_tasks.rake
29
+ test/libs/open_id_authentication/test/mem_cache_store_test.rb
30
+ test/libs/open_id_authentication/test/normalize_test.rb
31
+ test/libs/open_id_authentication/test/open_id_authentication_test.rb
32
+ test/libs/open_id_authentication/test/status_test.rb
33
+ test/libs/open_id_authentication/test/test_helper.rb
34
+ test/libs/rails_trickery.rb
35
+ test/libs/user.rb
36
+ test/libs/user_session.rb
37
+ test/session_test.rb
38
+ test/test_helper.rb
@@ -0,0 +1,115 @@
1
+ = Authlogic OpenID
2
+
3
+ Authlogic OpenID is an extension of the Authlogic library to add OpenID support. Authlogic v2.0 introduced an enhanced API that makes "plugging in" alternate authentication methods as easy as installing a gem.
4
+
5
+ == Helpful links
6
+
7
+ * <b>Documentation:</b> http://authlogic-oid.rubyforge.org
8
+ * <b>Authlogic:</b> http://github.com/binarylogic/authlogic
9
+ * <b>Live example:</b> http://authlogicexample.binarylogic.com
10
+
11
+ == Install and use
12
+
13
+ === 1. Make some simple changes to your database:
14
+
15
+ class AddUsersOpenidField < ActiveRecord::Migration
16
+ def self.up
17
+ add_column :users, :openid_identifier, :string
18
+ add_index :users, :openid_identifier
19
+
20
+ change_column :users, :login, :string, :default => nil, :null => true
21
+ change_column :users, :crypted_password, :string, :default => nil, :null => true
22
+ change_column :users, :password_salt, :string, :default => nil, :null => true
23
+ end
24
+
25
+ def self.down
26
+ remove_column :users, :openid_identifier
27
+
28
+ [:login, :crypted_password, :password_salt].each do |field|
29
+ User.all(:conditions => "#{field} is NULL").each { |user| user.update_attribute(field, "") if user.send(field).nil? }
30
+ change_column :users, field, :string, :default => "", :null => false
31
+ end
32
+ end
33
+ end
34
+
35
+ === 2. Install the openid_authentication plugin
36
+
37
+ $ script/plugin install git://github.com/rails/open_id_authentication.git
38
+
39
+ And make sure all required gems are installed:
40
+
41
+ rake gems:install
42
+
43
+ For more information on how to configure the plugin, checkout it's README: http://github.com/rails/open_id_authentication/tree/master
44
+
45
+ === 3. Install the Authlogic Openid gem
46
+
47
+ $ sudo gem install authlogic-oid
48
+
49
+ Now add the gem dependency in your config:
50
+
51
+ config.gem "authlogic-oid", :lib => "authlogic_openid"
52
+
53
+ Or for older version of rails, install it as a plugin:
54
+
55
+ $ script/plugin install git://github.com/binarylogic/authlogic_openid.git
56
+
57
+ === 4. Make sure you save your objects properly
58
+
59
+ You only need to save your objects this way if you want the user to authenticate with their OpenID provider.
60
+
61
+ That being said, you probably want to do this in your controllers. You should do this for BOTH your User objects and UserSession objects (assuming you are authenticating users). It should look something like this:
62
+
63
+ @user_session.save do |result|
64
+ if result
65
+ flash[:notice] = "Login successful!"
66
+ redirect_back_or_default account_url
67
+ else
68
+ render :action => :new
69
+ end
70
+ end
71
+
72
+ You should save your @user objects this way as well, because you also want the user to verify that they own the OpenID identifier that they supplied.
73
+
74
+ Notice we are saving with a block. Why? Because we need to redirect the user to their OpenID provider so that they can authenticate. When we do this, we don't want to execute that block of code, because if we do, we will get a DoubleRender error. This lets us skip that entire block and send the user along their way without any problems.
75
+
76
+ === 5. Check your validations / Auto registration
77
+
78
+ In case you want to enable automatic user registrations with OpenID, enable this in your session:
79
+
80
+ class UserSession < Authlogic::Session::Base
81
+ auto_register
82
+ end
83
+
84
+ In this case you migth also want to change the user object to no longer require a login:
85
+
86
+ class User < ActiveRecord::Base
87
+ acts_as_authentic do |c|
88
+ c.merge_validates_length_of_login_field_options(:unless => :using_openid?)
89
+ c.merge_validates_format_of_login_field_options(:unless => :using_openid?)
90
+ end
91
+ end
92
+
93
+ === 6. Done!
94
+
95
+ That's it! The rest is taken care of for you.
96
+
97
+ == Redirecting from the models?
98
+
99
+ If you are interested, I explain myself below. Regardless, if you don't feel comfortable with the organization of the logic,you can easily do this using the traditional method. As you saw in the setup instructions, this library leverages the open_id_authentication rails plugin. After the user has been authenticated just do this:
100
+
101
+ UserSession.create(@user)
102
+
103
+ It's that simple. For more information there is a great OpenID tutorial at: http://railscasts.com/episodes/68-openid-authentication
104
+
105
+ Now, here are my thoughts on the subject:
106
+
107
+ You are probably thinking: "Ben, you can't handle controller responsibilities in models". I agree with you on that comment, but my personal opinion is that these are not controller responsibilities. The fact that OpenID authentication requires a redirect should not effect the location of the logic / code. It's all part of the authentication process, which is the entire purpose of this library. This library is not one big module of code, its a collection of modules that all deal with OpenID authentication. These modules get included wherever it makes sense. That's the whole idea behind modules. To group common logic.
108
+
109
+ Let's take a step back and look at the traditional method of OpenID authentication in rails. What if you wanted to authenticate with OpenID in multiple controllers in your application (Ex: registration and loggin in)? You would probably pull out the common code into a module and include it in the respective controllers. Even better, you might create a class that elegantly handles this process and then place it in your lib directory. Then, if you really wanted to be slick, you might take it another step further and have your models trigger this class during certain actions. Then what do we have? This exact library, that's exactly what this is.
110
+
111
+ The last thing I will leave you with, to get you thinking, is... where do sweepers lie in the MVC pattern? Without this, things like caching would be extremely difficult. There is a big difference between misplacing code / logic, and organizing logic into a separate module and hooking it in using the API provided by your models. Especially when the logic needs to be triggered by actions invoked on models.
112
+
113
+ Regardless, if I still haven't convinced you, I hope this library is of some benefit to you. At the very least an example of how to extend Authlogic.
114
+
115
+ Copyright (c) 2009 Ben Johnson of [Binary Logic](http://www.binarylogic.com), released under the MIT license
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) << "/lib/authlogic_openid/version"
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |gemspec|
6
+ gemspec.name = "jacobat-authlogic-oid"
7
+ gemspec.summary = "Extension of the Authlogic library to add OpenID support."
8
+ gemspec.description = "Extension of the Authlogic library to add OpenID support."
9
+ gemspec.email = "jacob@incremental.dk"
10
+ gemspec.homepage = "http://github.com/jacobat/authlogic_openid"
11
+ gemspec.authors = ["Ben Johnson of Binary Logic", "Michael Reinsch"]
12
+ end
13
+ rescue LoadError
14
+ puts "Jeweler not available. Install it with: gem install jeweler"
15
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.4
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/rails/init.rb"
@@ -0,0 +1,6 @@
1
+ require "authlogic_openid/version"
2
+ require "authlogic_openid/acts_as_authentic"
3
+ require "authlogic_openid/session"
4
+
5
+ ActiveRecord::Base.send(:include, AuthlogicOpenid::ActsAsAuthentic)
6
+ Authlogic::Session::Base.send(:include, AuthlogicOpenid::Session)
@@ -0,0 +1,170 @@
1
+ # This module is responsible for adding OpenID functionality to Authlogic. Checkout the README for more info and please
2
+ # see the sub modules for detailed documentation.
3
+ module AuthlogicOpenid
4
+ # This module is responsible for adding in the OpenID functionality to your models. It hooks itself into the
5
+ # acts_as_authentic method provided by Authlogic.
6
+ module ActsAsAuthentic
7
+ # Adds in the neccesary modules for acts_as_authentic to include and also disabled password validation if
8
+ # OpenID is being used.
9
+ def self.included(klass)
10
+ klass.class_eval do
11
+ extend Config
12
+ add_acts_as_authentic_module(Methods, :prepend)
13
+ end
14
+ end
15
+
16
+ module Config
17
+ # Some OpenID providers support a lightweight profile exchange protocol, for those that do, you can require
18
+ # certain fields. This is convenient for new registrations, as it will basically fill out the fields in the
19
+ # form for them, so they don't have to re-type information already stored with their OpenID account.
20
+ #
21
+ # For more info and what fields you can use see: http://openid.net/specs/openid-simple-registration-extension-1_0.html
22
+ #
23
+ # * <tt>Default:</tt> []
24
+ # * <tt>Accepts:</tt> Array of symbols
25
+ def openid_required_fields(value = nil)
26
+ rw_config(:openid_required_fields, value, [])
27
+ end
28
+ alias_method :openid_required_fields=, :openid_required_fields
29
+
30
+ # Same as required_fields, but optional instead.
31
+ #
32
+ # * <tt>Default:</tt> []
33
+ # * <tt>Accepts:</tt> Array of symbols
34
+ def openid_optional_fields(value = nil)
35
+ rw_config(:openid_optional_fields, value, [])
36
+ end
37
+ alias_method :openid_optional_fields=, :openid_optional_fields
38
+ end
39
+
40
+ module Methods
41
+ # Set up some simple validations
42
+ def self.included(klass)
43
+ return if !klass.column_names.include?("openid_identifier")
44
+
45
+ klass.class_eval do
46
+ validates_uniqueness_of :openid_identifier, :scope => validations_scope, :if => :using_openid?
47
+ validate :validate_openid
48
+ validates_length_of_password_field_options validates_length_of_password_field_options.merge(:if => :validate_password_with_openid?)
49
+ validates_confirmation_of_password_field_options validates_confirmation_of_password_field_options.merge(:if => :validate_password_with_openid?)
50
+ validates_length_of_password_confirmation_field_options validates_length_of_password_confirmation_field_options.merge(:if => :validate_password_with_openid?)
51
+ end
52
+ end
53
+
54
+ # Set the openid_identifier field and also resets the persistence_token if this value changes.
55
+ def openid_identifier=(value)
56
+ write_attribute(:openid_identifier, value.blank? ? nil : OpenID.normalize_url(value))
57
+ reset_persistence_token if openid_identifier_changed?
58
+ rescue OpenID::DiscoveryFailure => e
59
+ @openid_error = e.message
60
+ end
61
+
62
+ # This is where all of the magic happens. This is where we hook in and add all of the OpenID sweetness.
63
+ #
64
+ # I had to take this approach because when authenticating with OpenID nonces and what not are stored in database
65
+ # tables. That being said, the whole save process for ActiveRecord is wrapped in a transaction. Trying to authenticate
66
+ # with OpenID in a transaction is not good because that transaction be get rolled back, thus reversing all of the OpenID
67
+ # inserts and making OpenID authentication fail every time. So We need to step outside of the transaction and do our OpenID
68
+ # madness.
69
+ #
70
+ # Another advantage of taking this approach is that we can set fields from their OpenID profile before we save the record,
71
+ # if their OpenID provider supports it.
72
+ def save(perform_validation = true, &block)
73
+ return false if perform_validation && block_given? && authenticate_with_openid? && !authenticate_with_openid
74
+ result = super
75
+ yield(result) if block_given?
76
+ result
77
+ end
78
+
79
+ private
80
+ def authenticate_with_openid
81
+ @openid_error = nil
82
+
83
+ if !openid_complete?
84
+ session_class.controller.session[:openid_attributes] = attributes_to_save
85
+ else
86
+ map_saved_attributes(session_class.controller.session[:openid_attributes])
87
+ session_class.controller.session[:openid_attributes] = nil
88
+ end
89
+
90
+ options = {
91
+ :required => self.class.openid_required_fields,
92
+ :optional => self.class.openid_optional_fields,
93
+ :return_to => session_class.controller.url_for(:for_model => "1"),
94
+ :method => :post }
95
+
96
+ session_class.controller.send(:authenticate_with_open_id, openid_identifier, options) do |result, openid_identifier, registration|
97
+ if result.unsuccessful?
98
+ @openid_error = result.message
99
+ else
100
+ self.openid_identifier = openid_identifier
101
+ map_openid_registration(registration)
102
+ end
103
+
104
+ return true
105
+ end
106
+
107
+ return false
108
+ end
109
+
110
+ # Override this method to map the OpenID registration fields with fields in your model. See the required_fields and
111
+ # optional_fields configuration options to enable this feature.
112
+ #
113
+ # Basically you will get a hash of values passed as a single argument. Then just map them as you see fit. Check out
114
+ # the source of this method for an example.
115
+ def map_openid_registration(registration) # :doc:
116
+ self.name ||= registration[:fullname] if respond_to?(:name) && !registration[:fullname].blank?
117
+ self.first_name ||= registration[:fullname].split(" ").first if respond_to?(:first_name) && !registration[:fullname].blank?
118
+ self.last_name ||= registration[:fullname].split(" ").last if respond_to?(:last_name) && !registration[:last_name].blank?
119
+ end
120
+
121
+ # This method works in conjunction with map_saved_attributes.
122
+ #
123
+ # Let's say a user fills out a registration form, provides an OpenID and submits the form. They are then redirected to their
124
+ # OpenID provider. All is good and they are redirected back. All of those fields they spent time filling out are forgetten
125
+ # and they have to retype them all. To avoid this, AuthlogicOpenid saves all of these attributes in the session and then
126
+ # attempts to restore them. See the source for what attributes it saves. If you need to block more attributes, or save
127
+ # more just override this method and do whatever you want.
128
+ def attributes_to_save # :doc:
129
+ attrs_to_save = attributes.clone.delete_if do |k, v|
130
+ [:id, :password, crypted_password_field, password_salt_field, :persistence_token, :perishable_token, :single_access_token, :login_count,
131
+ :failed_login_count, :last_request_at, :current_login_at, :last_login_at, :current_login_ip, :last_login_ip, :created_at,
132
+ :updated_at, :lock_version].include?(k.to_sym)
133
+ end
134
+ attrs_to_save.merge!(:password => password, :password_confirmation => password_confirmation)
135
+ end
136
+
137
+ # This method works in conjunction with attributes_to_save. See that method for a description of the why these methods exist.
138
+ #
139
+ # If the default behavior of this method is not sufficient for you because you have attr_protected or attr_accessible then
140
+ # override this method and set them individually. Maybe something like this would be good:
141
+ #
142
+ # attrs.each do |key, value|
143
+ # send("#{key}=", value)
144
+ # end
145
+ def map_saved_attributes(attrs) # :doc:
146
+ self.attributes = attrs
147
+ end
148
+
149
+ def validate_openid
150
+ errors.add(:openid_identifier, "had the following error: #{@openid_error}") if @openid_error
151
+ end
152
+
153
+ def using_openid?
154
+ respond_to?(:openid_identifier) && !openid_identifier.blank?
155
+ end
156
+
157
+ def openid_complete?
158
+ session_class.controller.using_open_id? && session_class.controller.params[:for_model]
159
+ end
160
+
161
+ def authenticate_with_openid?
162
+ session_class.activated? && ((using_openid? && openid_identifier_changed?) || openid_complete?)
163
+ end
164
+
165
+ def validate_password_with_openid?
166
+ !using_openid? && require_password?
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,133 @@
1
+ module AuthlogicOpenid
2
+ # This module is responsible for adding all of the OpenID goodness to the Authlogic::Session::Base class.
3
+ module Session
4
+ # Add a simple openid_identifier attribute and some validations for the field.
5
+ def self.included(klass)
6
+ klass.class_eval do
7
+ extend Config
8
+ include Methods
9
+ end
10
+ end
11
+
12
+ module Config
13
+ # What method should we call to find a record by the openid_identifier?
14
+ # This is useful if you want to store multiple openid_identifiers for a single record.
15
+ # You could do something like:
16
+ #
17
+ # class User < ActiveRecord::Base
18
+ # def self.find_by_openid_identifier(identifier)
19
+ # user.first(:conditions => {:openid_identifiers => {:identifier => identifier}})
20
+ # end
21
+ # end
22
+ #
23
+ # Obviously the above depends on what you are calling your assocition, etc. But you get the point.
24
+ #
25
+ # * <tt>Default:</tt> :find_by_openid_identifier
26
+ # * <tt>Accepts:</tt> Symbol
27
+ def find_by_openid_identifier_method(value = nil)
28
+ rw_config(:find_by_openid_identifier_method, value, :find_by_openid_identifier)
29
+ end
30
+ alias_method :find_by_openid_identifier_method=, :find_by_openid_identifier_method
31
+
32
+ # Add this in your Session object to Auto Register a new user using openid via sreg
33
+ def auto_register(value=true)
34
+ auto_register_value(value)
35
+ end
36
+
37
+ def auto_register_value(value=nil)
38
+ rw_config(:auto_register,value,false)
39
+ end
40
+
41
+ alias_method :auto_register=,:auto_register
42
+ end
43
+
44
+ module Methods
45
+ def self.included(klass)
46
+ klass.class_eval do
47
+ attr_reader :openid_identifier
48
+ validate :validate_openid_error
49
+ validate :validate_by_openid, :if => :authenticating_with_openid?
50
+ end
51
+ end
52
+
53
+ # Hooks into credentials so that you can pass an :openid_identifier key.
54
+ def credentials=(value)
55
+ super
56
+ values = value.is_a?(Array) ? value : [value]
57
+ hash = values.first.is_a?(Hash) ? values.first.with_indifferent_access : nil
58
+ self.openid_identifier = hash[:openid_identifier] if !hash.nil? && hash.key?(:openid_identifier)
59
+ end
60
+
61
+ def openid_identifier=(value)
62
+ @openid_identifier = value.blank? ? nil : OpenID.normalize_url(value)
63
+ @openid_error = nil
64
+ rescue OpenID::DiscoveryFailure => e
65
+ @openid_identifier = nil
66
+ @openid_error = e.message
67
+ end
68
+
69
+ # Cleaers out the block if we are authenticating with OpenID, so that we can redirect without a DoubleRender
70
+ # error.
71
+ def save(&block)
72
+ block = nil if !openid_identifier.blank? && controller.request.env[Rack::OpenID::RESPONSE].blank?
73
+ super(&block)
74
+ end
75
+
76
+ private
77
+ def authenticating_with_openid?
78
+ attempted_record.nil? && errors.empty? && (!openid_identifier.blank? || (controller.using_open_id? && controller.params[:for_session]))
79
+ end
80
+
81
+ def find_by_openid_identifier_method
82
+ self.class.find_by_openid_identifier_method
83
+ end
84
+
85
+ def find_by_openid_identifier_method
86
+ self.class.find_by_openid_identifier_method
87
+ end
88
+
89
+ def auto_register?
90
+ self.class.auto_register_value
91
+ end
92
+
93
+ def validate_by_openid
94
+ self.remember_me = controller.params[:remember_me] == "true" if controller.params.key?(:remember_me)
95
+
96
+ options = {
97
+ :required => klass.openid_required_fields,
98
+ :optional => klass.openid_optional_fields,
99
+ :return_to => controller.url_for(:for_session => "1", :remember_me => remember_me?),
100
+ :method => :post}
101
+
102
+ controller.send(:authenticate_with_open_id, openid_identifier, options) do |result, openid_identifier, registration|
103
+ if result.unsuccessful?
104
+ errors.add_to_base(result.message)
105
+ return
106
+ end
107
+
108
+ self.attempted_record = klass.send(find_by_openid_identifier_method, openid_identifier)
109
+
110
+ if !attempted_record
111
+ if auto_register?
112
+ auto_reg_record = klass.new
113
+ auto_reg_record.openid_identifier = openid_identifier
114
+ auto_reg_record.send(:map_openid_registration, registration)
115
+
116
+ if !auto_reg_record.save
117
+ auto_reg_record.errors.each {|attr, msg| errors.add(attr, msg) }
118
+ else
119
+ self.attempted_record = auto_reg_record
120
+ end
121
+ else
122
+ errors.add(:openid_identifier, "did not match any users in our database, have you set up your account to use OpenID?")
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ def validate_openid_error
129
+ errors.add(:openid_identifier, @openid_error) if @openid_error
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,51 @@
1
+ module AuthlogicOpenid
2
+ # A class for describing the current version of a library. The version
3
+ # consists of three parts: the +major+ number, the +minor+ number, and the
4
+ # +tiny+ (or +patch+) number.
5
+ class Version
6
+ include Comparable
7
+
8
+ # A convenience method for instantiating a new Version instance with the
9
+ # given +major+, +minor+, and +tiny+ components.
10
+ def self.[](major, minor, tiny)
11
+ new(major, minor, tiny)
12
+ end
13
+
14
+ attr_reader :major, :minor, :tiny
15
+
16
+ # Create a new Version object with the given components.
17
+ def initialize(major, minor, tiny)
18
+ @major, @minor, @tiny = major, minor, tiny
19
+ end
20
+
21
+ # Compare this version to the given +version+ object.
22
+ def <=>(version)
23
+ to_i <=> version.to_i
24
+ end
25
+
26
+ # Converts this version object to a string, where each of the three
27
+ # version components are joined by the '.' character. E.g., 2.0.0.
28
+ def to_s
29
+ @to_s ||= [@major, @minor, @tiny].join(".")
30
+ end
31
+
32
+ # Converts this version to a canonical integer that may be compared
33
+ # against other version objects.
34
+ def to_i
35
+ @to_i ||= @major * 1_000_000 + @minor * 1_000 + @tiny
36
+ end
37
+
38
+ def to_a
39
+ [@major, @minor, @tiny]
40
+ end
41
+
42
+ MAJOR = 1
43
+ MINOR = 0
44
+ TINY = 4
45
+
46
+ # The current version as a Version instance
47
+ CURRENT = new(MAJOR, MINOR, TINY)
48
+ # The current version as a String
49
+ STRING = CURRENT.to_s
50
+ end
51
+ end
@@ -0,0 +1 @@
1
+ require "authlogic_openid"
@@ -0,0 +1,105 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class ActsAsAuthenticTest < ActiveSupport::TestCase
4
+ def test_included
5
+ assert User.send(:acts_as_authentic_modules).include?(AuthlogicOpenid::ActsAsAuthentic::Methods)
6
+ assert_equal :validate_password_with_openid?, User.validates_length_of_password_field_options[:if]
7
+ assert_equal :validate_password_with_openid?, User.validates_confirmation_of_password_field_options[:if]
8
+ assert_equal :validate_password_with_openid?, User.validates_length_of_password_confirmation_field_options[:if]
9
+ end
10
+
11
+ def test_password_not_required_on_create
12
+ user = User.new
13
+ user.login = "sweet"
14
+ user.email = "a@a.com"
15
+ user.openid_identifier = "https://me.yahoo.com/a/9W0FJjRj0o981TMSs0vqVxPdmMUVOQ--"
16
+ assert !user.save {} # because we are redirecting, the user was NOT saved
17
+ assert_redirecting_to_yahoo "for_model"
18
+ end
19
+
20
+ def test_password_required_on_create
21
+ user = User.new
22
+ user.login = "sweet"
23
+ user.email = "a@a.com"
24
+ assert !user.save
25
+ assert user.errors.on(:password)
26
+ assert user.errors.on(:password_confirmation)
27
+ end
28
+
29
+ def test_password_not_required_on_update
30
+ ben = users(:ben)
31
+ assert_nil ben.crypted_password
32
+ assert ben.save
33
+ end
34
+
35
+ def test_password_required_on_update
36
+ ben = users(:ben)
37
+ ben.openid_identifier = nil
38
+ assert_nil ben.crypted_password
39
+ assert !ben.save
40
+ assert ben.errors.on(:password)
41
+ assert ben.errors.on(:password_confirmation)
42
+ end
43
+
44
+ def test_validates_uniqueness_of_openid_identifier
45
+ u = User.new(:openid_identifier => "bens_identifier")
46
+ assert !u.valid?
47
+ assert u.errors.on(:openid_identifier)
48
+ end
49
+
50
+ def test_setting_openid_identifier_changed_persistence_token
51
+ ben = users(:ben)
52
+ old_persistence_token = ben.persistence_token
53
+ ben.openid_identifier = "http://new"
54
+ assert_not_equal old_persistence_token, ben.persistence_token
55
+ end
56
+
57
+ def test_invalid_openid_identifier
58
+ u = User.new(:openid_identifier => "%")
59
+ assert !u.valid?
60
+ assert u.errors.on(:openid_identifier)
61
+ end
62
+
63
+ def test_blank_openid_identifer_gets_set_to_nil
64
+ u = User.new(:openid_identifier => "")
65
+ assert_nil u.openid_identifier
66
+ end
67
+
68
+ def test_updating_with_openid
69
+ ben = users(:ben)
70
+ ben.openid_identifier = "https://me.yahoo.com/a/9W0FJjRj0o981TMSs0vqVxPdmMUVOQ--"
71
+ assert !ben.save {} # because we are redirecting
72
+ assert_redirecting_to_yahoo "for_model"
73
+ end
74
+
75
+ def test_updating_without_openid
76
+ ben = users(:ben)
77
+ ben.openid_identifier = nil
78
+ ben.password = "test"
79
+ ben.password_confirmation = "test"
80
+ assert ben.save
81
+ assert_not_redirecting
82
+ end
83
+
84
+ def test_updating_without_validation
85
+ ben = users(:ben)
86
+ ben.openid_identifier = "https://me.yahoo.com/a/9W0FJjRj0o981TMSs0vqVxPdmMUVOQ--"
87
+ assert ben.save(false)
88
+ assert_not_redirecting
89
+ end
90
+
91
+ def test_updating_without_a_block
92
+ ben = users(:ben)
93
+ ben.openid_identifier = "https://me.yahoo.com/a/9W0FJjRj0o981TMSs0vqVxPdmMUVOQ--"
94
+ assert ben.save
95
+ ben.reload
96
+ assert_equal "https://me.yahoo.com/a/9W0FJjRj0o981TMSs0vqVxPdmMUVOQ--", ben.openid_identifier
97
+ end
98
+
99
+ def test_updating_while_not_activated
100
+ UserSession.controller = nil
101
+ ben = users(:ben)
102
+ ben.openid_identifier = "https://me.yahoo.com/a/9W0FJjRj0o981TMSs0vqVxPdmMUVOQ--"
103
+ assert ben.save {}
104
+ end
105
+ end
@@ -0,0 +1,9 @@
1
+ ben:
2
+ login: bjohnson
3
+ persistence_token: 6cde0674657a8a313ce952df979de2830309aa4c11ca65805dd00bfdc65dbcc2f5e36718660a1d2e68c1a08c276d996763985d2f06fd3d076eb7bc4d97b1e317
4
+ single_access_token: <%= Authlogic::Random.friendly_token %>
5
+ perishable_token: <%= Authlogic::Random.friendly_token %>
6
+ openid_identifier: bens_identifier
7
+ email: bjohnson@binarylogic.com
8
+ first_name: Ben
9
+ last_name: Johnson
@@ -0,0 +1,3 @@
1
+ class User < ActiveRecord::Base
2
+ acts_as_authentic
3
+ end
@@ -0,0 +1,2 @@
1
+ class UserSession < Authlogic::Session::Base
2
+ end
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class SessionTest < ActiveSupport::TestCase
4
+ def test_openid_identifier
5
+ session = UserSession.new
6
+ assert session.respond_to?(:openid_identifier)
7
+ session.openid_identifier = "http://test"
8
+ assert_equal "http://test/", session.openid_identifier
9
+ end
10
+
11
+ def test_validate_openid_error
12
+ session = UserSession.new
13
+ session.openid_identifier = "yes"
14
+ session.openid_identifier = "%"
15
+ assert_nil session.openid_identifier
16
+ assert !session.save
17
+ assert session.errors.on(:openid_identifier)
18
+ end
19
+
20
+ def test_validate_by_nil_openid_identifier
21
+ session = UserSession.new
22
+ assert !session.save
23
+ assert_not_redirecting
24
+ end
25
+
26
+ def test_validate_by_correct_openid_identifier
27
+ session = UserSession.new
28
+ session.openid_identifier = "https://me.yahoo.com/a/9W0FJjRj0o981TMSs0vqVxPdmMUVOQ--"
29
+ assert !session.save
30
+ assert_redirecting_to_yahoo "for_session"
31
+ end
32
+ end
@@ -0,0 +1,117 @@
1
+ require "test/unit"
2
+ require "rubygems"
3
+ require "ruby-debug"
4
+ require "active_record"
5
+ require "action_controller"
6
+ require "action_controller/test_process"
7
+
8
+ ActiveRecord::Schema.verbose = false
9
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
10
+ ActiveRecord::Base.configurations = true
11
+ ActiveRecord::Schema.define(:version => 1) do
12
+ create_table :open_id_authentication_associations, :force => true do |t|
13
+ t.integer :issued, :lifetime
14
+ t.string :handle, :assoc_type
15
+ t.binary :server_url, :secret
16
+ end
17
+
18
+ create_table :open_id_authentication_nonces, :force => true do |t|
19
+ t.integer :timestamp, :null => false
20
+ t.string :server_url, :null => true
21
+ t.string :salt, :null => false
22
+ end
23
+
24
+ create_table :users do |t|
25
+ t.datetime :created_at
26
+ t.datetime :updated_at
27
+ t.integer :lock_version, :default => 0
28
+ t.string :login
29
+ t.string :crypted_password
30
+ t.string :password_salt
31
+ t.string :persistence_token
32
+ t.string :single_access_token
33
+ t.string :perishable_token
34
+ t.string :openid_identifier
35
+ t.string :email
36
+ t.string :first_name
37
+ t.string :last_name
38
+ t.integer :login_count, :default => 0, :null => false
39
+ t.integer :failed_login_count, :default => 0, :null => false
40
+ t.datetime :last_request_at
41
+ t.datetime :current_login_at
42
+ t.datetime :last_login_at
43
+ t.string :current_login_ip
44
+ t.string :last_login_ip
45
+ end
46
+ end
47
+
48
+ require "active_record/fixtures"
49
+ require "openid"
50
+
51
+ module Rails
52
+ module VERSION
53
+ STRING = "2.3.5"
54
+ end
55
+ end
56
+
57
+ require File.dirname(__FILE__) + "/../../authlogic/lib/authlogic"
58
+ require File.dirname(__FILE__) + "/../../authlogic/lib/authlogic/test_case"
59
+ require File.dirname(__FILE__) + '/../../open_id_authentication/lib/open_id_authentication'
60
+
61
+ # this is partly from open_id_authentication/init.rb
62
+ ActionController::Base.send :include, OpenIdAuthentication
63
+
64
+ require File.dirname(__FILE__) + '/../lib/authlogic_openid' unless defined?(AuthlogicOpenid)
65
+ require File.dirname(__FILE__) + '/libs/user'
66
+ require File.dirname(__FILE__) + '/libs/user_session'
67
+
68
+ ActionController::Routing::Routes.draw do |map|
69
+ map.connect ':controller/:action/:id', :controller => 'session'
70
+ end
71
+
72
+ class SessionController < ActionController::Base
73
+ def default_template(action_name = self.action_name)
74
+ nil
75
+ end
76
+ end
77
+
78
+ class ActiveSupport::TestCase
79
+ include ActiveRecord::TestFixtures
80
+ self.fixture_path = File.dirname(__FILE__) + "/fixtures"
81
+ self.use_transactional_fixtures = false
82
+ self.use_instantiated_fixtures = false
83
+ self.pre_loaded_fixtures = false
84
+ fixtures :all
85
+ setup :activate_authlogic
86
+
87
+ private
88
+
89
+ def controller
90
+ @controller ||= create_controller
91
+ end
92
+
93
+ def create_controller
94
+ @request = ActionController::TestRequest.new
95
+ @request.path_parameters = {:action => "index", :controller => "session"}
96
+ @response = ActionController::TestResponse.new
97
+
98
+ c = SessionController.new
99
+ c.params = {}
100
+ c.request = @request
101
+ c.response = @response
102
+ c.send(:reset_session)
103
+ c.send(:initialize_current_url)
104
+
105
+ Authlogic::ControllerAdapters::RailsAdapter.new(c)
106
+ end
107
+
108
+ def assert_redirecting_to_yahoo(for_param)
109
+ [ /^OpenID identifier="https:\/\/me.yahoo.com\/a\/9W0FJjRj0o981TMSs0vqVxPdmMUVOQ--"/,
110
+ /return_to=\"http:\/\/test.host\/\?#{for_param}=1"/,
111
+ /method="post"/ ].each {|p| assert_match p, @response.headers["WWW-Authenticate"]}
112
+ end
113
+
114
+ def assert_not_redirecting
115
+ assert ! @response.headers["WWW-Authenticate"]
116
+ end
117
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jacobat-authlogic-oid
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 4
9
+ version: 1.0.4
10
+ platform: ruby
11
+ authors:
12
+ - Ben Johnson of Binary Logic
13
+ - Michael Reinsch
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-03-26 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Extension of the Authlogic library to add OpenID support.
23
+ email: jacob@incremental.dk
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README.rdoc
30
+ files:
31
+ - .gitignore
32
+ - CHANGELOG.rdoc
33
+ - MIT-LICENSE
34
+ - Manifest.txt
35
+ - README.rdoc
36
+ - Rakefile
37
+ - VERSION
38
+ - init.rb
39
+ - lib/authlogic_openid.rb
40
+ - lib/authlogic_openid/acts_as_authentic.rb
41
+ - lib/authlogic_openid/session.rb
42
+ - lib/authlogic_openid/version.rb
43
+ - rails/init.rb
44
+ - test/acts_as_authentic_test.rb
45
+ - test/fixtures/users.yml
46
+ - test/libs/user.rb
47
+ - test/libs/user_session.rb
48
+ - test/session_test.rb
49
+ - test/test_helper.rb
50
+ has_rdoc: true
51
+ homepage: http://github.com/jacobat/authlogic_openid
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options:
56
+ - --charset=UTF-8
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ requirements: []
74
+
75
+ rubyforge_project:
76
+ rubygems_version: 1.3.6
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Extension of the Authlogic library to add OpenID support.
80
+ test_files:
81
+ - test/acts_as_authentic_test.rb
82
+ - test/libs/user.rb
83
+ - test/libs/user_session.rb
84
+ - test/session_test.rb
85
+ - test/test_helper.rb