authlogic 1.4.1 → 1.4.2

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.

data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,11 @@
1
+ == 1.4.2 released 2009-2-20
2
+
3
+ * Cleaned up callbacks system to use hooks and execute in the proper order.
4
+ * Added brute force protection. See the consecutive_failed_logins_limit configuration option in Authlogic::Session::Config. Also see Authlogic::Session:BruteForceProtection
5
+ * Fixed issue with calling stale? when there is no record.
6
+ * Simon Harris fixed the issue of using lock_version with the associated record and also optimized the library for better performance.
7
+ * Implemented saving the record during the callback chain to execute as few queries as possible. This way modules can hook into Authlogic, modify the associated record, and not have to worry about saving the record.
8
+
1
9
  == 1.4.1 released 2009-2-8
2
10
 
3
11
  * Fixed I18n key misspelling.
data/Manifest CHANGED
@@ -10,6 +10,7 @@ lib/authlogic/crypto_providers/bcrypt.rb
10
10
  lib/authlogic/crypto_providers/sha1.rb
11
11
  lib/authlogic/crypto_providers/sha512.rb
12
12
  lib/authlogic/i18n.rb
13
+ lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/base.rb
13
14
  lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb
14
15
  lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb
15
16
  lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb
@@ -17,17 +18,18 @@ lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/perishability
17
18
  lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb
18
19
  lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb
19
20
  lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb
20
- lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb
21
21
  lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb
22
22
  lib/authlogic/session/active_record_trickery.rb
23
23
  lib/authlogic/session/authenticates_many_association.rb
24
24
  lib/authlogic/session/base.rb
25
+ lib/authlogic/session/brute_force_protection.rb
25
26
  lib/authlogic/session/callbacks.rb
26
27
  lib/authlogic/session/config.rb
27
28
  lib/authlogic/session/cookies.rb
28
29
  lib/authlogic/session/errors.rb
29
30
  lib/authlogic/session/params.rb
30
31
  lib/authlogic/session/perishability.rb
32
+ lib/authlogic/session/record_info.rb
31
33
  lib/authlogic/session/scopes.rb
32
34
  lib/authlogic/session/session.rb
33
35
  lib/authlogic/session/timeout.rb
@@ -63,6 +65,7 @@ test/orm_adapters_tests/active_record_adapter_tests/authenticates_many_test.rb
63
65
  test/session_tests/active_record_trickery_test.rb
64
66
  test/session_tests/authenticates_many_association_test.rb
65
67
  test/session_tests/base_test.rb
68
+ test/session_tests/brute_force_protection_test.rb
66
69
  test/session_tests/config_test.rb
67
70
  test/session_tests/cookies_test.rb
68
71
  test/session_tests/params_test.rb
data/README.rdoc CHANGED
@@ -129,6 +129,7 @@ The user model needs to have the following columns. The names of these columns c
129
129
  t.string :single_access_token, :null => false # optional, see the tokens section below.
130
130
  t.string :perishable_token, :null => false # optional, see the tokens section below.
131
131
  t.integer :login_count, :null => false, :default => 0 # optional, this is a "magic" column, see the magic columns section below
132
+ t.integer :failed_login_count, :null => false, :default => 0 # optional, this is a "magic" column, see the magic columns section below
132
133
 
133
134
  === Set up your model
134
135
 
@@ -178,6 +179,7 @@ Just like ActiveRecord has "magic" columns, such as: created_at and updated_at.
178
179
 
179
180
  Column name Description
180
181
  login_count Increased every time an explicit login is made. This will *NOT* increase if logging in by a session, cookie, or basic http auth
182
+ failed_login_count This increases for each consecutive failed login. See Authlogic::Session::BruteForceProtection and the consecutive_failed_logins_limit config option for more details.
181
183
  last_request_at Updates every time the user logs in, either by explicitly logging in, or logging in by cookie, session, or http auth
182
184
  current_login_at Updates with the current time when an explicit login is made.
183
185
  last_login_at Updates with the value of current_login_at before it is reset.
@@ -203,26 +205,7 @@ Need Authlogic to check your own "state"? No problem, check out the hooks sectio
203
205
 
204
206
  Just like ActiveRecord you can create your own hooks / callbacks so that you can do whatever you want when certain actions are performed. Such as before_save, after_save, etc.
205
207
 
206
- before_create
207
- after_create
208
-
209
- before_destroy
210
- after_destroy
211
-
212
- before_find
213
- after_find
214
-
215
- before_save
216
- after_save
217
-
218
- before_update
219
- after_update
220
-
221
- before_validation
222
- validate
223
- after_validation
224
-
225
- See Authlogic::Session::Callbacks for more information
208
+ See Authlogic::Session::Callbacks for more information.
226
209
 
227
210
  == Multiple Sessions / Session Identifiers
228
211
 
@@ -429,7 +412,7 @@ With the above information you should be able to scope your sessions any way you
429
412
  The errors in Authlogic work JUST LIKE ActiveRecord. In fact, it uses the exact same ActiveRecord errors class. Use it the same way:
430
413
 
431
414
  class UserSession
432
- before_validation :check_if_awesome
415
+ validate :check_if_awesome
433
416
 
434
417
  private
435
418
  def check_if_awesome
@@ -438,7 +421,7 @@ The errors in Authlogic work JUST LIKE ActiveRecord. In fact, it uses the exact
438
421
  end
439
422
  end
440
423
 
441
- == Timing Out Sessions
424
+ == Timing Out Sessions (Logging out after inactivity)
442
425
 
443
426
  Think about financial websites, if you are inactive for a certain period of time you will be asked to log back in on your next request. You can do this with Authlogic easily, there are 2 parts to this:
444
427
 
@@ -483,7 +466,7 @@ Obviously there is a little more to it than this, but hopefully this clarifies a
483
466
 
484
467
  When things come together like this I think its a sign that you are doing something right. Put that in your pipe and smoke it!
485
468
 
486
- == Internationalization (I18n)
469
+ == Internationalization (I18n) / Changing Messages
487
470
 
488
471
  Please see Authlogic::I18n for more information. Internationalization is very easy to implement, in fact if you are using the default rails I18n library then you don't need to do anything other than defining the messages in your localization configuration files. See Authlogic::I18n for a complete list of keys you need to define.
489
472
 
data/authlogic.gemspec CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{authlogic}
5
- s.version = "1.4.1"
5
+ s.version = "1.4.2"
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-02-08}
9
+ s.date = %q{2009-02-20}
10
10
  s.description = %q{A clean, simple, and unobtrusive ruby authentication solution.}
11
11
  s.email = %q{bjohnson@binarylogic.com}
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
- 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"]
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/base.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/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/brute_force_protection.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/record_info.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
+ 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/base.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/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/brute_force_protection.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/record_info.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/brute_force_protection_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
16
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Authlogic", "--main", "README.rdoc"]
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.rubyforge_project = %q{authlogic}
19
19
  s.rubygems_version = %q{1.3.1}
20
20
  s.summary = %q{A clean, simple, and unobtrusive ruby authentication solution.}
21
- s.test_files = ["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/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"]
21
+ s.test_files = ["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/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/brute_force_protection_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"]
22
22
 
23
23
  if s.respond_to? :specification_version then
24
24
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
@@ -27,15 +27,12 @@ Gem::Specification.new do |s|
27
27
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
28
  s.add_runtime_dependency(%q<activesupport>, [">= 0"])
29
29
  s.add_runtime_dependency(%q<echoe>, [">= 0"])
30
- s.add_development_dependency(%q<echoe>, [">= 0"])
31
30
  else
32
31
  s.add_dependency(%q<activesupport>, [">= 0"])
33
32
  s.add_dependency(%q<echoe>, [">= 0"])
34
- s.add_dependency(%q<echoe>, [">= 0"])
35
33
  end
36
34
  else
37
35
  s.add_dependency(%q<activesupport>, [">= 0"])
38
36
  s.add_dependency(%q<echoe>, [">= 0"])
39
- s.add_dependency(%q<echoe>, [">= 0"])
40
37
  end
41
38
  end
data/lib/authlogic.rb CHANGED
@@ -13,7 +13,7 @@ require File.dirname(__FILE__) + "/authlogic/crypto_providers/bcrypt"
13
13
  require File.dirname(__FILE__) + "/authlogic/crypto_providers/aes256"
14
14
 
15
15
  if defined?(ActiveRecord)
16
- require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic"
16
+ require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/base"
17
17
  require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials"
18
18
  require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in"
19
19
  require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/perishability"
@@ -26,12 +26,14 @@ end
26
26
 
27
27
  require File.dirname(__FILE__) + "/authlogic/session/authenticates_many_association"
28
28
  require File.dirname(__FILE__) + "/authlogic/session/active_record_trickery"
29
+ require File.dirname(__FILE__) + "/authlogic/session/brute_force_protection"
29
30
  require File.dirname(__FILE__) + "/authlogic/session/callbacks"
30
31
  require File.dirname(__FILE__) + "/authlogic/session/config"
31
32
  require File.dirname(__FILE__) + "/authlogic/session/cookies"
32
33
  require File.dirname(__FILE__) + "/authlogic/session/errors"
33
34
  require File.dirname(__FILE__) + "/authlogic/session/params"
34
35
  require File.dirname(__FILE__) + "/authlogic/session/perishability"
36
+ require File.dirname(__FILE__) + "/authlogic/session/record_info"
35
37
  require File.dirname(__FILE__) + "/authlogic/session/session"
36
38
  require File.dirname(__FILE__) + "/authlogic/session/scopes"
37
39
  require File.dirname(__FILE__) + "/authlogic/session/timeout"
@@ -42,9 +44,11 @@ module Authlogic
42
44
  class Base
43
45
  include ActiveRecordTrickery
44
46
  include Callbacks
47
+ include BruteForceProtection
45
48
  include Cookies
46
49
  include Params
47
50
  include Perishability
51
+ include RecordInfo
48
52
  include Session
49
53
  include Scopes
50
54
  include Timeout
@@ -33,6 +33,7 @@ module Authlogic
33
33
  # login_blank: can not be blank
34
34
  # login_not_found: does not exist
35
35
  # login_invalid: should use only letters, numbers, spaces, and .-_@ please.
36
+ # consecutive_failed_logins_limit_exceeded: Consecutive failed logins limit exceeded.
36
37
  # email_invalid: should look like an email address.
37
38
  # password_blank: can not be blank
38
39
  # password_invalid: is not valid
@@ -2,9 +2,16 @@ module Authlogic
2
2
  module ORMAdapters # :nodoc:
3
3
  module ActiveRecordAdapter # :nodoc:
4
4
  # = Acts As Authentic
5
- # Provides the acts_as_authentic method to include in your models to help with authentication. See sub modules for more information.
5
+ #
6
+ # Provides the acts_as_authentic method to include in your models to help with authentication. You can include it as follows:
7
+ #
8
+ # class User < ActiveRecord::Base
9
+ # acts_as_authentic :option => "value"
10
+ # end
11
+ #
12
+ # For a list of configuration options see the ActsAsAuthentic::Config module.
6
13
  module ActsAsAuthentic
7
- # All logic for this method is split up into sub modules. This a stub to create a method chain off of and provide documentation. See sub modules for more details.
14
+ # All logic for this method is split up into sub modules. See sub modules for more details.
8
15
  def acts_as_authentic(options = {})
9
16
  end
10
17
  end
@@ -150,15 +150,6 @@ module Authlogic
150
150
  # * <tt>email_field_validates_uniqueness_of_options</tt> - default: same as :login_field if :login_field_type == :email,
151
151
  # These options are applied to the validates_uniqueness_of call for the :email_field
152
152
  module Config
153
- def first_column_to_exist(*columns_to_check) # :nodoc:
154
- columns_to_check.each { |column_name| return column_name.to_sym if column_names.include?(column_name.to_s) }
155
- columns_to_check.first ? columns_to_check.first.to_sym : nil
156
- end
157
-
158
- def meta_def(name, &block)
159
- (class << self; self; end).instance_eval { define_method name, &block }
160
- end
161
-
162
153
  def acts_as_authentic_with_config(options = {})
163
154
  # Stop all configuration if the DB is not set up
164
155
  begin
@@ -224,12 +215,15 @@ module Authlogic
224
215
 
225
216
  options[:transition_from_crypto_provider] = [options[:transition_from_crypto_provider]].compact unless options[:transition_from_crypto_provider].is_a?(Array)
226
217
 
227
- meta_def :acts_as_authentic_config do
228
- options
229
- end
230
-
218
+ cattr_accessor :acts_as_authentic_config
219
+ self.acts_as_authentic_config = options
231
220
  acts_as_authentic_without_config(options)
232
221
  end
222
+
223
+ def first_column_to_exist(*columns_to_check) # :nodoc:
224
+ columns_to_check.each { |column_name| return column_name.to_sym if column_names.include?(column_name.to_s) }
225
+ columns_to_check.first ? columns_to_check.first.to_sym : nil
226
+ end
233
227
  end
234
228
  end
235
229
  end
@@ -39,7 +39,7 @@ module Authlogic
39
39
  @_logged_out = true
40
40
 
41
41
  #{options[:session_ids].inspect}.each do |session_id|
42
- session = #{options[:session_class]}.find(*[session_id].compact)
42
+ session = #{options[:session_class]}.find(session_id, self)
43
43
  if session
44
44
  if !session.record.blank?
45
45
  @_logged_out = false
@@ -63,7 +63,7 @@ module Authlogic
63
63
  session_id = #{options[:session_ids].inspect}.first
64
64
 
65
65
  # If we are already logged in, ignore this completely. All that we care about is updating ourself.
66
- next if #{options[:session_class]}.find(*[session_id].compact)
66
+ next if #{options[:session_class]}.find(session_id, self)
67
67
 
68
68
  # Log me in
69
69
  args = [self, session_id].compact
@@ -61,10 +61,12 @@ module Authlogic
61
61
  # UserSession.find(:secure)
62
62
  #
63
63
  # See the id method for more information on ids.
64
- def find(id = nil)
65
- args = [id].compact
66
- session = new(*args)
67
- if session.find_record
64
+ def find(id = nil, priority_record = nil)
65
+ session = new(id)
66
+ session.before_find
67
+ if record = session.find_record
68
+ session.after_find
69
+ record.save_without_session_maintenance(false) if record.changed? && record != priority_record
68
70
  session
69
71
  else
70
72
  nil
@@ -90,7 +92,7 @@ module Authlogic
90
92
  end
91
93
  end
92
94
  end
93
-
95
+
94
96
  attr_accessor :new_session
95
97
  attr_reader :record, :unauthorized_record
96
98
  attr_writer :authenticating_with, :id, :persisting
@@ -165,8 +167,13 @@ module Authlogic
165
167
 
166
168
  # Resets everything, your errors, record, cookies, and session. Basically "logs out" a user.
167
169
  def destroy
170
+ before_destroy
171
+
168
172
  errors.clear
169
173
  @record = nil
174
+
175
+ after_destroy
176
+
170
177
  true
171
178
  end
172
179
 
@@ -276,20 +283,13 @@ module Authlogic
276
283
  def save(&block)
277
284
  result = nil
278
285
  if valid?
279
- record.login_count = (record.login_count.blank? ? 1 : record.login_count + 1) if record.respond_to?(:login_count)
280
-
281
- if record.respond_to?(:current_login_at)
282
- record.last_login_at = record.current_login_at if record.respond_to?(:last_login_at)
283
- record.current_login_at = klass.default_timezone == :utc ? Time.now.utc : Time.now
284
- end
285
-
286
- if record.respond_to?(:current_login_ip)
287
- record.last_login_ip = record.current_login_ip if record.respond_to?(:last_login_ip)
288
- record.current_login_ip = controller.request.remote_ip
289
- end
290
-
291
- record.save_without_session_maintenance(false)
286
+ # hooks
287
+ before_save
288
+ new_session? ? before_create : before_update
289
+ new_session? ? after_create : after_update
290
+ after_save
292
291
 
292
+ record.save_without_session_maintenance(false) if record.changed?
293
293
  self.new_session = false
294
294
  result = self
295
295
  else
@@ -323,8 +323,19 @@ module Authlogic
323
323
  def valid?
324
324
  errors.clear
325
325
  if valid_credentials?
326
+ # hooks
327
+ before_validation
328
+ new_session? ? before_validation_on_create : before_validation_on_update
326
329
  validate
330
+
327
331
  valid_record?
332
+
333
+ # hooks
334
+ new_session? ? after_validation_on_create : after_validation_on_update
335
+ after_validation
336
+
337
+ record.save_without_session_maintenance(false) if record.changed?
338
+
328
339
  return true if errors.empty?
329
340
  end
330
341
 
@@ -345,10 +356,6 @@ module Authlogic
345
356
  false
346
357
  end
347
358
 
348
- # Overwite this method to add your own validation, or use callbacks: before_validation, after_validation
349
- def validate
350
- end
351
-
352
359
  private
353
360
  def controller
354
361
  self.class.controller
@@ -0,0 +1,54 @@
1
+ module Authlogic
2
+ module Session
3
+ # = Brute Force Protection
4
+ #
5
+ # A brute force attacks is executed by hammering a login with as many password combinations as possible, until one works. A brute force attacked is
6
+ # generally combated with a slow hasing algorithm such as BCrypt. You can increase the cost, which makes the hash generation slower, and ultimately
7
+ # increases the time it takes to execute a brute force attack. Just to put this into perspective, if a hacker was to gain access to your server
8
+ # and execute a brute force attack locally, meaning there is no network lag, it would take decades to complete. Now throw in network lag for hackers
9
+ # executing this attack over a network, and it would take centuries.
10
+ #
11
+ # But for those that are extra paranoid and can't get enough protection, why not stop them as soon as you realize something isn't right? That's
12
+ # what this module is all about. By default the consecutive_failed_logins_limit configuration option is set to 50, if someone consecutively fails to login
13
+ # after 50 attempts their account will be suspended. This is a very liberal number and at this point it should be obvious that something is not right.
14
+ # If you wish to lower this number just set the configuration to a lower number:
15
+ #
16
+ # class UserSession < Authlogic::Session::Base
17
+ # consecutive_failed_logins_limit 10
18
+ # end
19
+ module BruteForceProtection
20
+ def self.included(klass)
21
+ klass.validate :validate_failed_logins, :if => :protect_from_brute_force_attacks?
22
+ klass.after_validation :increase_failed_login_count, :if => :protect_from_brute_force_attacks?
23
+ klass.after_save :reset_failed_login_count, :if => :protect_from_brute_force_attacks?
24
+ end
25
+
26
+ # This allows you to reset the failed_login_count for the associated record, allowing that account to start at 0 and continue
27
+ # trying to login. So, if an account exceeds the limit the only way they will be able to log back in is if your execute this
28
+ # method, which merely resets the failed_login_count field to 0.
29
+ def reset_failed_login_count
30
+ record.update_attribute(:failed_login_count, 0)
31
+ end
32
+
33
+ private
34
+ def protect_from_brute_force_attacks?
35
+ record && record.respond_to?(:failed_login_count) && consecutive_failed_logins_limit > 0
36
+ end
37
+
38
+ def record_by_login
39
+ unchecked_record = search_for_record(find_by_login_method, send(login_field))
40
+ end
41
+
42
+ def validate_failed_logins
43
+ errors.add_to_base(I18n.t('error_messages.consecutive_failed_logins_limit_exceeded', :default => "Consecutive failed logins limit exceeded.")) if record.failed_login_count && record.failed_login_count >= consecutive_failed_logins_limit
44
+ end
45
+
46
+ def increase_failed_login_count
47
+ if !errors.empty?
48
+ record.failed_login_count ||= 0
49
+ record.failed_login_count += 1
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -2,83 +2,66 @@ module Authlogic
2
2
  module Session
3
3
  # = Callbacks
4
4
  #
5
- # Just like in ActiveRecord you have before_save, before_validation, etc. You have similar callbacks with Authlogic, see all callbacks below.
5
+ # Just like in ActiveRecord you have before_save, before_validation, etc. You have similar callbacks with Authlogic, see the METHODS constant below. The order of execution is as follows:
6
+ #
7
+ # Here is the order they execute
8
+ #
9
+ # before_find
10
+ # after_find
11
+ # save record if changed?
12
+ #
13
+ # before_validation
14
+ # before_validation_on_create
15
+ # before_validation_on_update
16
+ # validate
17
+ # after_validation_on_update
18
+ # after_validation_on_create
19
+ # after_validation
20
+ # save record if changed?
21
+ #
22
+ # before_save
23
+ # before_create
24
+ # before_update
25
+ # after_update
26
+ # after_create
27
+ # after_save
28
+ # save record if changed?
29
+ #
30
+ # before_destroy
31
+ # destroy
32
+ # after_destroy
33
+ #
34
+ # Notice the "save record if changed?" lines above. This helps with performance. If you need to make changes to the associated record, there is no need to save the record, Authlogic will do it for you.
35
+ # This allow multiple modules to modify the record and execute as few queries as possible.
36
+ #
37
+ # **WARNING**: unlike ActiveRecord, these callbacks must be set up on the class level:
38
+ #
39
+ # class UserSession < Authlogic::Session::Base
40
+ # before_validation :my_method
41
+ # validate :another_method
42
+ # # ..etc
43
+ # end
44
+ #
45
+ # You can NOT define a "before_validation" method, this is bad practice and does not allow Authlogic to extend properly with multiple extensions. Please ONLY use the method above.
6
46
  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 validate after_validation)
8
-
47
+ METHODS = [
48
+ "before_find", "after_find",
49
+ "before_validation", "before_validation_on_create", "before_validation_on_update", "validate", "after_validation_on_update", "after_validation_on_create", "after_validation",
50
+ "before_save", "before_create", "before_update", "after_update", "after_create", "after_save",
51
+ "before_destroy", "after_destroy"
52
+ ]
53
+
9
54
  def self.included(base) #:nodoc:
10
- [:destroy, :find_record, :save, :validate].each do |method|
11
- base.send :alias_method_chain, method, :callbacks
12
- end
13
-
14
55
  base.send :include, ActiveSupport::Callbacks
15
- base.define_callbacks *CALLBACKS
56
+ base.define_callbacks *METHODS
16
57
  end
17
58
 
18
- # Runs the following callbacks:
19
- #
20
- # before_destroy
21
- # destroy
22
- # after_destroy # only if destroy is successful
23
- def destroy_with_callbacks
24
- run_callbacks(:before_destroy)
25
- result = destroy_without_callbacks
26
- run_callbacks(:after_destroy) if result
27
- result
28
- end
29
-
30
- # Runs the following callbacks:
31
- #
32
- # before_find
33
- # find_record
34
- # after_find # if a record was found
35
- def find_record_with_callbacks
36
- run_callbacks(:before_find)
37
- result = find_record_without_callbacks
38
- run_callbacks(:after_find) if result
39
- result
40
- end
41
-
42
- # Runs the following callbacks:
43
- #
44
- # before_save
45
- # before_create # only if new_session? == true
46
- # before_update # only if new_session? == false
47
- # save
48
- # # the following are only run is save is successful
49
- # after_save
50
- # before_update # only if new_session? == false
51
- # before_create # only if new_session? == true
52
- def save_with_callbacks(&block)
53
- run_callbacks(:before_save)
54
- if new_session?
55
- run_callbacks(:before_create)
56
- else
57
- run_callbacks(:before_update)
58
- end
59
- result = save_without_callbacks(&block)
60
- if result
61
- run_callbacks(:after_save)
62
-
63
- if new_session?
64
- run_callbacks(:after_create)
65
- else
66
- run_callbacks(:after_update)
59
+ METHODS.each do |method|
60
+ class_eval <<-"end_eval", __FILE__, __LINE__
61
+ def #{method}
62
+ run_callbacks(:#{method})
67
63
  end
68
- end
69
- result
70
- end
71
-
72
- # Runs the following callbacks:
73
- #
74
- # before_validation
75
- # validate
76
- # after_validation # only if errors.empty?
77
- def validate_with_callbacks
78
- run_callbacks(:before_validation)
79
- validate_without_callbacks
80
- run_callbacks(:validate)
81
- run_callbacks(:after_validation) if errors.empty?
64
+ end_eval
82
65
  end
83
66
  end
84
67
  end
@@ -185,6 +185,25 @@ module Authlogic
185
185
  end
186
186
  alias_method :logout_on_timeout=, :logout_on_timeout
187
187
 
188
+ # To help protect from brute force attacks you can set a limit on the allowed number of consecutive failed logins. By default this is 50, this is a very liberal
189
+ # number, and if someone fails to login after 50 tries it should be pretty obvious that it's a machine trying to login in and very likely a brute force attack.
190
+ #
191
+ # In order to enable this field your model MUST have a failed_login_count (integer) field.
192
+ #
193
+ # If you don't know what a brute force attack is, it's when a machine tries to login into a system using every combination of character possible. Thus resulting
194
+ # in possibly millions of attempts to log into an account.
195
+ #
196
+ # * <tt>Default:</tt> 50
197
+ # * <tt>Accepts:</tt> Integer, set to 0 to disable
198
+ def consecutive_failed_logins_limit(value = nil)
199
+ if value.nil?
200
+ read_inheritable_attribute(:consecutive_failed_logins_limit) || consecutive_failed_logins_limit(50)
201
+ else
202
+ write_inheritable_attribute(:consecutive_failed_logins_limit, value)
203
+ end
204
+ end
205
+ alias_method :logout_on_timeout=, :logout_on_timeout
206
+
188
207
  def not_active_message(value = nil) # :nodoc:
189
208
  new_i18n_error
190
209
  end
@@ -318,6 +337,10 @@ module Authlogic
318
337
  self.class.change_single_access_token_with_password == true
319
338
  end
320
339
 
340
+ def consecutive_failed_logins_limit
341
+ self.class.consecutive_failed_logins_limit
342
+ end
343
+
321
344
  def cookie_key
322
345
  build_key(self.class.cookie_key)
323
346
  end
@@ -11,7 +11,7 @@ module Authlogic
11
11
 
12
12
  private
13
13
  def reset_perishable_token!
14
- record.send("reset_#{perishable_token_field}!") if record.respond_to?("reset_#{perishable_token_field}!") && !record.send("disable_#{perishable_token_field}_maintenance?")
14
+ record.send("reset_#{perishable_token_field}") if record.respond_to?("reset_#{perishable_token_field}") && !record.send("disable_#{perishable_token_field}_maintenance?")
15
15
  end
16
16
  end
17
17
  end
@@ -0,0 +1,24 @@
1
+ module Authlogic
2
+ module Session
3
+ module RecordInfo
4
+ def self.included(klass)
5
+ klass.before_create :update_info
6
+ end
7
+
8
+ private
9
+ def update_info
10
+ record.login_count = (record.login_count.blank? ? 1 : record.login_count + 1) if record.respond_to?(:login_count)
11
+
12
+ if record.respond_to?(:current_login_at)
13
+ record.last_login_at = record.current_login_at if record.respond_to?(:last_login_at)
14
+ record.current_login_at = klass.default_timezone == :utc ? Time.now.utc : Time.now
15
+ end
16
+
17
+ if record.respond_to?(:current_login_ip)
18
+ record.last_login_ip = record.current_login_ip if record.respond_to?(:last_login_ip)
19
+ record.current_login_ip = controller.request.remote_ip
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -5,9 +5,9 @@ module Authlogic
5
5
  # Handles all parts of authentication that deal with sessions. Such as persisting a session and saving / destroy a session.
6
6
  module Session
7
7
  def self.included(klass)
8
- klass.after_save :update_session!, :if => :persisting?
9
- klass.after_destroy :update_session!, :if => :persisting?
10
- klass.after_find :update_session!, :if => :persisting?
8
+ klass.after_save :update_session, :if => :persisting?
9
+ klass.after_destroy :update_session, :if => :persisting?
10
+ klass.after_find :update_session, :if => :persisting? # to continue persisting the session after an http_auth request
11
11
  end
12
12
 
13
13
  # Tries to validate the session from information in the session
@@ -36,7 +36,7 @@ module Authlogic
36
36
  [controller.session[session_key], controller.session["#{session_key}_id"]].compact
37
37
  end
38
38
 
39
- def update_session!
39
+ def update_session
40
40
  controller.session[session_key] = record && record.send(persistence_token_field)
41
41
  controller.session["#{session_key}_id"] = record && record.send(record.class.primary_key)
42
42
  end
@@ -10,8 +10,9 @@ module Authlogic
10
10
  def self.included(klass)
11
11
  klass.class_eval do
12
12
  alias_method_chain :find_record, :timeout
13
- after_find :update_last_request_at!
14
- after_save :update_last_request_at!
13
+ before_find :reset_stale_state
14
+ after_find :set_last_request_at
15
+ before_save :set_last_request_at
15
16
  end
16
17
  end
17
18
 
@@ -19,21 +20,27 @@ module Authlogic
19
20
  # 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
21
  def find_record_with_timeout
21
22
  result = find_record_without_timeout
22
- self.record = nil if result && stale?
23
+ if result && stale?
24
+ self.record = nil
25
+ @stale = true
26
+ end
23
27
  result
24
28
  end
25
29
 
26
30
  # 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
31
  # 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.
28
32
  def stale?
29
- logout_on_timeout? && record && record.logged_out?
33
+ @stale == true || (logout_on_timeout? && record && record.logged_out?)
30
34
  end
31
35
 
32
36
  private
33
- def update_last_request_at!
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)
37
+ def reset_stale_state
38
+ @stale = nil
39
+ end
40
+
41
+ def set_last_request_at
42
+ if record && 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)
35
43
  record.last_request_at = klass.default_timezone == :utc ? Time.now.utc : Time.now
36
- record.save_without_session_maintenance(false)
37
44
  end
38
45
  end
39
46
  end
@@ -44,7 +44,7 @@ module Authlogic # :nodoc:
44
44
 
45
45
  MAJOR = 1
46
46
  MINOR = 4
47
- TINY = 1
47
+ TINY = 2
48
48
 
49
49
  # The current version as a Version instance
50
50
  CURRENT = new(MAJOR, MINOR, TINY)
@@ -133,7 +133,17 @@ module ORMAdaptersTests
133
133
  assert_not_equal old_salt, ben.password_salt
134
134
  assert_not_equal old_persistence_token, ben.persistence_token
135
135
  assert UserSession.find
136
+ end
137
+
138
+ def test_reset_password!
139
+ UserSession.create(users(:ben))
140
+ session = UserSession.find
141
+ assert session
142
+ ben = session.record
136
143
 
144
+ old_password = ben.crypted_password
145
+ old_salt = ben.password_salt
146
+ old_persistence_token = ben.persistence_token
137
147
  ben.reset_password!
138
148
  ben.reload
139
149
  assert_not_equal old_password, ben.crypted_password
@@ -0,0 +1,19 @@
1
+ require File.dirname(__FILE__) + '/../test_helper.rb'
2
+
3
+ module SessionTests
4
+ class BruteForceProtectionTest < ActiveSupport::TestCase
5
+ def test_under_limit
6
+ ben = users(:ben)
7
+ ben.failed_login_count = UserSession.consecutive_failed_logins_limit - 1
8
+ assert ben.save
9
+ assert UserSession.create(:login => ben.login, :password => "benrocks")
10
+ end
11
+
12
+ def test_exceeded_limit
13
+ ben = users(:ben)
14
+ ben.failed_login_count = UserSession.consecutive_failed_logins_limit
15
+ assert ben.save
16
+ assert !UserSession.create(:login => ben.login, :password => "benrocks")
17
+ end
18
+ end
19
+ end
@@ -33,16 +33,39 @@ module SessionTests
33
33
  assert !session.stale?
34
34
  end
35
35
 
36
- def test_stale
36
+ def test_not_stale
37
37
  UserSession.logout_on_timeout = true
38
38
  ben = users(:ben)
39
39
  ben.update_attribute(:last_request_at, Time.now)
40
40
  set_session_for(ben)
41
41
  session = UserSession.find
42
42
  assert !session.stale?
43
- session.record.last_request_at = 3.years.ago
43
+ end
44
+
45
+ def test_stale
46
+ ben = users(:ben)
47
+ set_session_for(ben)
48
+ ben.update_attribute(:last_request_at, 3.years.ago)
49
+ session = UserSession.find
44
50
  assert session.stale?
51
+ assert_nil @controller.session["user_credentials"]
52
+ assert_nil @controller.session["user_credentials_id"]
45
53
  UserSession.logout_on_timeout = false
46
54
  end
55
+
56
+ def test_stale_find
57
+ UserSession.logout_on_timeout = true
58
+ ben = users(:ben)
59
+
60
+ ben.update_attribute(:last_request_at, 3.years.ago)
61
+ set_session_for(ben)
62
+ session = UserSession.find
63
+ assert session.stale?
64
+
65
+ ben.update_attribute(:last_request_at, Time.now)
66
+ set_session_for(ben)
67
+ session = UserSession.find
68
+ assert !session.stale?
69
+ end
47
70
  end
48
71
  end
data/test/test_helper.rb CHANGED
@@ -34,6 +34,7 @@ ActiveRecord::Schema.define(:version => 1) do
34
34
  create_table :users do |t|
35
35
  t.datetime :created_at
36
36
  t.datetime :updated_at
37
+ t.integer :lock_version, :default => 0
37
38
  t.integer :company_id
38
39
  t.string :login
39
40
  t.string :crypted_password
@@ -45,6 +46,7 @@ ActiveRecord::Schema.define(:version => 1) do
45
46
  t.string :first_name
46
47
  t.string :last_name
47
48
  t.integer :login_count
49
+ t.integer :failed_login_count
48
50
  t.datetime :last_request_at
49
51
  t.datetime :current_login_at
50
52
  t.datetime :last_login_at
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.1
4
+ version: 1.4.2
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-02-08 00:00:00 -05:00
12
+ date: 2009-02-20 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -32,16 +32,6 @@ dependencies:
32
32
  - !ruby/object:Gem::Version
33
33
  version: "0"
34
34
  version:
35
- - !ruby/object:Gem::Dependency
36
- name: echoe
37
- type: :development
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- version: "0"
44
- version:
45
35
  description: A clean, simple, and unobtrusive ruby authentication solution.
46
36
  email: bjohnson@binarylogic.com
47
37
  executables: []
@@ -58,6 +48,7 @@ extra_rdoc_files:
58
48
  - lib/authlogic/crypto_providers/sha1.rb
59
49
  - lib/authlogic/crypto_providers/sha512.rb
60
50
  - lib/authlogic/i18n.rb
51
+ - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/base.rb
61
52
  - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb
62
53
  - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb
63
54
  - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb
@@ -65,17 +56,18 @@ extra_rdoc_files:
65
56
  - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb
66
57
  - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb
67
58
  - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb
68
- - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb
69
59
  - lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb
70
60
  - lib/authlogic/session/active_record_trickery.rb
71
61
  - lib/authlogic/session/authenticates_many_association.rb
72
62
  - lib/authlogic/session/base.rb
63
+ - lib/authlogic/session/brute_force_protection.rb
73
64
  - lib/authlogic/session/callbacks.rb
74
65
  - lib/authlogic/session/config.rb
75
66
  - lib/authlogic/session/cookies.rb
76
67
  - lib/authlogic/session/errors.rb
77
68
  - lib/authlogic/session/params.rb
78
69
  - lib/authlogic/session/perishability.rb
70
+ - lib/authlogic/session/record_info.rb
79
71
  - lib/authlogic/session/scopes.rb
80
72
  - lib/authlogic/session/session.rb
81
73
  - lib/authlogic/session/timeout.rb
@@ -96,6 +88,7 @@ files:
96
88
  - lib/authlogic/crypto_providers/sha1.rb
97
89
  - lib/authlogic/crypto_providers/sha512.rb
98
90
  - lib/authlogic/i18n.rb
91
+ - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/base.rb
99
92
  - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb
100
93
  - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb
101
94
  - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb
@@ -103,17 +96,18 @@ files:
103
96
  - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb
104
97
  - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb
105
98
  - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb
106
- - lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb
107
99
  - lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb
108
100
  - lib/authlogic/session/active_record_trickery.rb
109
101
  - lib/authlogic/session/authenticates_many_association.rb
110
102
  - lib/authlogic/session/base.rb
103
+ - lib/authlogic/session/brute_force_protection.rb
111
104
  - lib/authlogic/session/callbacks.rb
112
105
  - lib/authlogic/session/config.rb
113
106
  - lib/authlogic/session/cookies.rb
114
107
  - lib/authlogic/session/errors.rb
115
108
  - lib/authlogic/session/params.rb
116
109
  - lib/authlogic/session/perishability.rb
110
+ - lib/authlogic/session/record_info.rb
117
111
  - lib/authlogic/session/scopes.rb
118
112
  - lib/authlogic/session/session.rb
119
113
  - lib/authlogic/session/timeout.rb
@@ -149,6 +143,7 @@ files:
149
143
  - test/session_tests/active_record_trickery_test.rb
150
144
  - test/session_tests/authenticates_many_association_test.rb
151
145
  - test/session_tests/base_test.rb
146
+ - test/session_tests/brute_force_protection_test.rb
152
147
  - test/session_tests/config_test.rb
153
148
  - test/session_tests/cookies_test.rb
154
149
  - test/session_tests/params_test.rb
@@ -205,6 +200,7 @@ test_files:
205
200
  - test/session_tests/active_record_trickery_test.rb
206
201
  - test/session_tests/authenticates_many_association_test.rb
207
202
  - test/session_tests/base_test.rb
203
+ - test/session_tests/brute_force_protection_test.rb
208
204
  - test/session_tests/config_test.rb
209
205
  - test/session_tests/cookies_test.rb
210
206
  - test/session_tests/params_test.rb