sidonath-authlogic_rpx 1.0.4b

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,126 @@
1
+ # This module is responsible for adding RPX functionality to Authlogic. Checkout the README for more info and please
2
+ # see the sub modules for detailed documentation.
3
+ module AuthlogicRpx
4
+ # This module is responsible for adding in the RPX 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
+ # RPX 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
+
18
+ # map_id is used to enable RPX identity mapping
19
+ # experimental - a feature of RPX paid accounts and not properly developed/tested yet
20
+ #
21
+ # * <tt>Default:</tt> false
22
+ # * <tt>Accepts:</tt> boolean
23
+ def map_id(value = false)
24
+ rw_config(:map_id, value, false)
25
+ end
26
+ alias_method :map_id=, :map_id
27
+
28
+ # Name of this method is defined in find_by_rpx_identifier_method
29
+ # method in session.rb
30
+ def find_by_rpx_identifier(id)
31
+ identifier = RPXIdentifier.find_by_identifier(id)
32
+ return nil if identifier.nil?
33
+ identifier.user
34
+ end
35
+
36
+ end
37
+
38
+ module Methods
39
+
40
+ # Set up some simple validations
41
+ def self.included(klass)
42
+ klass.class_eval do
43
+ has_many :rpx_identifiers, :class_name => 'RPXIdentifier'
44
+
45
+ validates_length_of_password_field_options validates_length_of_password_field_options.merge(:if => :validate_password_with_rpx?)
46
+ validates_confirmation_of_password_field_options validates_confirmation_of_password_field_options.merge(:if => :validate_password_with_rpx?)
47
+ validates_length_of_password_confirmation_field_options validates_length_of_password_confirmation_field_options.merge(:if => :validate_password_with_rpx?)
48
+ before_validation :adding_rpx_identifier
49
+ after_create :map_rpx_identifier
50
+ attr_writer :creating_new_record_from_rpx
51
+ end
52
+ end
53
+
54
+ # support a block given to the save
55
+ def save(perform_validation = true, &block)
56
+ result = super perform_validation
57
+ yield(result) if block_given?
58
+ result
59
+ end
60
+
61
+ # test if account it using RPX authentication
62
+ def using_rpx?
63
+ !rpx_identifiers.empty?
64
+ end
65
+
66
+ # test if account it using normal password authentication
67
+ def using_password?
68
+ !send(crypted_password_field).blank?
69
+ end
70
+
71
+ private
72
+
73
+ def validate_password_with_rpx?
74
+ if @creating_new_record_from_rpx
75
+ false
76
+ else
77
+ !using_rpx? && require_password?
78
+ end
79
+ end
80
+
81
+ # hook for adding RPX identifier to an existing account. This is invoked prior to model validation.
82
+ # RPX information is plucked from the controller session object (where it was placed by the session model as a result
83
+ # of the RPX callback)
84
+ # The minimal action taken is to add an RPXIdentifier object to the user.
85
+ #
86
+ # This procedure chains to the map_added_rpx_data, which may be over-ridden in your project to perform
87
+ # additional mapping of RPX information to the user model as may be desired.
88
+ #
89
+ def adding_rpx_identifier
90
+ return true unless session_class && session_class.controller
91
+ added_rpx_data = session_class.controller.session['added_rpx_data']
92
+ unless added_rpx_data.blank?
93
+ session_class.controller.session['added_rpx_data'] = nil
94
+ map_added_rpx_data( added_rpx_data )
95
+ end
96
+ return true
97
+ end
98
+
99
+ # map_added_rpx_data maps additional fields from the RPX response into the user object during the "add RPX to existing account" process.
100
+ # Override this in your user model to perform field mapping as may be desired
101
+ # See https://rpxnow.com/docs#profile_data for the definition of available attributes
102
+ #
103
+ # By default, it only creates a new RPXIdentifier for the user.
104
+ #
105
+ def map_added_rpx_data( rpx_data )
106
+ self.rpx_identifiers.create( :identifier => rpx_data['profile']['identifier'] )
107
+ end
108
+
109
+ # experimental - a feature of RPX paid accounts and not properly developed/tested yet
110
+ def map_id?
111
+ self.class.map_id
112
+ end
113
+
114
+ # experimental - a feature of RPX paid accounts and not properly developed/tested yet
115
+ def map_rpx_identifier
116
+ RPXNow.map(rpx_identifier, id) if using_rpx? && map_id?
117
+ end
118
+
119
+ # experimental - a feature of RPX paid accounts and not properly developed/tested yet
120
+ def unmap_rpx_identifer
121
+ RPXNow.unmap(rpx_identifier, id) if using_rpx? && map_id?
122
+ end
123
+
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,42 @@
1
+ module AuthlogicRpx
2
+ module Helper
3
+
4
+ # helper to insert an embedded iframe RPX login
5
+ # takes options hash:
6
+ # * <tt>app_name:</tt> name of the application (will be prepended to RPX domain and used in RPX dialogues)
7
+ # * <tt>return_url:</tt> url for the RPX callback (e.g. user_sessions_url)
8
+ # * <tt>add_rpx:</tt> if true, requests RPX callback to add to current session. Else runs normal authentication process (default)
9
+ #
10
+ def rpx_embed(options = {})
11
+ params = (
12
+ { :authenticity_token => form_authenticity_token, :add_rpx => options[:add_rpx] }.collect { |n| "#{n[0]}=#{ u(n[1]) }" if n[1] }
13
+ ).compact.join('&')
14
+ RPXNow.embed_code(options[:app_name], u( options[:return_url] + '?' + params ) )
15
+ end
16
+
17
+ # helper to insert a link to pop-up RPX login
18
+ # takes options hash:
19
+ # * <tt>link_text:</tt> text to use in the link
20
+ # * <tt>app_name:</tt> name of the application (will be prepended to RPX domain and used in RPX dialogues)
21
+ # * <tt>return_url:</tt> url for the RPX callback (e.g. user_sessions_url)
22
+ # * <tt>add_rpx:</tt> if true, requests RPX callback to add to current session. Else runs normal authentication process (default)
23
+ # * <tt>unobtrusive:</tt> true/false; sets javascript style for link. Default: true
24
+ #
25
+ # NB: i18n considerations? supports a :language parameter (not tested)
26
+ def rpx_popup(options = {})
27
+ params = (
28
+ { :authenticity_token => form_authenticity_token, :add_rpx => options[:add_rpx] }.collect { |n| "#{n[0]}=#{ u(n[1]) }" if n[1] }
29
+ ).compact.join('&')
30
+ unobtrusive = options[:unobtrusive].nil? ? true : options[:unobtrusive]
31
+ return_url = options[:return_url] + '?' + params
32
+ return_url = u( return_url ) if unobtrusive # double-encoding required only if unobtrusive mode used
33
+ RPXNow.popup_code(
34
+ options[:link_text],
35
+ options[:app_name],
36
+ return_url,
37
+ :unobtrusive=>unobtrusive
38
+ )
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,219 @@
1
+ module AuthlogicRpx
2
+ # This module is responsible for adding all of the RPX goodness to the Authlogic::Session::Base class.
3
+ module Session
4
+ # Add a simple rpx_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
+
14
+ def find_by_rpx_identifier_method(value = nil)
15
+ rw_config(:find_by_rpx_identifier_method, value, :find_by_rpx_identifier)
16
+ end
17
+ alias_method :find_by_rpx_identifier_method=, :find_by_rpx_identifier_method
18
+
19
+ # Auto Register is enabled by default.
20
+ # Add this in your Session object if you need to disable auto-registration via rpx
21
+ #
22
+ def auto_register(value=true)
23
+ auto_register_value(value)
24
+ end
25
+ def auto_register_value(value=nil)
26
+ rw_config(:auto_register,value,true)
27
+ end
28
+ alias_method :auto_register=,:auto_register
29
+
30
+ # Add this in your Session object to set the RPX API key
31
+ # RPX won't work without the API key. Set it here if not already set in your app configuration.
32
+ #
33
+ def rpx_key(value=nil)
34
+ rpx_key_value(value)
35
+ end
36
+ def rpx_key_value(value=nil)
37
+ if !inheritable_attributes.include?(:rpx_key)
38
+ RPXNow.api_key = value
39
+ end
40
+ rw_config(:rpx_key,value,false)
41
+ end
42
+ alias_method :rpx_key=,:rpx_key
43
+
44
+ # Add this in your Session object to set whether RPX returns extended user info
45
+ # By default, it will not, which is enough to get username, name, email and the rpx identified
46
+ # if you want to map additional information into your user details, you can request extended
47
+ # attributes (though not all providers give them - see the RPX docs)
48
+ #
49
+ def rpx_extended_info(value=true)
50
+ rpx_extended_info_value(value)
51
+ end
52
+ def rpx_extended_info_value(value=nil)
53
+ rw_config(:rpx_extended_info,value,false)
54
+ end
55
+ alias_method :rpx_extended_info=,:rpx_extended_info
56
+
57
+ end
58
+
59
+ module Methods
60
+
61
+ def self.included(klass)
62
+ klass.class_eval do
63
+ attr_accessor :new_registration
64
+ after_persisting :add_rpx_identifier, :if => :adding_rpx_identifier?
65
+ validate :validate_by_rpx, :if => :authenticating_with_rpx?
66
+ end
67
+ end
68
+
69
+ # Determines if the authenticated user is also a new registration.
70
+ # For use in the session controller to help direct the most appropriate action to follow.
71
+ #
72
+ def new_registration?
73
+ new_registration
74
+ end
75
+
76
+ # Determines if the authenticated user has a complete registration (no validation errors)
77
+ # For use in the session controller to help direct the most appropriate action to follow.
78
+ #
79
+ def registration_complete?
80
+ attempted_record && attempted_record.valid?
81
+ end
82
+
83
+ private
84
+ # Tests if current request is for RPX authentication
85
+ #
86
+ def authenticating_with_rpx?
87
+ controller.params[:token] && !controller.params[:add_rpx]
88
+ end
89
+
90
+ # hook instance finder method to class
91
+ #
92
+ def find_by_rpx_identifier_method
93
+ self.class.find_by_rpx_identifier_method
94
+ end
95
+
96
+ # Tests if auto_registration is enabled (on by default)
97
+ #
98
+ def auto_register?
99
+ self.class.auto_register_value
100
+ end
101
+
102
+ # Tests if rpx_extended_info is enabled (off by default)
103
+ #
104
+ def rpx_extended_info?
105
+ self.class.rpx_extended_info_value
106
+ end
107
+
108
+ # Tests if current request is the special case of adding RPX to an existing account
109
+ #
110
+ def adding_rpx_identifier?
111
+ controller.params[:token] && controller.params[:add_rpx]
112
+ end
113
+
114
+ # Handles the special case of RPX being added to an existing account.
115
+ # At this point, a session has been established as a result of a "save" on the user model (which indirectly triggers user session validation).
116
+ # We do not directly add the RPX details to the user record here in order to avoid getting
117
+ # into a recursive dance between the session and user models.
118
+ # Rather, it uses the trick of adding the necessary RPX information to the session object,
119
+ # and the user model will pluck these values out before completing its validation step.
120
+ #
121
+ def add_rpx_identifier
122
+ data = RPXNow.user_data(controller.params[:token], :extended=> rpx_extended_info? ) {|raw| raw }
123
+ controller.session['added_rpx_data'] = data if data
124
+ end
125
+
126
+ # the main RPX magic. At this point, a session is being validated and we know RPX identifier
127
+ # has been provided. We'll callback to RPX to verify the token, and authenticate the matching
128
+ # user.
129
+ # If no user is found, and we have auto_register enabled (default) this method will also
130
+ # create the user registration stub.
131
+ #
132
+ # On return to the controller, you can test for new_registration? and registration_complete?
133
+ # to determine the most appropriate action
134
+ #
135
+ def validate_by_rpx
136
+ @rpx_data = RPXNow.user_data(
137
+ controller.params[:token],
138
+ :extended => rpx_extended_info?) { |raw| raw }
139
+
140
+ # If we don't have a valid sign-in, give-up at this point
141
+ if @rpx_data.nil?
142
+ errors.add_to_base("Authentication failed. Please try again.")
143
+ return false
144
+ end
145
+
146
+ rpx_id = @rpx_data['profile']['identifier']
147
+ if rpx_id.blank?
148
+ errors.add_to_base("Authentication failed. Please try again.")
149
+ return false
150
+ end
151
+
152
+ self.attempted_record = klass.send(find_by_rpx_identifier_method, rpx_id)
153
+
154
+ # so what do we do if we can't find an existing user matching the RPX authentication...
155
+ if !attempted_record
156
+ if auto_register?
157
+ self.attempted_record = klass.new()
158
+ map_rpx_data
159
+
160
+ # save the new user record - without session maintenance else we
161
+ # get caught in a self-referential hell, since both session and
162
+ # user objects invoke each other upon save
163
+ self.new_registration = true
164
+ self.attempted_record.creating_new_record_from_rpx = true
165
+ self.attempted_record.rpx_identifiers.build(:identifier => rpx_id)
166
+ self.attempted_record.save_without_session_maintenance
167
+ else
168
+ errors.add_to_base("We did not find any accounts with that login. Enter your details and create an account.")
169
+ return false
170
+ end
171
+ else
172
+ map_rpx_data_each_login
173
+ end
174
+
175
+ end
176
+
177
+ # map_rpx_data maps additional fields from the RPX response into the user object during auto-registration.
178
+ # Override this in your session model to change the field mapping
179
+ # See https://rpxnow.com/docs#profile_data for the definition of available attributes
180
+ #
181
+ # In this procedure, you will be writing to fields of the "self.attempted_record" object, pulling data from the @rpx_data object.
182
+ #
183
+ # WARNING: if you are using auto-registration, any fields you map should NOT have constraints enforced at the database level.
184
+ # authlogic_rpx will optimistically attempt to save the user record during registration, and
185
+ # violating a database constraint will cause the authentication/registration to fail.
186
+ #
187
+ # You can/should enforce any required validations at the model level e.g.
188
+ # validates_uniqueness_of :username, :case_sensitive => false
189
+ # This will allow the auto-registration to proceed, and the user can be given a chance to rectify the validation errors
190
+ # on your user profile page.
191
+ #
192
+ # If it is not acceptable in your application to have user records created with potential validation errors in auto-populated fields, you
193
+ # will need to override map_rpx_data and implement whatever special handling makes sense in your case. For example:
194
+ # - directly check for uniqueness and other validation requirements
195
+ # - automatically "uniquify" fields like username
196
+ # - save conflicting profile information to "pending user review" columns or a seperate table
197
+ #
198
+ def map_rpx_data
199
+ self.attempted_record.send("#{klass.login_field}=", @rpx_data['profile']['preferredUsername'] ) if attempted_record.send(klass.login_field).blank?
200
+ self.attempted_record.send("#{klass.email_field}=", @rpx_data['profile']['email'] ) if attempted_record.send(klass.email_field).blank?
201
+ end
202
+
203
+ # map_rpx_data_each_login provides a hook to allow you to map RPX profile information every time the user
204
+ # logs in.
205
+ # By default, nothing is mapped.
206
+ #
207
+ # This would mainly be used to update relatively volatile information that you are maintaining in the user model (such as profile image url)
208
+ #
209
+ # In this procedure, you will be writing to fields of the "self.attempted_record" object, pulling data from the @rpx_data object.
210
+ #
211
+ #
212
+ def map_rpx_data_each_login
213
+
214
+ end
215
+
216
+ end
217
+
218
+ end
219
+ end
@@ -0,0 +1,51 @@
1
+ module AuthlogicRpx
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,8 @@
1
+ require "authlogic_rpx/version"
2
+ require "authlogic_rpx/acts_as_authentic"
3
+ require "authlogic_rpx/session"
4
+ require "authlogic_rpx/helper"
5
+
6
+ ActiveRecord::Base.send(:include, AuthlogicRpx::ActsAsAuthentic)
7
+ Authlogic::Session::Base.send(:include, AuthlogicRpx::Session)
8
+ ActionController::Base.helper AuthlogicRpx::Helper
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require "authlogic_rpx"
@@ -0,0 +1,38 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{sidonath-authlogic_rpx}
5
+ s.version = "1.0.4b"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Paul Gallagher / tardate", "John J. Bachir / jjb", "Damir Zekic / sidonath"]
9
+ s.date = %q{2009-12-24}
10
+ s.description = %q{Authlogic extension/plugin that provides RPX (rpxnow.com) authentication support}
11
+ s.email = %q{damirz@gmail.com}
12
+ s.extra_rdoc_files = ["CHANGELOG.rdoc", "README.rdoc", "lib/authlogic_rpx.rb", "lib/authlogic_rpx/acts_as_authentic.rb", "lib/authlogic_rpx/helper.rb", "lib/authlogic_rpx/session.rb", "lib/authlogic_rpx/version.rb"]
13
+ s.files = ["CHANGELOG.rdoc", "MIT-LICENSE", "Manifest", "README.rdoc", "Rakefile", "sidonath-authlogic_rpx.gemspec", "init.rb", "lib/authlogic_rpx.rb", "lib/authlogic_rpx/acts_as_authentic.rb", "lib/authlogic_rpx/helper.rb", "lib/authlogic_rpx/session.rb", "lib/authlogic_rpx/version.rb", "rails/init.rb", "test/acts_as_authentic_test.rb", "test/fixtures/users.yml", "test/libs/rails_trickery.rb", "test/libs/user.rb", "test/libs/user_session.rb", "test/session_test.rb", "test/test_helper.rb"]
14
+ s.homepage = %q{http://github.com/sidonath/authlogic_rpx}
15
+ s.post_install_message = %q{}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Authlogic_rpx", "--main", "README.rdoc"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{authlogic_rpx}
19
+ s.rubygems_version = %q{1.3.5}
20
+ s.summary = %q{Authlogic plug-in for RPX support}
21
+ s.test_files = ["test/acts_as_authentic_test.rb", "test/session_test.rb", "test/test_helper.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 3
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ s.add_runtime_dependency(%q<authlogic>, [">= 2.1.1"])
29
+ s.add_runtime_dependency(%q<rpx_now>, [">= 0.6.6"])
30
+ else
31
+ s.add_dependency(%q<authlogic>, [">= 2.1.1"])
32
+ s.add_dependency(%q<rpx_now>, [">= 0.6.6"])
33
+ end
34
+ else
35
+ s.add_dependency(%q<authlogic>, [">= 2.1.1"])
36
+ s.add_dependency(%q<rpx_now>, [">= 0.6.6"])
37
+ end
38
+ end
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class ActsAsAuthenticTest < ActiveSupport::TestCase
4
+
5
+ end
File without changes
@@ -0,0 +1,41 @@
1
+ # The only reason I am doing all of this non sense is becuase the openid_authentication requires that
2
+ # these constants be present. The only other alternative is to use an entire rails application for testing
3
+ # which is a little too overboard for this, I think.
4
+
5
+ RAILS_ROOT = ''
6
+
7
+ class ActionController < Authlogic::TestCase::MockController
8
+ class Request < Authlogic::TestCase::MockRequest
9
+ def request_method
10
+ ""
11
+ end
12
+ end
13
+
14
+ def root_url
15
+ ''
16
+ end
17
+
18
+ def request
19
+ return @request if defined?(@request)
20
+ super
21
+ # Rails does some crazy s#!t with the "method" method. If I don't do this I get a "wrong arguments (0 for 1) error"
22
+ @request.class.class_eval do
23
+ def method
24
+ nil
25
+ end
26
+ end
27
+ @request
28
+ end
29
+
30
+ def url_for(*args)
31
+ ''
32
+ end
33
+
34
+ def redirecting_to
35
+ @redirect_to
36
+ end
37
+
38
+ def redirect_to(*args)
39
+ @redirect_to = args
40
+ end
41
+ end
data/test/libs/user.rb ADDED
@@ -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,5 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class SessionTest < ActiveSupport::TestCase
4
+
5
+ end
@@ -0,0 +1,61 @@
1
+ require "test/unit"
2
+ require "rubygems"
3
+ require "ruby-debug"
4
+ require "active_record"
5
+
6
+ ActiveRecord::Schema.verbose = false
7
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
8
+ ActiveRecord::Base.configurations = true
9
+ ActiveRecord::Schema.define(:version => 1) do
10
+
11
+ create_table :users do |t|
12
+ t.datetime :created_at
13
+ t.datetime :updated_at
14
+ t.integer :lock_version, :default => 0
15
+ t.string :login
16
+ t.string :crypted_password
17
+ t.string :password_salt
18
+ t.string :persistence_token
19
+ t.string :single_access_token
20
+ t.string :perishable_token
21
+ t.string :rpx_identifier
22
+ t.string :email
23
+ t.string :first_name
24
+ t.string :last_name
25
+ t.integer :login_count, :default => 0, :null => false
26
+ t.integer :failed_login_count, :default => 0, :null => false
27
+ t.datetime :last_request_at
28
+ t.datetime :current_login_at
29
+ t.datetime :last_login_at
30
+ t.string :current_login_ip
31
+ t.string :last_login_ip
32
+ end
33
+ end
34
+
35
+ require "active_record/fixtures"
36
+ require "openid"
37
+ require "authlogic"
38
+ require "authlogic/test_case"
39
+ require File.dirname(__FILE__) + "/libs/rails_trickery"
40
+ require File.dirname(__FILE__) + '/libs/user'
41
+ require File.dirname(__FILE__) + '/libs/user_session'
42
+
43
+ class ActiveSupport::TestCase
44
+ include ActiveRecord::TestFixtures
45
+ self.fixture_path = File.dirname(__FILE__) + "/fixtures"
46
+ self.use_transactional_fixtures = false
47
+ self.use_instantiated_fixtures = false
48
+ self.pre_loaded_fixtures = false
49
+ fixtures :all
50
+ setup :activate_authlogic
51
+
52
+ private
53
+ def activate_authlogic
54
+ Authlogic::Session::Base.controller = controller
55
+ end
56
+
57
+ def controller
58
+ @controller ||= Authlogic::TestCase::ControllerAdapter.new(ActionController.new)
59
+ end
60
+
61
+ end