authlogic 1.4.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of authlogic might be problematic. Click here for more details.

@@ -1,3 +1,17 @@
1
+ == 1.4.1 released 2009-2-8
2
+
3
+ * Fixed I18n key misspelling.
4
+ * Added I18n keys for ORM error messages.
5
+ * Use the password_field configuration value for the alias_methods defined in acts_as_authentic/credentials.rb
6
+ * Change shoulda macros implementation to follow the shoulda documentation
7
+ * Rails >2.3 uses :domain for the session option instead of :session_domain. Authlogic now uses the proper key in the rails adapter.
8
+ * Added validate_password attribute to force password validation regardless if the password is blank. This is useful for forms explicitly changing passwords.
9
+ * The class level find method will return a session object if the session is stale. The protection is that there will be no record associated with that session. This allows you to receive an object and call the stale? method on it to determine why the user must log back in.
10
+ * Added validate callbacks in Session::Base so you can run callbacks by calling validate :my_method, just like in AR.
11
+ * Checked for blank persistence tokens when trying to validate passwords, this is where transitioning occurs. People transitioning from older systems never had a persistence token, which means it would be nil here.
12
+ * Update allowed domain name extensions for email
13
+ * Ignore default length options for validations if alternate length options are provided, since AR raises an error if 2 different length specifications are provided.
14
+
1
15
  == 1.4.0 released 2009-1-28
2
16
 
3
17
  * Added support for cookie domain, based on your frameworks session domain configuration
@@ -219,6 +219,7 @@ Just like ActiveRecord you can create your own hooks / callbacks so that you can
219
219
  after_update
220
220
 
221
221
  before_validation
222
+ validate
222
223
  after_validation
223
224
 
224
225
  See Authlogic::Session::Callbacks for more information
@@ -406,6 +407,11 @@ But what if you *don't* want to separate your cookies by subdomains? You can acc
406
407
 
407
408
  ActionController::Base.session_options[:session_domain] = '.mydomain.com'
408
409
 
410
+ or for Rails 2.3.0 or higher:
411
+
412
+ ActionController::Base.session_options[:domain] = '.mydomain.com'
413
+
414
+
409
415
  Notice the above is configuration for your session, not your cookies. Authlogic notices this and assume this is how you want to treat your cookies as well. As a result, it applies this domain to the cookies it sets. Now your session and all cookies act the same and are scoped under the same domain under Authlogic.
410
416
 
411
417
  Now let's look at this from the other angle. What if you are *NOT* using subdomains, but still want to separate cookies for each account. Simple, set the :scope_cookies option for authenticate_many:
data/Rakefile CHANGED
@@ -10,5 +10,4 @@ Echoe.new 'authlogic' do |p|
10
10
  p.summary = "A clean, simple, and unobtrusive ruby authentication solution."
11
11
  p.url = "http://github.com/binarylogic/authlogic"
12
12
  p.dependencies = %w(activesupport echoe)
13
- p.install_message = "BREAKS BACKWARDS COMPATIBILITY! This is only for those using I18n. If you were using the Authlogic configuration to implement I18n you need to update your configuration. A new cleaner approach has been implemented for I18n in Authlogic. See Authlogic::I18n for more details."
14
13
  end
@@ -2,18 +2,17 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{authlogic}
5
- s.version = "1.4.0"
5
+ s.version = "1.4.1"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Ben Johnson of Binary Logic"]
9
- s.date = %q{2009-01-28}
9
+ s.date = %q{2009-02-08}
10
10
  s.description = %q{A clean, simple, and unobtrusive ruby authentication solution.}
11
11
  s.email = %q{bjohnson@binarylogic.com}
12
12
  s.extra_rdoc_files = ["CHANGELOG.rdoc", "lib/authlogic/controller_adapters/abstract_adapter.rb", "lib/authlogic/controller_adapters/merb_adapter.rb", "lib/authlogic/controller_adapters/rails_adapter.rb", "lib/authlogic/crypto_providers/aes256.rb", "lib/authlogic/crypto_providers/bcrypt.rb", "lib/authlogic/crypto_providers/sha1.rb", "lib/authlogic/crypto_providers/sha512.rb", "lib/authlogic/i18n.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/perishability.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb", "lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb", "lib/authlogic/session/active_record_trickery.rb", "lib/authlogic/session/authenticates_many_association.rb", "lib/authlogic/session/base.rb", "lib/authlogic/session/callbacks.rb", "lib/authlogic/session/config.rb", "lib/authlogic/session/cookies.rb", "lib/authlogic/session/errors.rb", "lib/authlogic/session/params.rb", "lib/authlogic/session/perishability.rb", "lib/authlogic/session/scopes.rb", "lib/authlogic/session/session.rb", "lib/authlogic/session/timeout.rb", "lib/authlogic/testing/test_unit_helpers.rb", "lib/authlogic/version.rb", "lib/authlogic.rb", "README.rdoc"]
13
13
  s.files = ["CHANGELOG.rdoc", "generators/session/session_generator.rb", "generators/session/templates/session.rb", "init.rb", "lib/authlogic/controller_adapters/abstract_adapter.rb", "lib/authlogic/controller_adapters/merb_adapter.rb", "lib/authlogic/controller_adapters/rails_adapter.rb", "lib/authlogic/crypto_providers/aes256.rb", "lib/authlogic/crypto_providers/bcrypt.rb", "lib/authlogic/crypto_providers/sha1.rb", "lib/authlogic/crypto_providers/sha512.rb", "lib/authlogic/i18n.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/perishability.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb", "lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb", "lib/authlogic/session/active_record_trickery.rb", "lib/authlogic/session/authenticates_many_association.rb", "lib/authlogic/session/base.rb", "lib/authlogic/session/callbacks.rb", "lib/authlogic/session/config.rb", "lib/authlogic/session/cookies.rb", "lib/authlogic/session/errors.rb", "lib/authlogic/session/params.rb", "lib/authlogic/session/perishability.rb", "lib/authlogic/session/scopes.rb", "lib/authlogic/session/session.rb", "lib/authlogic/session/timeout.rb", "lib/authlogic/testing/test_unit_helpers.rb", "lib/authlogic/version.rb", "lib/authlogic.rb", "Manifest", "MIT-LICENSE", "Rakefile", "README.rdoc", "shoulda_macros/authlogic.rb", "test/crypto_provider_tests/aes256_test.rb", "test/crypto_provider_tests/bcrypt_test.rb", "test/crypto_provider_tests/sha1_test.rb", "test/crypto_provider_tests/sha512_test.rb", "test/fixtures/companies.yml", "test/fixtures/employees.yml", "test/fixtures/projects.yml", "test/fixtures/users.yml", "test/libs/mock_controller.rb", "test/libs/mock_cookie_jar.rb", "test/libs/mock_request.rb", "test/libs/ordered_hash.rb", "test/libs/user.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/logged_in_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/perishability_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/persistence_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/session_maintenance_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/single_access_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/authenticates_many_test.rb", "test/session_tests/active_record_trickery_test.rb", "test/session_tests/authenticates_many_association_test.rb", "test/session_tests/base_test.rb", "test/session_tests/config_test.rb", "test/session_tests/cookies_test.rb", "test/session_tests/params_test.rb", "test/session_tests/perishability_test.rb", "test/session_tests/scopes_test.rb", "test/session_tests/session_test.rb", "test/session_tests/timeout_test.rb", "test/test_helper.rb", "authlogic.gemspec"]
14
14
  s.has_rdoc = true
15
15
  s.homepage = %q{http://github.com/binarylogic/authlogic}
16
- s.post_install_message = %q{BREAKS BACKWARDS COMPATIBILITY! This is only for those using I18n. If you were using the Authlogic configuration to implement I18n you need to update your configuration. A new cleaner approach has been implemented for I18n in Authlogic. See Authlogic::I18n for more details.}
17
16
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Authlogic", "--main", "README.rdoc"]
18
17
  s.require_paths = ["lib"]
19
18
  s.rubyforge_project = %q{authlogic}
@@ -14,7 +14,8 @@ module Authlogic
14
14
  end
15
15
 
16
16
  def cookie_domain
17
- controller.class.session_options[:session_domain]
17
+ @cookie_domain_key ||= (Rails::VERSION::MAJOR >= 2 && Rails::VERSION::MINOR >= 3) ? :domain : :session_domain
18
+ controller.class.session_options[@cookie_domain_key]
18
19
  end
19
20
 
20
21
  def request_content_type
@@ -1,13 +1,15 @@
1
1
  module Authlogic
2
2
  # I18n
3
3
  #
4
- # Allows any message, error message, etc to use internationalization. In earlier versions of Authlogic each message was translated via configuration.
4
+ # This class allows any message in Authlogic to use internationalization. In earlier versions of Authlogic each message was translated via configuration.
5
5
  # This cluttered up the configuration and cluttered up Authlogic. So all translation has been extracted out into this class. Now all messages pass through
6
6
  # this class, making it much easier to implement in I18n library / plugin you want. Use this as a layer that sits between Authlogic and whatever I18n
7
7
  # library you want to use.
8
8
  #
9
- # By default this uses the rails I18n library, if it exists. If it doesnt exist it just returns the default english message. Using the Authlogic I18n class
10
- # works EXACTLY like the rails I18n class. Here is how all messages are translated internally with Authlogic:
9
+ # By default this uses the rails I18n library, if it exists. If it doesnt exist it just returns the default english message. The Authlogic I18n class
10
+ # works EXACTLY like the rails I18n class. This is because the arguments are delegated to this class.
11
+ #
12
+ # Here is how all messages are translated internally with Authlogic:
11
13
  #
12
14
  # Authlogic::I18n.t('error_messages.password_invalid', :default => "is invalid")
13
15
  #
@@ -24,14 +26,16 @@ module Authlogic
24
26
  #
25
27
  # Authlogic::I18n.extend MyAuthlogicI18nAdapter
26
28
  #
27
- # That it's! Here is a complete list of the keys that are passed. Just defined these however you wish:
29
+ # That it's! Here is a complete list of the keys that are passed. Just define these however you wish:
28
30
  #
29
31
  # authlogic:
30
32
  # error_messages:
31
33
  # login_blank: can not be blank
32
34
  # login_not_found: does not exist
35
+ # login_invalid: should use only letters, numbers, spaces, and .-_@ please.
36
+ # email_invalid: should look like an email address.
33
37
  # password_blank: can not be blank
34
- # password_invlid: is not valid
38
+ # password_invalid: is not valid
35
39
  # not_active: Your account is not active
36
40
  # not_confirmed: Your account is not confirmed
37
41
  # not_approved: Your account is not approved
@@ -23,35 +23,36 @@ module Authlogic
23
23
  if options[:validate_fields]
24
24
  email_name_regex = '[\w\.%\+\-]+'
25
25
  domain_head_regex = '(?:[A-Z0-9\-]+\.)+'
26
- domain_tld_regex = '(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)'
26
+ domain_tld_regex = '(?:[A-Z]{2}|aero|ag|asia|at|be|biz|ca|cc|cn|com|de|edu|eu|fm|gov|gs|jobs|jp|in|info|me|mil|mobi|museum|ms|name|net|nu|nz|org|tc|tw|tv|uk|us|vg|ws)'
27
27
  email_field_regex ||= /\A#{email_name_regex}@#{domain_head_regex}#{domain_tld_regex}\z/i
28
28
 
29
29
  if options[:validate_login_field]
30
30
  case options[:login_field_type]
31
31
  when :email
32
- validates_length_of options[:login_field], {:within => 6..100}.merge(options[:login_field_validates_length_of_options])
33
- validates_format_of options[:login_field], {:with => email_field_regex, :message => "should look like an email address."}.merge(options[:login_field_validates_format_of_options])
32
+ validates_length_of options[:login_field], sanitize_validation_length_options({:within => 6..100}, options[:login_field_validates_length_of_options])
33
+ validates_format_of options[:login_field], {:with => email_field_regex, :message => I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}.merge(options[:login_field_validates_format_of_options])
34
34
  else
35
- validates_length_of options[:login_field], {:within => 2..100}.merge(options[:login_field_validates_length_of_options])
36
- validates_format_of options[:login_field], {:with => /\A\w[\w\.\-_@ ]+\z/, :message => "should use only letters, numbers, spaces, and .-_@ please."}.merge(options[:login_field_validates_format_of_options])
35
+ validates_length_of options[:login_field], sanitize_validation_length_options({:within => 2..100}, options[:login_field_validates_length_of_options])
36
+ validates_format_of options[:login_field], {:with => /\A\w[\w\.\-_@ ]+\z/, :message => I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")}.merge(options[:login_field_validates_format_of_options])
37
37
  end
38
38
 
39
39
  validates_uniqueness_of options[:login_field], {:allow_blank => true}.merge(options[:login_field_validates_uniqueness_of_options].merge(:if => "#{options[:login_field]}_changed?".to_sym))
40
40
  end
41
41
 
42
42
  if options[:validate_password_field]
43
- validates_length_of options[:password_field], {:minimum => 4}.merge(options[:password_field_validates_length_of_options].merge(:if => "validate_#{options[:password_field]}?".to_sym))
43
+ validates_length_of options[:password_field], sanitize_validation_length_options({:minimum => 4}, options[:password_field_validates_length_of_options].merge(:if => "validate_#{options[:password_field]}?".to_sym))
44
44
  validates_confirmation_of options[:password_field], options[:password_field_validates_confirmation_of_options].merge(:if => "#{options[:password_salt_field]}_changed?".to_sym)
45
45
  validates_presence_of "#{options[:password_field]}_confirmation", options[:password_confirmation_field_validates_presence_of_options].merge(:if => "#{options[:password_salt_field]}_changed?".to_sym)
46
46
  end
47
47
 
48
48
  if options[:validate_email_field] && options[:email_field]
49
- validates_length_of options[:email_field], {:within => 6..100}.merge(options[:email_field_validates_length_of_options])
50
- validates_format_of options[:email_field], {:with => email_field_regex, :message => "should look like an email address."}.merge(options[:email_field_validates_format_of_options])
49
+ validates_length_of options[:email_field], sanitize_validation_length_options({:within => 6..100}, options[:email_field_validates_length_of_options])
50
+ validates_format_of options[:email_field], {:with => email_field_regex, :message => I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}.merge(options[:email_field_validates_format_of_options])
51
51
  validates_uniqueness_of options[:email_field], options[:email_field_validates_uniqueness_of_options].merge(:if => "#{options[:email_field]}_changed?".to_sym)
52
52
  end
53
53
  end
54
54
 
55
+ attr_accessor "validate_#{options[:password_field]}".to_sym
55
56
  attr_reader options[:password_field]
56
57
 
57
58
  class_eval <<-"end_eval", __FILE__, __LINE__
@@ -68,7 +69,6 @@ module Authlogic
68
69
  self.#{options[:password_salt_field]} = self.class.unique_token
69
70
  self.#{options[:crypted_password_field]} = #{options[:crypto_provider]}.encrypt(*encrypt_arguments(@#{options[:password_field]}, #{options[:act_like_restful_authentication].inspect} ? :restful_authentication : nil))
70
71
  end
71
- alias_method :update_#{options[:password_field]}, :#{options[:password_field]}= # this is to avoids the method chain, so we are ONLY changing the password
72
72
 
73
73
  def valid_#{options[:password_field]}?(attempted_password)
74
74
  return false if attempted_password.blank? || #{options[:crypted_password_field]}.blank? || #{options[:password_salt_field]}.blank?
@@ -84,7 +84,7 @@ module Authlogic
84
84
  # then let's reset the password using the new algorithm. If the algorithm has a cost (BCrypt) and the cost has changed, update the password with
85
85
  # the new cost.
86
86
  if index > 0 || (encryptor.respond_to?(:cost_matches?) && !encryptor.cost_matches?(#{options[:crypted_password_field]}))
87
- update_#{options[:password_field]}(attempted_password)
87
+ self.password = attempted_password
88
88
  save(false)
89
89
  end
90
90
 
@@ -100,7 +100,7 @@ module Authlogic
100
100
  self.#{options[:password_field]} = friendly_token
101
101
  self.#{options[:password_field]}_confirmation = friendly_token
102
102
  end
103
- alias_method :randomize_password, :reset_password
103
+ alias_method :randomize_#{options[:password_field]}, :reset_#{options[:password_field]}
104
104
 
105
105
  def confirm_#{options[:password_field]}
106
106
  raise "confirm_#{options[:password_field]} has been removed, please use #{options[:password_field]}_confirmation. " +
@@ -111,7 +111,7 @@ module Authlogic
111
111
  reset_#{options[:password_field]}
112
112
  save_without_session_maintenance(false)
113
113
  end
114
- alias_method :randomize_password!, :reset_password!
114
+ alias_method :randomize_#{options[:password_field]}!, :reset_#{options[:password_field]}!
115
115
 
116
116
  def validate_#{options[:password_field]}?
117
117
  case #{options[:password_field_validates_length_of_options][:if].inspect}
@@ -121,7 +121,7 @@ module Authlogic
121
121
  return false if !send(#{options[:password_field_validates_length_of_options][:if].inspect})
122
122
  end
123
123
 
124
- new_record? || #{options[:password_salt_field]}_changed? || #{options[:crypted_password_field]}.blank?
124
+ new_record? || #{options[:password_salt_field]}_changed? || #{options[:crypted_password_field]}.blank? || ["true", "1", "yes"].include?(validate_#{options[:password_field]}.to_s)
125
125
  end
126
126
 
127
127
  private
@@ -135,6 +135,12 @@ module Authlogic
135
135
  end
136
136
  end_eval
137
137
  end
138
+
139
+ def sanitize_validation_length_options(defaults, options)
140
+ length_keys = [:minimum, :maximum, :in, :within, :is]
141
+ length_keys.each { |key| defaults.delete(key) } if options.keys.find { |key| length_keys.include?(key.to_sym) }
142
+ defaults.merge(options)
143
+ end
138
144
  end
139
145
  end
140
146
  end
@@ -66,6 +66,18 @@ module Authlogic
66
66
  def reset_#{options[:persistence_token_field]}?
67
67
  #{options[:persistence_token_field]}.blank?
68
68
  end
69
+
70
+ # When a user logs in we need to ensure they have a persistence token. Think about apps that are transitioning and
71
+ # never have a persistence token to begin with. When their users log in their persistence token needs to be set.
72
+ # The only other time persistence tokens are reset is in a before_validation on the user, and when a user is saved
73
+ # from the session we skip validation for performance reasons. We do save_without_session_maintenance(false), the false
74
+ # indicates to skip validation.
75
+ def valid_#{options[:password_field]}_with_persistence?(attempted_password)
76
+ result = valid_password_without_persistence?(attempted_password)
77
+ reset_#{options[:persistence_token_field]}! if result && #{options[:persistence_token_field]}.blank?
78
+ result
79
+ end
80
+ alias_method_chain :valid_#{options[:password_field]}?, :persistence
69
81
  end_eval
70
82
  end
71
83
  end
@@ -64,8 +64,11 @@ module Authlogic
64
64
  def find(id = nil)
65
65
  args = [id].compact
66
66
  session = new(*args)
67
- return session if session.find_record
68
- nil
67
+ if session.find_record
68
+ session
69
+ else
70
+ nil
71
+ end
69
72
  end
70
73
 
71
74
  # The name of the class that this session is authenticating with. For example, the UserSession class will authenticate with the User class
@@ -452,7 +455,7 @@ module Authlogic
452
455
  return true if disable_magic_states?
453
456
  [:active, :approved, :confirmed].each do |required_status|
454
457
  if record.respond_to?("#{required_status}?") && !record.send("#{required_status}?")
455
- errors.add_to_base(I18n.t("errors_messages.not_#{required_status}", :default => "Your account is not #{required_status}"))
458
+ errors.add_to_base(I18n.t("error_messages.not_#{required_status}", :default => "Your account is not #{required_status}"))
456
459
  return false
457
460
  end
458
461
  end
@@ -4,7 +4,7 @@ module Authlogic
4
4
  #
5
5
  # Just like in ActiveRecord you have before_save, before_validation, etc. You have similar callbacks with Authlogic, see all callbacks below.
6
6
  module Callbacks
7
- CALLBACKS = %w(before_create after_create before_destroy after_destroy before_find after_find before_save after_save before_update after_update before_validation after_validation)
7
+ CALLBACKS = %w(before_create after_create before_destroy after_destroy before_find after_find before_save after_save before_update after_update before_validation validate after_validation)
8
8
 
9
9
  def self.included(base) #:nodoc:
10
10
  [:destroy, :find_record, :save, :validate].each do |method|
@@ -77,6 +77,7 @@ module Authlogic
77
77
  def validate_with_callbacks
78
78
  run_callbacks(:before_validation)
79
79
  validate_without_callbacks
80
+ run_callbacks(:validate)
80
81
  run_callbacks(:after_validation) if errors.empty?
81
82
  end
82
83
  end
@@ -165,9 +165,14 @@ module Authlogic
165
165
  # determines when we consider a user to be "logged out". Meaning, if they login and then leave the website, when do mark them as logged out?
166
166
  # I recommend just using this as a fun feature on your website or reports, giving you a ballpark number of users logged in and active. This is
167
167
  # not meant to be a dead accurate representation of a users logged in state, since there is really no real way to do this with web based apps.
168
+ # Think about a user that logs in and doesn't log out. There is no action that tells you that the user isn't technically still logged in and
169
+ # active.
168
170
  #
169
- # That being said, you can use that feature to require a login if their session timesout. Similar to how financial sites work. Just set this option to
170
- # true and if your record returns true for logged_out? then they will be required to log back in.
171
+ # That being said, you can use that feature to require a new login if their session timesout. Similar to how financial sites work. Just set this option to
172
+ # true and if your record returns true for stale? then they will be required to log back in.
173
+ #
174
+ # Lastly, UserSession.find will still return a object is the session is stale, but you will not get a record. This allows you to determine if the
175
+ # user needs to log back in because their session went stale, or because they just aren't logged in. Just call current_user_session.stale? as your flag.
171
176
  #
172
177
  # * <tt>Default:</tt> false
173
178
  # * <tt>Accepts:</tt> Boolean
@@ -13,7 +13,7 @@ module Authlogic
13
13
  def valid_cookie?
14
14
  if cookie_credentials
15
15
  self.unauthorized_record = search_for_record("find_by_#{persistence_token_field}", cookie_credentials)
16
- valid? && !stale?
16
+ valid?
17
17
  else
18
18
  false
19
19
  end
@@ -25,7 +25,7 @@ module Authlogic
25
25
  self.unauthorized_record = record
26
26
  end
27
27
  end
28
- valid? && !stale?
28
+ valid?
29
29
  else
30
30
  false
31
31
  end
@@ -8,14 +8,27 @@ module Authlogic
8
8
  # module kicks in. See the logout_on_timeout configuration option for how to turn this on.
9
9
  module Timeout
10
10
  def self.included(klass)
11
- klass.after_find :update_last_request_at!
12
- klass.after_save :update_last_request_at!
11
+ klass.class_eval do
12
+ alias_method_chain :find_record, :timeout
13
+ after_find :update_last_request_at!
14
+ after_save :update_last_request_at!
15
+ end
13
16
  end
14
17
 
18
+ # This implements the stale functionality when trying to find a session. If the session is stale the record will be cleared, but the session object will still be
19
+ # returned. This allows you to perform a current_user_session.stale? query in order to inform your users of why they need to log back in.
20
+ def find_record_with_timeout
21
+ result = find_record_without_timeout
22
+ self.record = nil if result && stale?
23
+ result
24
+ end
25
+
26
+ # Tells you if the record is stale or not. Meaning the record has timed out. This will only return true if you set logout_on_timeout to true in your configuration.
27
+ # Basically how a bank website works. If you aren't active over a certain period of time your session becomes stale and requires you to log back in.
15
28
  def stale?
16
29
  logout_on_timeout? && record && record.logged_out?
17
30
  end
18
-
31
+
19
32
  private
20
33
  def update_last_request_at!
21
34
  if record.class.column_names.include?("last_request_at") && (record.last_request_at.blank? || last_request_at_threshold.to_i.seconds.ago >= record.last_request_at)
@@ -23,7 +23,7 @@ module Authlogic
23
23
  # Sets the cookie for a record. This way when you execute a request in your test, cookie values will be present.
24
24
  def set_cookie_for(record)
25
25
  session_class = session_class(record)
26
- @request.cookies[session_class.cookie_key] = record.record.send(record.class.acts_as_authentic_config[:persistence_token_field])
26
+ @request.cookies[session_class.cookie_key] = record.send(record.class.acts_as_authentic_config[:persistence_token_field])
27
27
  end
28
28
 
29
29
  # Sets the HTTP_AUTHORIZATION header for basic HTTP auth. This way when you execute a request in your test that is trying to authenticate
@@ -44,7 +44,7 @@ module Authlogic # :nodoc:
44
44
 
45
45
  MAJOR = 1
46
46
  MINOR = 4
47
- TINY = 0
47
+ TINY = 1
48
48
 
49
49
  # The current version as a Version instance
50
50
  CURRENT = new(MAJOR, MINOR, TINY)
@@ -1,14 +1,12 @@
1
- require "test/unit"
2
-
3
1
  module Authlogic
4
2
  module ShouldaMacros
5
- def should_be_authentic
6
- klass = model_class
7
- should "acts as authentic" do
8
- assert klass.respond_to?(:acts_as_authentic_config)
3
+ class Test::Unit::TestCase
4
+ def self.should_be_authentic
5
+ klass = model_class
6
+ should "acts as authentic" do
7
+ assert klass.respond_to?(:acts_as_authentic_config)
8
+ end
9
9
  end
10
10
  end
11
11
  end
12
- end
13
-
14
- Test::Unit::TestCase.extend Authlogic::ShouldaMacros
12
+ end
@@ -136,9 +136,16 @@ module ORMAdaptersTests
136
136
  User.acts_as_authentic(:crypto_provider => crypto_provider, :transition_from_crypto_provider => from_crypto_providers)
137
137
  records.each do |record|
138
138
  old_hash = record.crypted_password
139
+ old_persistence_token = record.persistence_token
139
140
  assert record.valid_password?(password_for(record))
140
- assert_not_equal old_hash, record.crypted_password
141
+ assert_not_equal old_hash.to_s, record.crypted_password.to_s
142
+ assert_not_equal old_persistence_token.to_s, record.persistence_token.to_s # we need to make sure the persistence token gets reset, what if it is nil and has never been used before?
143
+
144
+ old_hash = record.crypted_password
145
+ old_persistence_token = record.persistence_token
141
146
  assert record.valid_password?(password_for(record))
147
+ assert_equal old_hash.to_s, record.crypted_password.to_s
148
+ assert_equal old_persistence_token.to_s, record.persistence_token.to_s
142
149
  end
143
150
  end
144
151
  end
@@ -57,6 +57,13 @@ module ORMAdaptersTests
57
57
  assert user.valid?
58
58
  end
59
59
 
60
+ # Make sure the default :within option is ignored, since AR will raise an error if :within and :minimum are passed.
61
+ def test_multiple_length_options
62
+ User.acts_as_authentic(:login_field_validates_length_of_options => {:minimum => 6})
63
+ user = User.new
64
+ assert_nothing_raised { user.valid? }
65
+ end
66
+
60
67
  def test_employee_validations
61
68
  employee = Employee.new
62
69
  employee.password = "pass"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authlogic
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Johnson of Binary Logic
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-28 00:00:00 -05:00
12
+ date: 2009-02-08 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -160,7 +160,7 @@ files:
160
160
  - authlogic.gemspec
161
161
  has_rdoc: true
162
162
  homepage: http://github.com/binarylogic/authlogic
163
- post_install_message: BREAKS BACKWARDS COMPATIBILITY! This is only for those using I18n. If you were using the Authlogic configuration to implement I18n you need to update your configuration. A new cleaner approach has been implemented for I18n in Authlogic. See Authlogic::I18n for more details.
163
+ post_install_message:
164
164
  rdoc_options:
165
165
  - --line-numbers
166
166
  - --inline-source