authlogic 1.3.8 → 1.3.9

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

Potentially problematic release.


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

@@ -1,4 +1,12 @@
1
- == 1.3.8 released 2008-11-30
1
+ == 1.3.9 released 2009-1-9
2
+
3
+ * Added the disable_perishable_token_maintenance option to disable the automatic resetting of the perishable_token, meaning you will have to maintain this yourself.
4
+ * Changed shoulda macro to conform to standards so model is not required to be passed
5
+ * Modified method definitions for the Session class to check for already defined methods, allowing you to write your own "credential" methods, and Authlogic will not overwrite your custom methods.
6
+ * Fixed bug when passing :all to single_access_allowed_request_types
7
+ * Added logout_on_timeout configuration option for Session::Base
8
+
9
+ == 1.3.8 released 2008-12-24
2
10
 
3
11
  * Only change persistence token if the password is not blank
4
12
  * Normalize the last_request_at_threshold so that you can pass an integer or a date/time range.
data/Manifest CHANGED
@@ -29,6 +29,7 @@ lib/authlogic/session/params.rb
29
29
  lib/authlogic/session/perishability.rb
30
30
  lib/authlogic/session/scopes.rb
31
31
  lib/authlogic/session/session.rb
32
+ lib/authlogic/session/timeout.rb
32
33
  lib/authlogic/testing/test_unit_helpers.rb
33
34
  lib/authlogic/version.rb
34
35
  lib/authlogic.rb
@@ -67,4 +68,5 @@ test/session_tests/params_test.rb
67
68
  test/session_tests/perishability_test.rb
68
69
  test/session_tests/scopes_test.rb
69
70
  test/session_tests/session_test.rb
71
+ test/session_tests/timeout_test.rb
70
72
  test/test_helper.rb
@@ -2,13 +2,20 @@
2
2
 
3
3
  Authlogic is a clean, simple, and unobtrusive ruby authentication solution. Put simply, its the Chuck Norris of authentication solutions for your framework of choice.
4
4
 
5
- So what is Authlogic, and why would I create a solution to a problem that already has plenty of solutions? Because none of the solutions felt right to me, RESTful development and authentication just didn't seem to go well together. It was like trying to fit a square peg in a round hole. All of the current solutions, for both rails and merb, just seemed to force that square peg in the round hole for me. Just because they did it for me doesn't make it right. They were either too complicated, bloated, littered my application with tons of code, had no platform for reasonable updating, used an inferior encryption algorithm, or were just confusing. This is not the simple / elegant ruby we all fell in love with. We need a "ruby like" authentication solution. Authlogic is my attempt to satisfy that need...
5
+ So what is Authlogic, and why would I create a solution to a problem that already has plenty of solutions? Because none of the current solutions feel right. The feel wrong because logic is not organized properly in the MVC structure. As you may know, a common misconception with the MVC design pattern is that the model "M" is only for data access logic, which is wrong. A model is a place for domain logic. This is why the RESTful design pattern and the current authentication solutions don't play nice, because the logic is not in the right spot. Authlogic solves this by placing the session maintenance logic into its own domain (aka "model"), where it belongs. Moving session maintenance into its own domain has its benefits:
6
6
 
7
- Let's take a rails application...
7
+ 1. It's easier to update and stay current with the latest security practices. Since authlogic sits in between you and your session it can assist in keeping your security top notch. Such as upgrading your hashing algorithm, helping you transition to a new algorithm, etc. Also, Authlogic is a gem, which means you get all of these benefits easily, through a rubygems update.
8
+ 2. It ties everything together on the domain level. Take a new user registration for example, no reason to manually log the user in, authlogic handles this for you via callbacks. The same applies to a user changing their password. Authlogic handles maintaining the session for you.
9
+ 3. Your application can stay clean and focused and free of redundant authentication code from app to app. Meaning generators are *NOT* necessary at all.
10
+ 4. A byproduct of #3 is that you don't have to test the same code over and over in each of your apps. You don't test the internals of ActiveRecord in each of your apps, so why would you test the internals of Authlogic? It's already been thoroughly tested for you. Focus on your application, and get rid of the noise by testing your application specific code and not generated code that you didn't write.
11
+ 5. You get to write your own code, just like you do for any other model. Meaning the code you write is specific to your application, the way you want it, and more importantly you understand it.
12
+ 6. You are not restricted to a single session. Think about Apple's me.com, where they need you to authenticate a second time before changing your billing information. Why not just create a second session for this? It works just like your initial session. Then your billing controller can require an "ultra secure" session.
13
+
14
+ Authlogic can do all of this and much more, keep reading to see...
8
15
 
9
- Wouldn't it be nice to keep your app up to date with the latest and greatest security techniques with a simple update of a gem?
16
+ == Quick example
10
17
 
11
- What if you could have authentication up and running in minutes without having to run a generator? All because it's simple, like everything else.
18
+ Let's take a rails application...
12
19
 
13
20
  What if creating a user session could be as simple as...
14
21
 
@@ -60,14 +67,12 @@ Or how about persisting the session...
60
67
  @current_user_session = UserSession.find
61
68
  end
62
69
 
63
- end current_user
70
+ def current_user
64
71
  return @current_user if defined?(@current_user)
65
72
  @current_user = current_user_session && current_user_session.user
66
73
  end
67
74
  end
68
75
 
69
- Authlogic and REST are like peas and carrots, as Forrest Gump would say. But This is just the tip of the ice berg. Keep reading to find out everything Authlogic can do.
70
-
71
76
  == Helpful links
72
77
 
73
78
  * <b>Documentation:</b> http://authlogic.rubyforge.org
@@ -116,7 +121,7 @@ The user model needs to have the following columns. The names of these columns c
116
121
 
117
122
  t.string :login, :null => false
118
123
  t.string :crypted_password, :null => false
119
- t.string :password_salt, :null => false # not needed if you are encrypting your pw instead of using a hash algorithm.
124
+ t.string :password_salt, :null => false
120
125
  t.string :persistence_token, :null => false
121
126
  t.string :single_access_token, :null => false # optional, see the tokens section below.
122
127
  t.string :perishable_token, :null => false # optional, see the tokens section below.
@@ -354,7 +359,7 @@ Now mix and match the above, it can get pretty hairy. Fear not, because Authlogi
354
359
 
355
360
  I will describe each below, in order.
356
361
 
357
- === Scoping your model
362
+ === 1. Scoping your model
358
363
 
359
364
  This scopes your login field validation, so that users are allowed to have the same login, just not in the same account.
360
365
 
@@ -363,7 +368,7 @@ This scopes your login field validation, so that users are allowed to have the s
363
368
  acts_as_authentic :scope => :account_id
364
369
  end
365
370
 
366
- === Scoping your session
371
+ === 2. Scoping your session
367
372
 
368
373
  When the session tries to validate it searches for a record. You want to scope that search. No problem...
369
374
 
@@ -380,7 +385,7 @@ This works just like ActiveRecord, so it should come natural. Here is how you ge
380
385
  authenticates_many :user_sessions
381
386
  end
382
387
 
383
- === Scoping cookies
388
+ === 3. Scoping cookies
384
389
 
385
390
  What's neat about cookies is that if you use sub domains they automatically scope their self. Meaning if you create a cookie in whatever.yourdomain.com it will not exist in another.yourdomain.com. So if you are using subdomains to scope your users, you don't have to do anything.
386
391
 
@@ -414,6 +419,22 @@ The errors in Authlogic work JUST LIKE ActiveRecord. In fact, it uses the exact
414
419
  end
415
420
  end
416
421
 
422
+ == Timing Out Sessions
423
+
424
+ 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:
425
+
426
+ 1. Define the timeout threshold:
427
+
428
+ acts_as_authentic :logged_in_timeout => 10.minutes # default is 10.minutes
429
+
430
+ 2. Enable logging out on timeouts
431
+
432
+ class UserSession < Authlogic::Session::Base
433
+ logout_on_timeout true # default if false
434
+ end
435
+
436
+ This will require a user to log back in if they are inactive for more than 10 minutes. In order for this feature to be used you must have a last_request_at datetime field in your data for whatever model you are authenticating with.
437
+
417
438
  == Automatic Session Updating
418
439
 
419
440
  This is one of my favorite features that I think is pretty cool. It's things like this that make a library great and let you know you are on the right track.
data/Rakefile CHANGED
@@ -1,19 +1,13 @@
1
1
  require 'rubygems'
2
2
  require File.dirname(__FILE__) << "/lib/authlogic/version"
3
-
4
- begin
5
- require 'echoe'
3
+ require 'echoe'
6
4
 
7
- Echoe.new 'authlogic' do |p|
8
- p.version = Authlogic::Version::STRING
9
- p.author = "Ben Johnson of Binary Logic"
10
- p.email = 'bjohnson@binarylogic.com'
11
- p.project = 'authlogic'
12
- p.summary = "A clean, simple, and unobtrusive ruby authentication solution."
13
- p.url = "http://github.com/binarylogic/authlogic"
14
- p.dependencies = %w(activesupport echoe)
15
- end
16
- rescue LoadError => boom
17
- puts "You are missing a dependency required for meta-operations on this gem."
18
- puts "#{boom.to_s.capitalize}."
5
+ Echoe.new 'authlogic' do |p|
6
+ p.version = Authlogic::Version::STRING
7
+ p.author = "Ben Johnson of Binary Logic"
8
+ p.email = 'bjohnson@binarylogic.com'
9
+ p.project = 'authlogic'
10
+ p.summary = "A clean, simple, and unobtrusive ruby authentication solution."
11
+ p.url = "http://github.com/binarylogic/authlogic"
12
+ p.dependencies = %w(activesupport echoe)
19
13
  end
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{authlogic}
5
- s.version = "1.3.8"
5
+ s.version = "1.3.9"
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{2008-12-24}
9
+ s.date = %q{2009-01-09}
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/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/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/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/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/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/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/orm_adapters/active_record_adapter/acts_as_authentic/config.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/perishability.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb", "lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb", "lib/authlogic/session/active_record_trickery.rb", "lib/authlogic/session/authenticates_many_association.rb", "lib/authlogic/session/base.rb", "lib/authlogic/session/callbacks.rb", "lib/authlogic/session/config.rb", "lib/authlogic/session/cookies.rb", "lib/authlogic/session/errors.rb", "lib/authlogic/session/params.rb", "lib/authlogic/session/perishability.rb", "lib/authlogic/session/scopes.rb", "lib/authlogic/session/session.rb", "lib/authlogic/session/timeout.rb", "lib/authlogic/testing/test_unit_helpers.rb", "lib/authlogic/version.rb", "lib/authlogic.rb", "Manifest", "MIT-LICENSE", "Rakefile", "README.rdoc", "shoulda_macros/authlogic.rb", "test/crypto_provider_tests/aes256_test.rb", "test/crypto_provider_tests/bcrypt_test.rb", "test/crypto_provider_tests/sha1_test.rb", "test/crypto_provider_tests/sha512_test.rb", "test/fixtures/companies.yml", "test/fixtures/employees.yml", "test/fixtures/projects.yml", "test/fixtures/users.yml", "test/libs/mock_controller.rb", "test/libs/mock_cookie_jar.rb", "test/libs/mock_request.rb", "test/libs/ordered_hash.rb", "test/libs/user.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/logged_in_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/perishability_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/persistence_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/session_maintenance_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/single_access_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/authenticates_many_test.rb", "test/session_tests/active_record_trickery_test.rb", "test/session_tests/authenticates_many_association_test.rb", "test/session_tests/base_test.rb", "test/session_tests/config_test.rb", "test/session_tests/cookies_test.rb", "test/session_tests/params_test.rb", "test/session_tests/perishability_test.rb", "test/session_tests/scopes_test.rb", "test/session_tests/session_test.rb", "test/session_tests/timeout_test.rb", "test/test_helper.rb", "authlogic.gemspec"]
14
14
  s.has_rdoc = true
15
15
  s.homepage = %q{http://github.com/binarylogic/authlogic}
16
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/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/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
@@ -33,6 +33,7 @@ require File.dirname(__FILE__) + "/authlogic/session/params"
33
33
  require File.dirname(__FILE__) + "/authlogic/session/perishability"
34
34
  require File.dirname(__FILE__) + "/authlogic/session/session"
35
35
  require File.dirname(__FILE__) + "/authlogic/session/scopes"
36
+ require File.dirname(__FILE__) + "/authlogic/session/timeout"
36
37
  require File.dirname(__FILE__) + "/authlogic/session/base"
37
38
 
38
39
  module Authlogic
@@ -45,6 +46,7 @@ module Authlogic
45
46
  include Perishability
46
47
  include Session
47
48
  include Scopes
49
+ include Timeout
48
50
  end
49
51
  end
50
52
  end
@@ -71,6 +71,11 @@ module Authlogic
71
71
  # Authlogic gives you a sepcial method for finding records by the perishable token (see Authlogic::ORMAdapters::ActiveRecordAdapter::ActcsAsAuthentic::Perishability). In this method
72
72
  # it checks for the age of the token. If the token is older than whatever you specify here, a record will NOT be returned. This way the tokens are perishable, thus making this system much
73
73
  # more secure.
74
+ #
75
+ # * <tt>disable_perishble_token_maintenance</tt> - default: false,
76
+ # Authlogic automatically maintains when to reset the perishable_token. This token should reset frequently because it is "perishable", but how frequent depends on your app.
77
+ # By default it tries to reset this token as much as possible, which is done via a before_validation callback. If for some reason you want to maintain this yourself just
78
+ # set this to true and use the reset_perishable_token and reset_perishable_token! methods to maintain it yourself.
74
79
  #
75
80
  # * <tt>persistence_field</tt> - default: :persistence_token, :remember_token, or :cookie_tokien, depending on which column is present,
76
81
  # defaults to :persistence_token if none are present,
@@ -27,6 +27,7 @@ module Authlogic
27
27
  named_scope :logged_out, lambda { {:conditions => ["last_request_at is NULL or last_request_at <= ?", #{options[:logged_in_timeout]}.seconds.ago]} }
28
28
 
29
29
  def logged_in?
30
+ raise "Can not determine the records login state because there is no last_request_at column" if !respond_to?(:last_request_at)
30
31
  !last_request_at.nil? && last_request_at > #{options[:logged_in_timeout]}.seconds.ago
31
32
  end
32
33
 
@@ -26,7 +26,7 @@ module Authlogic
26
26
  class_eval <<-"end_eval", __FILE__, __LINE__
27
27
  validates_uniqueness_of :#{options[:perishable_token_field]}, :if => :#{options[:perishable_token_field]}_changed?
28
28
 
29
- before_validation :reset_#{options[:perishable_token_field]}
29
+ before_validation :reset_#{options[:perishable_token_field]}, :unless => :disable_#{options[:perishable_token_field]}_maintenance?
30
30
 
31
31
  def self.find_using_#{options[:perishable_token_field]}(token, age = #{options[:perishable_token_valid_for]})
32
32
  return if token.blank?
@@ -51,6 +51,10 @@ module Authlogic
51
51
  reset_#{options[:perishable_token_field]}
52
52
  save_without_session_maintenance(false)
53
53
  end
54
+
55
+ def disable_#{options[:perishable_token_field]}_maintenance?
56
+ #{options[:disable_perishable_token_maintenance].inspect} == true
57
+ end
54
58
  end_eval
55
59
  end
56
60
  end
@@ -7,6 +7,8 @@ module Authlogic
7
7
  include Config
8
8
 
9
9
  class << self
10
+ attr_accessor :methods_configured
11
+
10
12
  # Returns true if a controller have been set and can be used properly. This MUST be set before anything can be done. Similar to how ActiveRecord won't allow you to do anything
11
13
  # without establishing a DB connection. In your framework environment this is done for you, but if you are using Authlogic outside of your frameword, you need to assign a controller
12
14
  # object to Authlogic via Authlogic::Session::Base.controller = obj.
@@ -190,12 +192,6 @@ module Authlogic
190
192
  find_with.each do |find_method|
191
193
  if send("valid_#{find_method}?")
192
194
  self.new_session = false
193
-
194
- 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)
195
- record.last_request_at = Time.now
196
- record.save_without_session_maintenance(false)
197
- end
198
-
199
195
  return record
200
196
  end
201
197
  end
@@ -353,25 +349,35 @@ module Authlogic
353
349
  self.class.controller
354
350
  end
355
351
 
352
+ # The goal with Authlogic is to feel as natural as possible. As a result, this method creates methods on the fly
353
+ # based on the configuration set. By default the configuration is based off of the columns names in the authenticating
354
+ # model. Thus allowing you to call user_session.username instead of user_session.login if you have a username column
355
+ # instead of a login column. Since class configuration can change during initialization it makes the most sense to enforce
356
+ # this configuration during the first initialization. At this point, all configuration should be set.
357
+ #
358
+ # Lastly, each method is defined individually to allow the user to provide their own "custom" method and this makes sure
359
+ # we don't replace their method.
356
360
  def create_configurable_methods!
357
- return if respond_to?(login_field) # already created these methods
361
+ return if self.class.methods_configured == true
362
+
363
+ self.class.send(:alias_method, klass_name.demodulize.underscore.to_sym, :record)
364
+ self.class.send(:attr_writer, login_field) if !respond_to?("#{login_field}=")
365
+ self.class.send(:attr_reader, login_field) if !respond_to?(login_field)
366
+ self.class.send(:attr_writer, password_field) if !respond_to?("#{password_field}=")
367
+ self.class.send(:define_method, password_field) {} if !respond_to?(password_field)
358
368
 
359
369
  self.class.class_eval <<-"end_eval", __FILE__, __LINE__
360
- alias_method :#{klass_name.demodulize.underscore}, :record
361
-
362
- attr_reader :#{login_field}
363
-
364
- def #{login_field}=(value)
370
+ def #{login_field}_with_authentication_flag=(value)
365
371
  self.authenticating_with = :password
366
- @#{login_field} = value
372
+ self.#{login_field}_without_authentication_flag = value
367
373
  end
374
+ alias_method_chain :#{login_field}=, :authentication_flag
368
375
 
369
- def #{password_field}=(value)
376
+ def #{password_field}_with_authentication_flag=(value)
370
377
  self.authenticating_with = :password
371
- @#{password_field} = value
378
+ self.#{password_field}_without_authentication_flag = value
372
379
  end
373
-
374
- def #{password_field}; end
380
+ alias_method_chain :#{password_field}=, :authentication_flag
375
381
 
376
382
  private
377
383
  # The password should not be accessible publicly. This way forms using form_for don't fill the password with the attempted password. The prevent this we just create this method that is private.
@@ -379,6 +385,8 @@ module Authlogic
379
385
  @#{password_field}
380
386
  end
381
387
  end_eval
388
+
389
+ self.class.methods_configured = true
382
390
  end
383
391
 
384
392
  def klass
@@ -176,6 +176,26 @@ module Authlogic
176
176
  end
177
177
  alias_method :login_field=, :login_field
178
178
 
179
+ # With acts_as_authentic you get a :logged_in_timeout configuration option. If this is set, after this amount of time has passed the user
180
+ # will be marked as logged out. Obviously, since web based apps are on a per request basis, we have to define a time limit threshold that
181
+ # determines when we consider a user to be "logged out". Meaning, if they login and then leave the website, when do mark them as logged out?
182
+ # I recommend just using this as a fun feature on your website or reports, giving you a ballpark number of users logged in and active. This is
183
+ # not meant to be a dead accurate representation of a users logged in state, since there is really no real way to do this with web based apps.
184
+ #
185
+ # That being said, you can use that feature to require a login if their session timesout. Similar to how financial sites work. Just set this option to
186
+ # true and if your record returns true for logged_out? then they will be required to log back in.
187
+ #
188
+ # * <tt>Default:</tt> false
189
+ # * <tt>Accepts:</tt> Boolean
190
+ def logout_on_timeout(value = nil)
191
+ if value.nil?
192
+ read_inheritable_attribute(:logout_on_timeout) || logout_on_timeout(false)
193
+ else
194
+ write_inheritable_attribute(:logout_on_timeout, value)
195
+ end
196
+ end
197
+ alias_method :logout_on_timeout=, :logout_on_timeout
198
+
179
199
  # The error message used when the record returns false to active?
180
200
  #
181
201
  # * <tt>Default:</tt> "Your account is not active"
@@ -315,7 +335,7 @@ module Authlogic
315
335
  # Specify a list of allowed request types and single access authentication will only be allowed for the ones you specify. Checkout the "Single Access / Private Feeds Access" section in the README.
316
336
  #
317
337
  # * <tt>Default:</tt> "application/rss+xml", "application/atom+xml"
318
- # * <tt>Accepts:</tt> String, or :all to allow single access authentication for any and all request types
338
+ # * <tt>Accepts:</tt> String of request type, or :all to allow single access authentication for any and all request types
319
339
  def single_access_allowed_request_types(*values)
320
340
  if values.blank?
321
341
  read_inheritable_attribute(:single_access_allowed_request_types) || single_access_allowed_request_types("application/rss+xml", "application/atom+xml")
@@ -376,6 +396,10 @@ module Authlogic
376
396
  self.class.login_field
377
397
  end
378
398
 
399
+ def logout_on_timeout?
400
+ self.class.logout_on_timeout == true
401
+ end
402
+
379
403
  def not_active_message
380
404
  self.class.not_active_message
381
405
  end
@@ -13,10 +13,10 @@ module Authlogic
13
13
  def valid_cookie?
14
14
  if cookie_credentials
15
15
  self.unauthorized_record = search_for_record("find_by_#{persistence_token_field}", cookie_credentials)
16
- return valid?
16
+ valid? && !stale?
17
+ else
18
+ false
17
19
  end
18
-
19
- false
20
20
  end
21
21
 
22
22
  private
@@ -12,14 +12,14 @@ module Authlogic
12
12
  module Params
13
13
  # Tries to validate the session from information in the params token
14
14
  def valid_params?
15
- if params_credentials && single_access_token_field && single_access_allowed_request_types.include?(controller.request_content_type)
15
+ if params_credentials && single_access_token_field && (single_access_allowed_request_types.include?(controller.request_content_type) || single_access_allowed_request_types.include?(:all))
16
16
  self.unauthorized_record = search_for_record("find_by_#{single_access_token_field}", params_credentials)
17
17
  self.persisting = false
18
18
  return true if valid?
19
19
  self.persisting = true
20
+ else
21
+ false
20
22
  end
21
-
22
- false
23
23
  end
24
24
 
25
25
  private
@@ -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}!")
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
@@ -25,10 +25,10 @@ module Authlogic
25
25
  self.unauthorized_record = record
26
26
  end
27
27
  end
28
- return valid?
28
+ valid? && !stale?
29
+ else
30
+ false
29
31
  end
30
-
31
- false
32
32
  end
33
33
 
34
34
  private
@@ -0,0 +1,28 @@
1
+ module Authlogic
2
+ module Session
3
+ # = Timeout
4
+ #
5
+ # This is reponsibile for determining if the session is stale or fresh. It is also responsible for maintaining the last_request_at value if the column is present.
6
+ #
7
+ # Think about how financial websites work. If you are inactive after a certain period of time you must log back in. By default this is disabled, but if enabled this
8
+ # module kicks in. See the logout_on_timeout configuration option for how to turn this on.
9
+ module Timeout
10
+ def self.included(klass)
11
+ klass.after_find :update_last_request_at!
12
+ klass.after_save :update_last_request_at!
13
+ end
14
+
15
+ def stale?
16
+ logout_on_timeout? && record && record.logged_out?
17
+ end
18
+
19
+ private
20
+ def update_last_request_at!
21
+ 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)
22
+ record.last_request_at = Time.now
23
+ record.save_without_session_maintenance(false)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -44,7 +44,7 @@ module Authlogic # :nodoc:
44
44
 
45
45
  MAJOR = 1
46
46
  MINOR = 3
47
- TINY = 8
47
+ TINY = 9
48
48
 
49
49
  # The current version as a Version instance
50
50
  CURRENT = new(MAJOR, MINOR, TINY)
@@ -2,9 +2,10 @@ require "test/unit"
2
2
 
3
3
  module Authlogic
4
4
  module ShouldaMacros
5
- def should_be_authentic(model)
5
+ def should_be_authentic
6
+ klass = model_class
6
7
  should "acts as authentic" do
7
- assert model.respond_to?(:acts_as_authentic_config)
8
+ assert klass.respond_to?(:acts_as_authentic_config)
8
9
  end
9
10
  end
10
11
  end
@@ -112,6 +112,16 @@ module ORMAdaptersTests
112
112
  #assert !user.errors.on(:password)
113
113
  end
114
114
 
115
+ def test_disable_perishable_token_maintenance
116
+ ben = users(:ben)
117
+ assert !ben.disable_perishable_token_maintenance?
118
+ User.acts_as_authentic(:disable_perishable_token_maintenance => true)
119
+ assert ben.disable_perishable_token_maintenance?
120
+ old_perishable_token = ben.perishable_token
121
+ assert ben.valid?
122
+ assert_equal old_perishable_token, ben.perishable_token
123
+ end
124
+
115
125
  private
116
126
  def get_default_configuration
117
127
  @default_configuration = User.acts_as_authentic_config
@@ -48,22 +48,6 @@ module SessionTests
48
48
  set_session_for(ben)
49
49
  session = UserSession.find
50
50
  assert session
51
- assert !session.record.last_request_at.nil?
52
-
53
- UserSession.last_request_at_threshold = 2.seconds
54
- assert_equal 2.seconds, UserSession.last_request_at_threshold
55
-
56
- assert UserSession.find
57
- last_request_at = ben.reload.last_request_at
58
- sleep(0.5)
59
- assert UserSession.find
60
- assert_equal last_request_at, ben.reload.last_request_at
61
- sleep(2)
62
- assert UserSession.find
63
- assert_not_equal last_request_at, ben.reload.last_request_at
64
-
65
- UserSession.last_request_at_threshold 0
66
- assert_equal 0, UserSession.last_request_at_threshold
67
51
  end
68
52
 
69
53
  def test_klass
@@ -102,6 +102,7 @@ module SessionTests
102
102
  end
103
103
 
104
104
  def test_login_field
105
+ UserSession.methods_configured = false
105
106
  UserSession.login_field = :saweet
106
107
  assert_equal :saweet, UserSession.login_field
107
108
  session = UserSession.new
@@ -176,6 +177,7 @@ module SessionTests
176
177
  end
177
178
 
178
179
  def test_password_field
180
+ UserSession.methods_configured = false
179
181
  UserSession.password_field = :saweet
180
182
  assert_equal :saweet, UserSession.password_field
181
183
  session = UserSession.new
@@ -0,0 +1,48 @@
1
+ require File.dirname(__FILE__) + '/../test_helper.rb'
2
+
3
+ module SessionTests
4
+ class TimeoutTest < ActiveSupport::TestCase
5
+ def test_after_find
6
+ ben = users(:ben)
7
+ set_session_for(ben)
8
+ session = UserSession.find
9
+ assert session
10
+ assert !session.record.last_request_at.nil?
11
+
12
+ UserSession.last_request_at_threshold = 2.seconds
13
+ assert_equal 2.seconds, UserSession.last_request_at_threshold
14
+
15
+ assert UserSession.find
16
+ last_request_at = ben.reload.last_request_at
17
+ sleep(0.5)
18
+ assert UserSession.find
19
+ assert_equal last_request_at, ben.reload.last_request_at
20
+ sleep(2)
21
+ assert UserSession.find
22
+ assert_not_equal last_request_at, ben.reload.last_request_at
23
+
24
+ UserSession.last_request_at_threshold 0
25
+ assert_equal 0, UserSession.last_request_at_threshold
26
+ end
27
+
28
+ def test_after_save
29
+ ben = users(:ben)
30
+ session = UserSession.new(ben)
31
+ assert session.save
32
+ assert !session.record.last_request_at.nil?
33
+ assert !session.stale?
34
+ end
35
+
36
+ def test_stale
37
+ UserSession.logout_on_timeout = true
38
+ ben = users(:ben)
39
+ ben.update_attribute(:last_request_at, Time.now)
40
+ set_session_for(ben)
41
+ session = UserSession.find
42
+ assert !session.stale?
43
+ session.record.last_request_at = 3.years.ago
44
+ assert session.stale?
45
+ UserSession.logout_on_timeout = false
46
+ end
47
+ end
48
+ end
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.3.8
4
+ version: 1.3.9
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: 2008-12-24 00:00:00 -06:00
12
+ date: 2009-01-09 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -77,6 +77,7 @@ extra_rdoc_files:
77
77
  - lib/authlogic/session/perishability.rb
78
78
  - lib/authlogic/session/scopes.rb
79
79
  - lib/authlogic/session/session.rb
80
+ - lib/authlogic/session/timeout.rb
80
81
  - lib/authlogic/testing/test_unit_helpers.rb
81
82
  - lib/authlogic/version.rb
82
83
  - lib/authlogic.rb
@@ -113,6 +114,7 @@ files:
113
114
  - lib/authlogic/session/perishability.rb
114
115
  - lib/authlogic/session/scopes.rb
115
116
  - lib/authlogic/session/session.rb
117
+ - lib/authlogic/session/timeout.rb
116
118
  - lib/authlogic/testing/test_unit_helpers.rb
117
119
  - lib/authlogic/version.rb
118
120
  - lib/authlogic.rb
@@ -151,6 +153,7 @@ files:
151
153
  - test/session_tests/perishability_test.rb
152
154
  - test/session_tests/scopes_test.rb
153
155
  - test/session_tests/session_test.rb
156
+ - test/session_tests/timeout_test.rb
154
157
  - test/test_helper.rb
155
158
  - authlogic.gemspec
156
159
  has_rdoc: true
@@ -206,4 +209,5 @@ test_files:
206
209
  - test/session_tests/perishability_test.rb
207
210
  - test/session_tests/scopes_test.rb
208
211
  - test/session_tests/session_test.rb
212
+ - test/session_tests/timeout_test.rb
209
213
  - test/test_helper.rb