diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index ba23feb7..9fe0f0ef 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -1,4 +1,4 @@ -== 1.0.1 released 2008-11-05 +== 1.1.0 released 2008-11-05 * Moved Rack standards into abstract_adapter for the controllers. * Added logging_in_with_credentials?, logging_in_with_unauthorized_record? @@ -13,6 +13,8 @@ * Added last_request_at_threshold configuration option. * Changed Scoped class to AuthenticatesManyAssociation, like AR has HasManyAssociation, etc. * Added should_be_authentic shoulda macro. +* Removed some magic from how sessions are initialized. See the initialize documentation, this method is a little more structured now, which was require for adding in openid. +* Added in logging via a params token, which is friendly for feed URLs. Works just like cookies and sessions when persisting the session. == 1.0.0 released 2008-11-05 diff --git a/lib/authlogic.rb b/lib/authlogic.rb index 75b17972..e18ae839 100644 --- a/lib/authlogic.rb +++ b/lib/authlogic.rb @@ -24,6 +24,8 @@ require File.dirname(__FILE__) + "/authlogic/session/config" require File.dirname(__FILE__) + "/authlogic/session/cookies" require File.dirname(__FILE__) + "/authlogic/session/errors" +require File.dirname(__FILE__) + "/authlogic/session/openid" +require File.dirname(__FILE__) + "/authlogic/session/params" require File.dirname(__FILE__) + "/authlogic/session/session" require File.dirname(__FILE__) + "/authlogic/session/scopes" require File.dirname(__FILE__) + "/authlogic/session/base" @@ -36,6 +38,8 @@ class Base include ActiveRecordTrickery include Callbacks include Cookies + #include OpenID + include Params include Session include Scopes end diff --git a/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb b/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb index 91c4b7e8..a3cb4db3 100644 --- a/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb +++ b/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb @@ -22,7 +22,8 @@ module ActsAsAuthentic # user.password= Method name based on the :password_field option. This is used to set the password. Pass the *raw* password to this. # user.confirm_password= Confirms the password, needed to change the password. # user.valid_password?(pass) Determines if the password passed is valid. The password could be encrypted or raw. - # user.reset_password! Basically resets the password to a random password using only letters and numbers. + # user.reset_password Resets the password to a random password using only letters and numbers. + # user.reset_password! The same as reset_password but saves the record. # user.logged_in? Based on the :logged_in_timeout option. Tells you if the user is logged in or not. # user.forget! Changes their remember token, making their cookie and session invalid. A way to log the user out withouth changing their password. # diff --git a/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb b/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb index a559526d..c6edf41b 100644 --- a/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb +++ b/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb @@ -5,6 +5,7 @@ module Credentials # :nodoc: def acts_as_authentic_with_credentials(options = {}) acts_as_authentic_without_credentials(options) + # The following helps extract configuration into their specific ORM adapter and allows the Session configuration to set itself based on these values class_eval <<-"end_eval", __FILE__, __LINE__ def self.login_field @login_field ||= #{options[:login_field].inspect} || @@ -39,6 +40,13 @@ def self.password_salt_field end end_eval + # The following methods allow other focused modules to alter validation behavior, such as openid as an alternate login + unless respond_to?(:allow_blank_for_login_validations?) + def self.allow_blank_for_login_validations? + false + end + end + options[:crypto_provider] ||= CryptoProviders::Sha512 options[:login_field_type] ||= login_field == :email ? :email : :login @@ -53,7 +61,7 @@ def self.password_salt_field options[:login_field_regex_message] ||= "should look like an email address." validates_format_of login_field, :with => options[:login_field_regex], :message => options[:login_field_regex_message] else - validates_length_of login_field, :within => 2..100 + validates_length_of login_field, :within => 2..100, :allow_blank => true options[:login_field_regex] ||= /\A\w[\w\.\-_@ ]+\z/ options[:login_field_regex_message] ||= "use only letters, numbers, spaces, and .-_@ please." validates_format_of login_field, :with => options[:login_field_regex], :message => options[:login_field_regex_message] @@ -81,23 +89,28 @@ def #{password_field}=(pass) self.#{password_salt_field} = self.class.unique_token self.#{crypted_password_field} = crypto_provider.encrypt(@#{password_field} + #{password_salt_field}) end - + def valid_#{password_field}?(attempted_password) return false if attempted_password.blank? || #{crypted_password_field}.blank? || #{password_salt_field}.blank? attempted_password == #{crypted_password_field} || (crypto_provider.respond_to?(:decrypt) && crypto_provider.decrypt(#{crypted_password_field}) == attempted_password + #{password_salt_field}) || (!crypto_provider.respond_to?(:decrypt) && crypto_provider.encrypt(attempted_password + #{password_salt_field}) == #{crypted_password_field}) end - + def #{password_field}; end def confirm_#{password_field}; end - def reset_#{password_field}! + def reset_#{password_field} chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a newpass = "" 1.upto(10) { |i| newpass << chars[rand(chars.size-1)] } self.#{password_field} = newpass self.confirm_#{password_field} = newpass + end + alias_method :randomize_password, :reset_password + + def reset_#{password_field}! + reset_#{password_field} save_without_session_maintenance(false) end alias_method :randomize_password!, :reset_password! @@ -106,7 +119,7 @@ def reset_#{password_field}! def tried_to_set_password? tried_to_set_password == true end - + def validate_password if new_record? || tried_to_set_#{password_field}? if @#{password_field}.blank? diff --git a/lib/authlogic/session/authenticates_many_association.rb b/lib/authlogic/session/authenticates_many_association.rb index 0b038eb8..870a0d46 100644 --- a/lib/authlogic/session/authenticates_many_association.rb +++ b/lib/authlogic/session/authenticates_many_association.rb @@ -2,7 +2,7 @@ module Authlogic module Session # = Authenticates Many Association # - # This object is used as a proxy for the authenticates_many relationship. It basically allows you to "save" scope details and call them on an object, which allows you to do the following: + # An object of this class is used as a proxy for the authenticates_many relationship. It basically allows you to "save" scope details and call them on an object, which allows you to do the following: # # @account.user_sessions.new # @account.user_sessions.find diff --git a/lib/authlogic/session/base.rb b/lib/authlogic/session/base.rb index 2d8885bd..02f73a98 100644 --- a/lib/authlogic/session/base.rb +++ b/lib/authlogic/session/base.rb @@ -80,26 +80,28 @@ def controllers end end - attr_accessor :login_with, :new_session + attr_accessor :new_session attr_reader :record, :unauthorized_record - attr_writer :id + attr_writer :id, :login_with # You can initialize a session by doing any of the following: # # UserSession.new - # UserSession.new(login, password) - # UserSession.new(:login => login, :password => password) - # UserSession.new(User.first) + # UserSession.new(:login => "login", :password => "password", :remember_me => true) + # UserSession.new(:openid => "identity url", :remember_me => true) + # UserSession.new(User.first, true) # # If a user has more than one session you need to pass an id so that Authlogic knows how to differentiate the sessions. The id MUST be a Symbol. # # UserSession.new(:my_id) - # UserSession.new(login, password, :my_id) - # UserSession.new({:login => loing, :password => password}, :my_id) - # UserSession.new(User.first, :my_id) + # UserSession.new({:login => "login", :password => "password", :remember_me => true}, :my_id) + # UserSession.new({:openid => "identity url", :remember_me => true}, :my_id) + # UserSession.new(User.first, true, :my_id) # # Ids are rarely used, but they can be useful. For example, what if users allow other users to login into their account via proxy? Now that user can "technically" be logged into 2 accounts at once. # To solve this just pass a id called :proxy, or whatever you want. Authlogic will separate everything out. + # + # The reason the id is separate from the first parameter hash is becuase this should be controlled by you, not by what the user passes. A usr could inject their own id and things would not work as expected. def initialize(*args) raise NotActivated.new(self) unless self.class.activated? @@ -107,14 +109,9 @@ def initialize(*args) self.id = args.pop if args.last.is_a?(Symbol) - case args.first - when Hash + if args.first.is_a?(Hash) self.credentials = args.first - when String - send("#{login_field}=", args[0]) if args.size > 0 - send("#{password_field}=", args[1]) if args.size > 1 - self.remember_me = args[2] if args.size > 2 - else + elsif !args.first.blank? && args.first.class < ::ActiveRecord::Base self.unauthorized_record = args.first self.remember_me = args[1] if args.size > 1 end @@ -131,7 +128,7 @@ def credentials=(values) return if values.blank? || !values.is_a?(Hash) values.symbolize_keys! [login_field.to_sym, password_field.to_sym, :remember_me].each do |field| - next if !values.key?(field) + next if values[field].blank? send("#{field}=", values[field]) end end @@ -210,6 +207,17 @@ def inspect # :nodoc: "#<#{self.class.name} #{details.inspect}>" end + # A flag for how the user is logging in. Possible values: + # + # * :credentials - username and password + # * :unauthorized_record - an actual ActiveRecord object + # * :openid - OpenID + # + # By default this is :credentials + def login_with + @login_with ||= :credentials + end + # Returns true if logging in with credentials. Credentials mean username and password. def logging_in_with_credentials? login_with == :credentials @@ -364,11 +372,7 @@ def record=(value) end def search_for_record(method, value) - begin - klass.send(method, value) - rescue Exception - raise method.inspect + " " + value.inspect - end + klass.send(method, value) end def valid_credentials? @@ -403,9 +407,6 @@ def valid_credentials? errors.add_to_base("You can not login with a new record.") return false end - else - errors.add_to_base("You must provide some form of credentials before logging in.") - return false end self.record = unchecked_record diff --git a/lib/authlogic/session/config.rb b/lib/authlogic/session/config.rb index 9b258a57..560ae64f 100644 --- a/lib/authlogic/session/config.rb +++ b/lib/authlogic/session/config.rb @@ -103,13 +103,14 @@ def find_by_openid_method(value = nil) end alias_method :find_by_openid_method=, :find_by_openid_method - # Calling UserSession.find tries to find the user session by session, then cookie, then basic http auth. This option allows you to change the order or remove any of these. + # Calling UserSession.find tries to find the user session by session, then cookie, then params, and finally by basic http auth. + # This option allows you to change the order or remove any of these. # - # * Default: [:session, :cookie, :http_auth] + # * Default: [:session, :cookie, :params, :http_auth] # * Accepts: Array, and can only use any of the 3 options above def find_with(*values) if values.blank? - read_inheritable_attribute(:find_with) || find_with(:session, :cookie, :http_auth) + read_inheritable_attribute(:find_with) || find_with(:session, :cookie, :params, :http_auth) else values.flatten! write_inheritable_attribute(:find_with, values) @@ -180,6 +181,24 @@ def openid_file_store_path(value = nil) end alias_method :openid_file_store_path=, :openid_file_store_path + # Works exactly like cookie_key, but for params. So a user can login via params just like a cookie or a session. Your URK would look like: + # + # http://www.domain.com?user_credentials=fdsfdfd32jfksdjfdksl + # + # You can change the "user_credentials" key above with this configuration option. Keep in mind, just like cookie_key, if you supply an id + # the id will be appended to the front. + # + # * Default: cookie_key + # * Accepts: String + def params_key(value = nil) + if value.nil? + read_inheritable_attribute(:params_key) || params_key(cookie_key) + else + write_inheritable_attribute(:params_key, value) + end + end + alias_method :params_key=, :params_key + # Works exactly like login_field, but for the password instead. # # * Default: Guesses based on the model columns, tries password and pass. If none are present it defaults to password @@ -263,14 +282,17 @@ def verify_password_method(value = nil) module InstanceMethods # :nodoc: def cookie_key - key_parts = [id, scope[:id], self.class.cookie_key].compact - key_parts.join("_") + build_key(self.class.cookie_key) end def find_by_login_method self.class.find_by_login_method end + def find_by_openid_method + self.class.find_by_openid_method + end + def find_with self.class.find_with end @@ -282,6 +304,14 @@ def last_request_at_threshold def login_field self.class.login_field end + + def openid_field + self.class.openid_field + end + + def params_key + build_key(self.class.params_key) + end def password_field self.class.password_field @@ -297,13 +327,18 @@ def remember_token_field end def session_key - key_parts = [id, scope[:id], self.class.session_key].compact - key_parts.join("_") + build_key(self.class.session_key) end def verify_password_method self.class.verify_password_method end + + private + def build_key(last_part) + key_parts = [id, scope[:id], last_part].compact + key_parts.join("_") + end end end end diff --git a/lib/authlogic/session/cookies.rb b/lib/authlogic/session/cookies.rb index 4e4c1050..24fc3528 100644 --- a/lib/authlogic/session/cookies.rb +++ b/lib/authlogic/session/cookies.rb @@ -1,5 +1,8 @@ module Authlogic module Session + # = Cookies + # + # Handles all authentication that deals with cookies, such as persisting a session and saving / destroying a session. module Cookies def self.included(klass) klass.after_save :save_cookie diff --git a/lib/authlogic/session/openid.rb b/lib/authlogic/session/openid.rb index 7eaaba15..ab20262b 100644 --- a/lib/authlogic/session/openid.rb +++ b/lib/authlogic/session/openid.rb @@ -2,9 +2,25 @@ module Authlogic module Session module OpenID def self.included(klass) - klass.alias_method_chain :create_configurable_methods!, :openid - klass.before_validation :valid_openid? - klass.attr_accessor :openid_response + klass.class_eval do + alias_method_chain :initialize, :openid + alias_method_chain :credentials=, :openid + alias_method_chain :create_configurable_methods!, :openid + before_validation :valid_openid? + attr_accessor :openid_response + end + end + + def initialize_with_openid(*args) + initialize_without_openid(*args) + self.login_with = :openid if openid_verification_complete? + end + + def credentials_with_openid=(values) + result = self.credentials_without_openid = values + return result if openid_field.blank? || values.blank? || !values.is_a?(Hash) || values[:openid].blank? + self.openid = values[:openid] + result end # Returns true if logging in with openid. Credentials mean username and password. @@ -12,28 +28,14 @@ def logging_in_with_openid? login_with == :openid end + def openid_verification_complete? + controller.params[:openid_complete] == "1" + end + def valid_openid? - if controller.params[:openid_complete].blank? - if send(openid_field).blank? - errors.add(openid_field, "can not be blank") - return false - end - - begin - self.openid_response = openid_consumer.begin(send(openid_field)) - rescue OpenID::OpenIDError => e - errors.add("The OpenID identifier #{send(openid_field)} could not be found: #{e}") - return false - end - - sregreq = OpenID::SReg::Request.new - # required fields - #sregreq.request_fields(['email','nickname'], true) - # optional fields - #sregreq.request_fields(['dob', 'fullname'], false) - oidreq.add_extension(sregreq) - oidreq.return_to_args["openid_complete"] = 1 - else + return false if openid_field.blank? + + if openid_verification_complete? case openid_response.status when OpenID::Consumer::SUCCESS @@ -44,6 +46,33 @@ def valid_openid? when OpenID::Consumer::SETUP_NEEDED errors.add_to_Base("OpenID authentication needs setup.") end + else + if logging_in_with_openid? + if send(openid_field).blank? + errors.add(openid_field, "can not be blank") + return false + end + + unless search_for_record(find_by_openid_method, send(openid_field)) + errors.add(openid_field, "did not match any records in our database") + return false + end + + begin + self.openid_response = openid_consumer.begin(send(openid_field)) + rescue OpenID::OpenIDError => e + errors.add("The OpenID identifier #{send(openid_field)} could not be found: #{e}") + return false + end + + sregreq = OpenID::SReg::Request.new + # required fields + #sregreq.request_fields(['email','nickname'], true) + # optional fields + #sregreq.request_fields(['dob', 'fullname'], false) + oidreq.add_extension(sregreq) + oidreq.return_to_args["openid_complete"] = 1 + end end end @@ -51,7 +80,7 @@ def valid_openid? def create_configurable_methods_with_openid! create_configurable_methods_without_openid! - return if respond_to?(openid_field) + return if openid_field.blank? || respond_to?(openid_field) if openid_field self.class.class_eval <<-"end_eval", __FILE__, __LINE__ diff --git a/lib/authlogic/session/params.rb b/lib/authlogic/session/params.rb new file mode 100644 index 00000000..802e1e9d --- /dev/null +++ b/lib/authlogic/session/params.rb @@ -0,0 +1,28 @@ +module Authlogic + module Session + # = Params + # + # Tries to log the user in via params. Think about cookies and sessions. They are just hashes in your controller, so are params. People never + # look at params as an authentication option, but it can be useful for logging into private feeds. Logging in a user is as simple as: + # + # http://www.domain.com?user_credentials=[insert remember token here] + # + # The user_credentials is based on the name of your session, the above example assumes UserSession. Also, this can be modified via configuration. + module Params + # Tries to validate the session from information in the params token + def valid_params? + if params_credentials + self.unauthorized_record = search_for_record("find_by_#{remember_token_field}", params_credentials) + return valid? + end + + false + end + + private + def params_credentials + controller.params[params_key] + end + end + end +end \ No newline at end of file diff --git a/lib/authlogic/session/session.rb b/lib/authlogic/session/session.rb index b27a821f..ea4e766f 100644 --- a/lib/authlogic/session/session.rb +++ b/lib/authlogic/session/session.rb @@ -1,5 +1,8 @@ module Authlogic module Session + # = Session + # + # Handles all parts of authentication that deal with sessions. Such as persisting a session and saving / destroy a session. module Session def self.included(klass) klass.after_save :update_session! diff --git a/test/libs/mock_controller.rb b/test/libs/mock_controller.rb index 39abab8a..f055948f 100644 --- a/test/libs/mock_controller.rb +++ b/test/libs/mock_controller.rb @@ -12,6 +12,10 @@ def cookies @cookies ||= MockCookieJar.new end + def params + @params ||= {} + end + def request @request ||= MockRequest.new end diff --git a/test/session_tests/authenticates_many_association_test.rb b/test/session_tests/authenticates_many_association_test.rb new file mode 100644 index 00000000..2d24841a --- /dev/null +++ b/test/session_tests/authenticates_many_association_test.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../test_helper.rb' + +module SessionTests + class AuthenticatesManyAssociationTest < ActiveSupport::TestCase + def test_initialize + assoc = Authlogic::Session::AuthenticatesManyAssociation.new(UserSession, {:conditions => ["1 = ?", 1]}, :some_id) + assert_equal UserSession, assoc.klass + assert_equal({:conditions => ["1 = ?", 1]}, assoc.find_options) + assert_equal :some_id, assoc.id + end + + def test_new + ben = users(:ben) + assoc = Authlogic::Session::AuthenticatesManyAssociation.new(UserSession, {:conditions => ["1 = ?", 1]}, :some_id) + session = assoc.new(ben) + assert_equal ben, session.unauthorized_record + assert_equal({:find_options => {:conditions => ["1 = ?", 1]}, :id => :some_id}, session.scope) + end + end +end \ No newline at end of file diff --git a/test/session_tests/base_test.rb b/test/session_tests/base_test.rb index 1fc39c80..f858177e 100644 --- a/test/session_tests/base_test.rb +++ b/test/session_tests/base_test.rb @@ -7,7 +7,7 @@ def test_activated Authlogic::Session::Base.reset_controllers! assert !UserSession.activated? end - + def test_controllers Authlogic::Session::Base.reset_controllers! assert_equal 0, Authlogic::Session::Base.send(:controllers).size @@ -28,15 +28,15 @@ def test_controllers assert_equal 2, Authlogic::Session::Base.send(:controllers).size assert_nil Authlogic::Session::Base.controller end - + def test_create ben = users(:ben) - assert !UserSession.create(ben.login, "badpw") - assert UserSession.create(ben.login, "benrocks") - assert_raise(Authlogic::Session::SessionInvalid) { UserSession.create!(ben.login, "badpw") } - assert UserSession.create!(ben.login, "benrocks") + assert !UserSession.create(:login => ben.login, :password => "badpw") + assert UserSession.create(:login => ben.login, :password => "benrocks") + assert_raise(Authlogic::Session::SessionInvalid) { UserSession.create!(:login => ben.login, :password => "badpw") } + assert UserSession.create!(:login => ben.login, :password => "benrocks") end - + def test_find ben = users(:ben) assert !UserSession.find @@ -49,77 +49,47 @@ def test_find assert session assert !session.record.last_request_at.nil? end - + def test_klass assert_equal User, UserSession.klass end - + def test_klass_name assert_equal "User", UserSession.klass_name end - - def test_scope_method # test_scope is reserved - UserSession.with_scope(:find_options => {:conditions => "1 = 1"}, :id => "some_id") do - assert_equal({:find_options => {:conditions => "1 = 1"}, :id => "some_id"}, UserSession.scope) - - ben = users(:ben) - session = UserSession.new - assert_equal({:find_options => {:conditions => "1 = 1"}, :id => "some_id"}, session.scope) - - session.id = :another_id - session.unauthorized_record = ben - assert session.save - assert_equal "another_id_some_id_user_credentials", session.cookie_key - assert_equal "another_id_some_id_user_credentials", session.session_key - end - assert_nil UserSession.scope - end - - def test_with_scope_method # test_with_scope is reserved - assert_raise(ArgumentError) { UserSession.with_scope } - # the rest of the method was tested in test_scope - end - def test_init UserSession.reset_controllers! assert_raise(Authlogic::Session::NotActivated) { UserSession.new } UserSession.controller = @controller - + session = UserSession.new assert session.respond_to?(:login) assert session.respond_to?(:login=) assert session.respond_to?(:password) assert session.respond_to?(:password=) assert session.respond_to?(:protected_password, true) - - + + session = UserSession.new(:my_id) assert_equal :my_id, session.id - - session = UserSession.new("login", "pass", true, :my_id) - assert_equal "login", session.login - assert_nil session.password - assert_equal "pass", session.send(:protected_password) - assert_equal true, session.remember_me - assert_equal :my_id, session.id - + session = UserSession.new({:login => "login", :password => "pass", :remember_me => true}, :my_id) assert_equal "login", session.login assert_nil session.password assert_equal "pass", session.send(:protected_password) assert_equal true, session.remember_me assert_equal :my_id, session.id - - session = UserSession.new(users(:ben), :my_id) + + session = UserSession.new(users(:ben), true, :my_id) assert_nil session.login assert_nil session.password assert_nil session.send(:protected_password) - assert_nil session.remember_me + assert session.remember_me assert_equal :my_id, session.id assert_equal users(:ben), session.unauthorized_record end - + def test_credentials session = UserSession.new session.credentials = {:login => "login", :password => "pass", :remember_me => true} @@ -143,16 +113,16 @@ def test_destroy assert session.destroy assert !session.record end - + def test_errors session = UserSession.new assert session.errors.is_a?(Authlogic::Session::Errors) end - + def test_find_record # tested thoroughly in test_find end - + def test_id ben = users(:ben) session = UserSession.new(ben, :my_id) @@ -160,98 +130,94 @@ def test_id assert_equal "my_id_user_credentials", session.cookie_key assert_equal "my_id_user_credentials", session.session_key end - + def test_inspect session = UserSession.new - assert_equal "#\"\"}>", session.inspect + assert_equal "#nil, :password=>\"\"}>", session.inspect session.login = "login" session.password = "pass" assert "#\"login\", :password=>\"\"}>" == session.inspect || "#\"\", :login=>\"login\"}>" == session.inspect end - + def test_new_session session = UserSession.new assert session.new_session? - + set_session_for(users(:ben)) session = UserSession.find assert !session.new_session? end - + def test_remember_me session = UserSession.new assert_nil session.remember_me assert !session.remember_me? - + session.remember_me = false assert_equal false, session.remember_me assert !session.remember_me? - + session.remember_me = true assert_equal true, session.remember_me assert session.remember_me? - + session.remember_me = nil assert_nil session.remember_me assert !session.remember_me? - + session.remember_me = "1" assert_equal "1", session.remember_me assert session.remember_me? - + session.remember_me = "true" assert_equal "true", session.remember_me assert session.remember_me? end - + def test_remember_me_until session = UserSession.new assert_nil session.remember_me_until - + session.remember_me = true assert 3.months.from_now <= session.remember_me_until end - + def test_save_with_nothing session = UserSession.new assert !session.save assert session.new_session? end - + def test_save_with_record ben = users(:ben) - session = UserSession.new(ben.login, "benrocks") + session = UserSession.new(:login => ben.login, :password => "benrocks") assert session.save assert !session.new_session? - assert_equal ben.remember_token, @controller.session["user_credentials"] - assert_equal ben.remember_token, @controller.cookies["user_credentials"] assert_equal 1, session.record.login_count assert Time.now >= session.record.current_login_at assert_equal "1.1.1.1", session.record.current_login_ip unset_cookie unset_session end - + def test_save_with_credentials ben = users(:ben) session = UserSession.new(ben) assert session.save assert !session.new_session? - assert_equal ben.remember_token, @controller.session["user_credentials"] - assert_equal ben.remember_token, @controller.cookies["user_credentials"] assert_equal 1, session.record.login_count assert Time.now >= session.record.current_login_at assert_equal "1.1.1.1", session.record.current_login_ip end - + def test_save_with_bang session = UserSession.new assert_raise(Authlogic::Session::SessionInvalid) { session.save! } - + session.unauthorized_record = users(:ben) assert session.save! end - + def test_unauthorized_record session = UserSession.new ben = users(:ben) @@ -259,50 +225,32 @@ def test_unauthorized_record assert_equal ben, session.unauthorized_record assert_equal :unauthorized_record, session.login_with end - + def test_valid session = UserSession.new assert !session.valid? assert_nil session.record assert session.errors.count > 0 - + ben = users(:ben) session.unauthorized_record = ben assert session.valid? assert_equal ben, session.record assert session.errors.empty? end - + def test_valid_http_auth ben = users(:ben) session = UserSession.new - + http_basic_auth_for { assert !session.valid_http_auth? } - + http_basic_auth_for(ben) do assert session.valid_http_auth? - assert session.find_record assert_equal ben, session.record - assert_equal ben.remember_token, @controller.session["user_credentials"] assert_equal ben.login, session.login assert_equal ben.crypted_password, session.send(:protected_password) - assert !session.new_session? end end - - def test_valid_session - ben = users(:ben) - session = UserSession.new - - assert !session.valid_session? - - set_session_for(ben) - assert session.valid_session? - assert session.find_record - assert_equal ben, session.record - assert_equal ben.remember_token, @controller.session["user_credentials"] - assert_equal ben, session.unauthorized_record - assert !session.new_session? - end end end \ No newline at end of file diff --git a/test/session_tests/cookies_test.rb b/test/session_tests/cookies_test.rb index bf8c69b0..639a1bff 100644 --- a/test/session_tests/cookies_test.rb +++ b/test/session_tests/cookies_test.rb @@ -13,14 +13,14 @@ def test_valid_cookie assert_equal ben, session.unauthorized_record end - def test_after_save_save_cookie + def test_save ben = users(:ben) session = UserSession.new(ben) assert session.save assert_equal ben.remember_token, @controller.cookies["user_credentials"] end - def test_after_destroy_destroy_cookie + def test_destroy ben = users(:ben) set_cookie_for(ben) session = UserSession.find diff --git a/test/session_tests/params_test.rb b/test/session_tests/params_test.rb new file mode 100644 index 00000000..059b72cf --- /dev/null +++ b/test/session_tests/params_test.rb @@ -0,0 +1,16 @@ +require File.dirname(__FILE__) + '/../test_helper.rb' + +module SessionTests + class ParamsTest < ActiveSupport::TestCase + def test_valid_params + ben = users(:ben) + session = UserSession.new + + assert !session.valid_params? + + set_params_for(ben) + assert session.valid_params? + assert_equal ben, session.unauthorized_record + end + end +end \ No newline at end of file diff --git a/test/session_tests/scopes_test.rb b/test/session_tests/scopes_test.rb index 38a0f72a..138721b2 100644 --- a/test/session_tests/scopes_test.rb +++ b/test/session_tests/scopes_test.rb @@ -2,20 +2,59 @@ module SessionTests class ScopesTest < ActiveSupport::TestCase - def test_scope - UserSession.with_scope(:find_options => {:conditions => "awesome = 1"}, :id => "some_id") do - assert_equal({:find_options => {:conditions => "awesome = 1"}, :id => "some_id"}, UserSession.scope) + def test_scope_method + assert_equal 0, Authlogic::Session::Base.send(:scopes).size + thread1 = Thread.new do + scope = {:id => :scope1} + Authlogic::Session::Base.send(:scope=, scope) + assert_equal scope, Authlogic::Session::Base.scope end - assert_nil UserSession.scope + thread1.join + assert_equal 1, Authlogic::Session::Base.send(:scopes).size + assert_nil Authlogic::Session::Base.scope + thread2 = Thread.new do + scope = {:id => :scope2} + Authlogic::Session::Base.send(:scope=, scope) + assert_equal scope, Authlogic::Session::Base.scope + end + thread2.join + assert_equal 2, Authlogic::Session::Base.send(:scopes).size + assert_nil Authlogic::Session::Base.scope + Authlogic::Session::Base.send(:scopes).clear end - def test_with_scope + def test_with_scope_method assert_raise(ArgumentError) { UserSession.with_scope } - # the rest of the method was tested in test_scope + + UserSession.with_scope(:find_options => {:conditions => "awesome = 1"}, :id => "some_id") do + assert_equal({:find_options => {:conditions => "awesome = 1"}, :id => "some_id"}, UserSession.scope) + end + + assert_nil UserSession.scope end def test_initialize + UserSession.with_scope(:find_options => {:conditions => "awesome = 1"}, :id => "some_id") do + session = UserSession.new + assert_equal({:find_options => {:conditions => "awesome = 1"}, :id => "some_id"}, session.scope) + session.id = :another_id + assert_equal "another_id_some_id_user_credentials", session.cookie_key + assert_equal "another_id_some_id_user_credentials", session.session_key + end + end + + def test_search_for_record_with_scopes + binary_logic = companies(:binary_logic) + ben = users(:ben) + zack = users(:zack) + + session = UserSession.new + assert_equal zack, session.send(:search_for_record, "find_by_login", zack.login) + + session.scope = {:find_options => {:conditions => ["company_id = ?", binary_logic.id]}} + assert_nil session.send(:search_for_record, "find_by_login", zack.login) + assert_equal ben, session.send(:search_for_record, "find_by_login", ben.login) end end end \ No newline at end of file diff --git a/test/session_tests/session_test.rb b/test/session_tests/session_test.rb new file mode 100644 index 00000000..1a95f5d2 --- /dev/null +++ b/test/session_tests/session_test.rb @@ -0,0 +1,45 @@ +require File.dirname(__FILE__) + '/../test_helper.rb' + +module SessionTests + class SessionTest < ActiveSupport::TestCase + def test_valid_session + ben = users(:ben) + session = UserSession.new + + assert !session.valid_session? + + set_session_for(ben) + assert session.valid_session? + assert session.find_record + assert_equal ben, session.record + assert_equal ben.remember_token, @controller.session["user_credentials"] + assert_equal ben, session.unauthorized_record + assert !session.new_session? + end + + def test_save + ben = users(:ben) + session = UserSession.new(ben) + assert @controller.session["user_credentials"].blank? + assert session.save + assert_equal ben.remember_token, @controller.session["user_credentials"] + end + + def test_destroy + ben = users(:ben) + set_session_for(ben) + assert_equal ben.remember_token, @controller.session["user_credentials"] + session = UserSession.find + assert session.destroy + assert @controller.session["user_credentials"].blank? + end + + def test_find + ben = users(:ben) + set_cookie_for(ben) + assert @controller.session["user_credentials"].blank? + assert UserSession.find + assert_equal ben.remember_token, @controller.session["user_credentials"] + end + end +end \ No newline at end of file diff --git a/test/test_helper.rb b/test/test_helper.rb index 7f2729ec..cb662381 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -38,6 +38,7 @@ t.string :login t.string :crypted_password t.string :password_salt + t.string :openid t.string :remember_token t.string :first_name t.string :last_name @@ -132,6 +133,14 @@ def unset_cookie @controller.cookies["user_credentials"] = nil end + def set_params_for(user, id = nil) + @controller.params["user_credentials"] = user.remember_token + end + + def unset_params + @controller.params["user_credentials"] = nil + end + def set_session_for(user, id = nil) @controller.session["user_credentials"] = user.remember_token end