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 +8 -0
- data/Manifest +4 -1
- data/README.rdoc +6 -23
- data/authlogic.gemspec +5 -8
- data/lib/authlogic.rb +5 -1
- data/lib/authlogic/i18n.rb +1 -0
- data/lib/authlogic/orm_adapters/active_record_adapter/{acts_as_authentic.rb → acts_as_authentic/base.rb} +9 -2
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb +7 -13
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb +2 -2
- data/lib/authlogic/session/base.rb +29 -22
- data/lib/authlogic/session/brute_force_protection.rb +54 -0
- data/lib/authlogic/session/callbacks.rb +54 -71
- data/lib/authlogic/session/config.rb +23 -0
- data/lib/authlogic/session/perishability.rb +1 -1
- data/lib/authlogic/session/record_info.rb +24 -0
- data/lib/authlogic/session/session.rb +4 -4
- data/lib/authlogic/session/timeout.rb +14 -7
- data/lib/authlogic/version.rb +1 -1
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb +10 -0
- data/test/session_tests/brute_force_protection_test.rb +19 -0
- data/test/session_tests/timeout_test.rb +25 -2
- data/test/test_helper.rb +2 -0
- metadata +10 -14
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
|
-
|
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
|
-
|
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.
|
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-
|
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/
|
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/
|
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
|
data/lib/authlogic/i18n.rb
CHANGED
@@ -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
|
-
#
|
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.
|
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
|
-
|
228
|
-
|
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
|
data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb
CHANGED
@@ -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(
|
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(
|
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
|
-
|
66
|
-
session
|
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
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
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
|
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
|
-
|
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 *
|
56
|
+
base.define_callbacks *METHODS
|
16
57
|
end
|
17
58
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
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}
|
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
|
9
|
-
klass.after_destroy :update_session
|
10
|
-
klass.after_find :update_session
|
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
|
-
|
14
|
-
|
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
|
-
|
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
|
34
|
-
|
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
|
data/lib/authlogic/version.rb
CHANGED
data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb
CHANGED
@@ -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
|
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
|
-
|
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.
|
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-
|
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
|