authlogic 1.4.3 → 2.0.0
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 +19 -0
- data/Manifest.txt +111 -0
- data/README.rdoc +116 -389
- data/Rakefile +14 -7
- data/lib/authlogic.rb +33 -35
- data/lib/authlogic/acts_as_authentic/base.rb +91 -0
- data/lib/authlogic/acts_as_authentic/email.rb +77 -0
- data/lib/authlogic/acts_as_authentic/logged_in_status.rb +54 -0
- data/lib/authlogic/acts_as_authentic/login.rb +65 -0
- data/lib/authlogic/acts_as_authentic/magic_columns.rb +24 -0
- data/lib/authlogic/acts_as_authentic/password.rb +215 -0
- data/lib/authlogic/acts_as_authentic/perishable_token.rb +100 -0
- data/lib/authlogic/acts_as_authentic/persistence_token.rb +66 -0
- data/lib/authlogic/acts_as_authentic/restful_authentication.rb +60 -0
- data/lib/authlogic/acts_as_authentic/session_maintenance.rb +127 -0
- data/lib/authlogic/acts_as_authentic/single_access_token.rb +58 -0
- data/lib/authlogic/acts_as_authentic/validations_scope.rb +32 -0
- data/lib/authlogic/{session/authenticates_many_association.rb → authenticates_many/association.rb} +10 -6
- data/lib/authlogic/authenticates_many/base.rb +55 -0
- data/lib/authlogic/controller_adapters/abstract_adapter.rb +2 -3
- data/lib/authlogic/controller_adapters/merb_adapter.rb +0 -4
- data/lib/authlogic/controller_adapters/rails_adapter.rb +0 -4
- data/lib/authlogic/crypto_providers/aes256.rb +0 -2
- data/lib/authlogic/crypto_providers/bcrypt.rb +0 -2
- data/lib/authlogic/crypto_providers/md5.rb +34 -0
- data/lib/authlogic/crypto_providers/sha1.rb +0 -2
- data/lib/authlogic/crypto_providers/sha512.rb +1 -3
- data/lib/authlogic/i18n.rb +1 -4
- data/lib/authlogic/random.rb +33 -0
- data/lib/authlogic/session/activation.rb +56 -0
- data/lib/authlogic/session/active_record_trickery.rb +15 -7
- data/lib/authlogic/session/base.rb +31 -456
- data/lib/authlogic/session/brute_force_protection.rb +50 -27
- data/lib/authlogic/session/callbacks.rb +24 -15
- data/lib/authlogic/session/cookies.rb +108 -22
- data/lib/authlogic/session/existence.rb +89 -0
- data/lib/authlogic/session/foundation.rb +63 -0
- data/lib/authlogic/session/http_auth.rb +23 -0
- data/lib/authlogic/session/id.rb +41 -0
- data/lib/authlogic/session/klass.rb +75 -0
- data/lib/authlogic/session/magic_columns.rb +75 -0
- data/lib/authlogic/session/magic_states.rb +58 -0
- data/lib/authlogic/session/params.rb +82 -19
- data/lib/authlogic/session/password.rb +156 -0
- data/lib/authlogic/session/{perishability.rb → perishable_token.rb} +4 -4
- data/lib/authlogic/session/persistence.rb +70 -0
- data/lib/authlogic/session/priority_record.rb +34 -0
- data/lib/authlogic/session/scopes.rb +57 -53
- data/lib/authlogic/session/session.rb +46 -31
- data/lib/authlogic/session/timeout.rb +65 -31
- data/lib/authlogic/session/unauthorized_record.rb +50 -0
- data/lib/authlogic/session/validation.rb +76 -0
- data/lib/authlogic/testing/test_unit_helpers.rb +3 -3
- data/lib/authlogic/version.rb +3 -3
- data/test/acts_as_authentic_test/base_test.rb +12 -0
- data/test/acts_as_authentic_test/email_test.rb +79 -0
- data/test/acts_as_authentic_test/logged_in_status_test.rb +36 -0
- data/test/acts_as_authentic_test/login_test.rb +79 -0
- data/test/acts_as_authentic_test/magic_columns_test.rb +27 -0
- data/test/acts_as_authentic_test/password_test.rb +212 -0
- data/test/acts_as_authentic_test/perishable_token_test.rb +56 -0
- data/test/acts_as_authentic_test/persistence_token_test.rb +55 -0
- data/test/acts_as_authentic_test/session_maintenance_test.rb +68 -0
- data/test/acts_as_authentic_test/single_access_test.rb +39 -0
- data/test/authenticates_many_test.rb +16 -0
- data/test/{crypto_provider_tests → crypto_provider_test}/aes256_test.rb +1 -1
- data/test/{crypto_provider_tests → crypto_provider_test}/bcrypt_test.rb +1 -1
- data/test/{crypto_provider_tests → crypto_provider_test}/sha1_test.rb +1 -1
- data/test/{crypto_provider_tests → crypto_provider_test}/sha512_test.rb +1 -1
- data/test/fixtures/employees.yml +4 -4
- data/test/fixtures/users.yml +6 -6
- data/test/libs/company.rb +6 -0
- data/test/libs/employee.rb +7 -0
- data/test/libs/employee_session.rb +2 -0
- data/test/libs/project.rb +3 -0
- data/test/libs/user_session.rb +2 -0
- data/test/random_test.rb +49 -0
- data/test/session_test/activation_test.rb +43 -0
- data/test/session_test/active_record_trickery_test.rb +26 -0
- data/test/session_test/brute_force_protection_test.rb +76 -0
- data/test/session_test/callbacks_test.rb +6 -0
- data/test/session_test/cookies_test.rb +107 -0
- data/test/session_test/credentials_test.rb +0 -0
- data/test/session_test/existence_test.rb +64 -0
- data/test/session_test/http_auth_test.rb +16 -0
- data/test/session_test/id_test.rb +17 -0
- data/test/session_test/klass_test.rb +35 -0
- data/test/session_test/magic_columns_test.rb +59 -0
- data/test/session_test/magic_states_test.rb +60 -0
- data/test/session_test/params_test.rb +53 -0
- data/test/session_test/password_test.rb +84 -0
- data/test/{session_tests → session_test}/perishability_test.rb +1 -1
- data/test/session_test/persistence_test.rb +21 -0
- data/test/{session_tests → session_test}/scopes_test.rb +2 -3
- data/test/session_test/session_test.rb +59 -0
- data/test/session_test/timeout_test.rb +43 -0
- data/test/session_test/unauthorized_record_test.rb +13 -0
- data/test/session_test/validation_test.rb +23 -0
- data/test/test_helper.rb +14 -29
- metadata +120 -112
- data/Manifest +0 -76
- data/authlogic.gemspec +0 -38
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/base.rb +0 -22
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb +0 -238
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb +0 -155
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb +0 -51
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/perishability.rb +0 -71
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb +0 -94
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb +0 -87
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb +0 -61
- data/lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb +0 -58
- data/lib/authlogic/session/config.rb +0 -421
- data/lib/authlogic/session/errors.rb +0 -18
- data/lib/authlogic/session/record_info.rb +0 -24
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb +0 -154
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb +0 -157
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/logged_in_test.rb +0 -24
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/perishability_test.rb +0 -41
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/persistence_test.rb +0 -54
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/session_maintenance_test.rb +0 -62
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/single_access_test.rb +0 -41
- data/test/orm_adapters_tests/active_record_adapter_tests/authenticates_many_test.rb +0 -32
- data/test/session_tests/active_record_trickery_test.rb +0 -14
- data/test/session_tests/authenticates_many_association_test.rb +0 -28
- data/test/session_tests/base_test.rb +0 -307
- data/test/session_tests/brute_force_protection_test.rb +0 -53
- data/test/session_tests/config_test.rb +0 -184
- data/test/session_tests/cookies_test.rb +0 -32
- data/test/session_tests/params_test.rb +0 -32
- data/test/session_tests/session_test.rb +0 -45
- data/test/session_tests/timeout_test.rb +0 -71
@@ -1,17 +1,17 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session
|
3
|
-
# = Perishability
|
4
|
-
#
|
5
3
|
# Maintains the perishable token, which is helpful for confirming records or authorizing records to reset their password. All that this
|
6
4
|
# module does is reset it after a session have been saved, just keep it changing. The more it changes, the tighter the security.
|
7
|
-
|
5
|
+
#
|
6
|
+
# See Authlogic::ActsAsAuthentic::PerishableToken for more information.
|
7
|
+
module PerishableToken
|
8
8
|
def self.included(klass)
|
9
9
|
klass.after_save :reset_perishable_token!
|
10
10
|
end
|
11
11
|
|
12
12
|
private
|
13
13
|
def reset_perishable_token!
|
14
|
-
record.
|
14
|
+
record.reset_perishable_token if record.respond_to?(:reset_perishable_token) && !record.disable_perishable_token_maintenance?
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Authlogic
|
2
|
+
module Session
|
3
|
+
# Responsible for allowing you to persist your sessions.
|
4
|
+
module Persistence
|
5
|
+
def self.included(klass)
|
6
|
+
klass.class_eval do
|
7
|
+
extend ClassMethods
|
8
|
+
include InstanceMethods
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
# This is how you persist a session. This finds the record for the current session using
|
14
|
+
# a variety of methods. It basically tries to "log in" the user without the user having
|
15
|
+
# to explicitly log in. Check out the other Authlogic::Session modules for more information.
|
16
|
+
#
|
17
|
+
# The best way to use this method is something like:
|
18
|
+
#
|
19
|
+
# helper_method :current_user_session, :current_user
|
20
|
+
#
|
21
|
+
# def current_user_session
|
22
|
+
# return @current_user_session if defined?(@current_user_session)
|
23
|
+
# @current_user_session = UserSession.find
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# def current_user
|
27
|
+
# return @current_user if defined?(@current_user)
|
28
|
+
# @current_user = current_user_session && current_user_session.user
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# Also, this method accepts a single parameter as the id, to find session that you marked with an id:
|
32
|
+
#
|
33
|
+
# UserSession.find(:secure)
|
34
|
+
#
|
35
|
+
# See the id method for more information on ids.
|
36
|
+
def find(id = nil, priority_record = nil)
|
37
|
+
session = new({:priority_record => priority_record}, id)
|
38
|
+
session.priority_record = priority_record
|
39
|
+
if session.persisting?
|
40
|
+
session
|
41
|
+
else
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module InstanceMethods
|
48
|
+
# Let's you know if the session is being persisted or not, meaning the user does not have to explicitly log in
|
49
|
+
# in order to be logged in. If the session has no associated record, it will try to find a record and persis
|
50
|
+
# the session. This is the method that the class level method find uses to ultimately persist the session.
|
51
|
+
def persisting?
|
52
|
+
return true if !record.nil?
|
53
|
+
self.attempted_record = nil
|
54
|
+
before_persisting
|
55
|
+
persist
|
56
|
+
ensure_authentication_attempted
|
57
|
+
if errors.empty? && !attempted_record.nil?
|
58
|
+
self.record = attempted_record
|
59
|
+
after_persisting
|
60
|
+
save_record
|
61
|
+
self.new_session = false
|
62
|
+
true
|
63
|
+
else
|
64
|
+
false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Authlogic
|
2
|
+
module Session
|
3
|
+
# The point of this module is to avoid the StaleObjectError raised when lock_version is implemented in ActiveRecord.
|
4
|
+
# We accomplish this by using a "priority record". Meaning this record is used if possible, it gets priority.
|
5
|
+
# This way we don't save a record behind the scenes thus making an object being used stale.
|
6
|
+
module PriorityRecord
|
7
|
+
def self.included(klass)
|
8
|
+
klass.class_eval do
|
9
|
+
attr_accessor :priority_record
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Setting priority record if it is passed. The only way it can be passed is through an array:
|
14
|
+
#
|
15
|
+
# session.credentials = [real_user_object, priority_user_object]
|
16
|
+
def credentials=(value)
|
17
|
+
super
|
18
|
+
values = value.is_a?(Array) ? value : [value]
|
19
|
+
self.priority_record = values.second if values.second.class < ::ActiveRecord::Base
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def attempted_record=(value)
|
24
|
+
value = priority_record if value == priority_record
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
def save_record(alternate_record = nil)
|
29
|
+
r = alternate_record || record
|
30
|
+
super if r != priority_record
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,55 +1,15 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session
|
3
|
-
#
|
3
|
+
# Authentication can be scoped, and it's easy, you just need to define how you want to scope everything. This should help you:
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# What with_scopes focuses on is scoping the query when finding the object and the name of the cookie / session. It works very similar to
|
8
|
-
# ActiveRecord::Base#with_scopes. It accepts a hash with any of the following options:
|
9
|
-
#
|
10
|
-
# * <tt>find_options:</tt> any options you can pass into ActiveRecord::Base.find. This is used when trying to find the record.
|
11
|
-
# * <tt>id:</tt> The id of the session, this gets merged with the real id. For information ids see the id method.
|
12
|
-
#
|
13
|
-
# Here is how you use it:
|
14
|
-
#
|
15
|
-
# UserSession.with_scope(:find_options => {:conditions => "account_id = 2"}, :id => "account_2") do
|
16
|
-
# UserSession.find
|
17
|
-
# end
|
18
|
-
#
|
19
|
-
# Eseentially what the above does is scope the searching of the object with the sql you provided. So instead of:
|
20
|
-
#
|
21
|
-
# User.find(:first, :conditions => "login = 'ben'")
|
22
|
-
#
|
23
|
-
# it would be:
|
24
|
-
#
|
25
|
-
# User.find(:first, :conditions => "login = 'ben' and account_id = 2")
|
26
|
-
#
|
27
|
-
# You will also notice the :id option. This works just like the id method. It scopes your cookies. So the name of your cookie will be:
|
28
|
-
#
|
29
|
-
# account_2_user_credentials
|
30
|
-
#
|
31
|
-
# instead of:
|
32
|
-
#
|
33
|
-
# user_credentials
|
34
|
-
#
|
35
|
-
# What is also nifty about scoping with an :id is that it merges your id's. So if you do:
|
36
|
-
#
|
37
|
-
# UserSession.with_scope(:find_options => {:conditions => "account_id = 2"}, :id => "account_2") do
|
38
|
-
# session = UserSession.new
|
39
|
-
# session.id = :secure
|
40
|
-
# end
|
41
|
-
#
|
42
|
-
# The name of your cookies will be:
|
43
|
-
#
|
44
|
-
# secure_account_2_user_credentials
|
5
|
+
# 1. Want to scope by a parent object? Ex: An account has many users. Checkout Authlogic::AuthenticatesMany
|
6
|
+
# 2. Want to scope the validations in your model? Ex: 2 users can have the same login under different accounts. See Authlogic::ActsAsAuthentic::Scope
|
45
7
|
module Scopes # :nodoc:
|
46
8
|
def self.included(klass)
|
47
|
-
klass.extend(ClassMethods)
|
48
|
-
klass.send(:include, InstanceMethods)
|
49
9
|
klass.class_eval do
|
10
|
+
extend ClassMethods
|
11
|
+
include InstanceMethods
|
50
12
|
attr_writer :scope
|
51
|
-
alias_method_chain :initialize, :scopes
|
52
|
-
alias_method_chain :search_for_record, :scopes
|
53
13
|
end
|
54
14
|
end
|
55
15
|
|
@@ -60,7 +20,44 @@ module Authlogic
|
|
60
20
|
Thread.current[:authlogic_scope]
|
61
21
|
end
|
62
22
|
|
63
|
-
#
|
23
|
+
# What with_scopes focuses on is scoping the query when finding the object and the name of the cookie / session. It works very similar to
|
24
|
+
# ActiveRecord::Base#with_scopes. It accepts a hash with any of the following options:
|
25
|
+
#
|
26
|
+
# * <tt>find_options:</tt> any options you can pass into ActiveRecord::Base.find. This is used when trying to find the record.
|
27
|
+
# * <tt>id:</tt> The id of the session, this gets merged with the real id. For information ids see the id method.
|
28
|
+
#
|
29
|
+
# Here is how you use it:
|
30
|
+
#
|
31
|
+
# UserSession.with_scope(:find_options => {:conditions => "account_id = 2"}, :id => "account_2") do
|
32
|
+
# UserSession.find
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# Eseentially what the above does is scope the searching of the object with the sql you provided. So instead of:
|
36
|
+
#
|
37
|
+
# User.find(:first, :conditions => "login = 'ben'")
|
38
|
+
#
|
39
|
+
# it would be:
|
40
|
+
#
|
41
|
+
# User.find(:first, :conditions => "login = 'ben' and account_id = 2")
|
42
|
+
#
|
43
|
+
# You will also notice the :id option. This works just like the id method. It scopes your cookies. So the name of your cookie will be:
|
44
|
+
#
|
45
|
+
# account_2_user_credentials
|
46
|
+
#
|
47
|
+
# instead of:
|
48
|
+
#
|
49
|
+
# user_credentials
|
50
|
+
#
|
51
|
+
# What is also nifty about scoping with an :id is that it merges your id's. So if you do:
|
52
|
+
#
|
53
|
+
# UserSession.with_scope(:find_options => {:conditions => "account_id = 2"}, :id => "account_2") do
|
54
|
+
# session = UserSession.new
|
55
|
+
# session.id = :secure
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# The name of your cookies will be:
|
59
|
+
#
|
60
|
+
# secure_account_2_user_credentials
|
64
61
|
def with_scope(options = {}, &block)
|
65
62
|
raise ArgumentError.new("You must provide a block") unless block_given?
|
66
63
|
self.scope = options
|
@@ -76,21 +73,28 @@ module Authlogic
|
|
76
73
|
end
|
77
74
|
|
78
75
|
module InstanceMethods
|
79
|
-
|
76
|
+
# Setting the scope if it exists upon instantiation.
|
77
|
+
def initialize(*args)
|
80
78
|
self.scope = self.class.scope
|
81
|
-
|
79
|
+
super
|
82
80
|
end
|
83
81
|
|
84
|
-
#
|
82
|
+
# The scope of the current object
|
85
83
|
def scope
|
86
84
|
@scope ||= {}
|
87
85
|
end
|
88
86
|
|
89
|
-
|
90
|
-
|
91
|
-
|
87
|
+
private
|
88
|
+
# Used for things like cookie_key, session_key, etc.
|
89
|
+
def build_key(last_part)
|
90
|
+
[scope[:id], super].compact.join("_")
|
91
|
+
end
|
92
|
+
|
93
|
+
def search_for_record(*args)
|
94
|
+
klass.send(:with_scope, :find => (scope[:find_options] || {})) do
|
95
|
+
klass.send(*args)
|
96
|
+
end
|
92
97
|
end
|
93
|
-
end
|
94
98
|
end
|
95
99
|
end
|
96
100
|
end
|
@@ -1,45 +1,60 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session
|
3
|
-
# = Session
|
4
|
-
#
|
5
3
|
# Handles all parts of authentication that deal with sessions. Such as persisting a session and saving / destroy a session.
|
6
4
|
module Session
|
7
5
|
def self.included(klass)
|
8
|
-
klass.
|
9
|
-
|
10
|
-
|
6
|
+
klass.class_eval do
|
7
|
+
extend Config
|
8
|
+
include InstanceMethods
|
9
|
+
persist :persist_by_session
|
10
|
+
after_save :update_session
|
11
|
+
after_destroy :update_session
|
12
|
+
after_persisting :update_session, :unless => :single_access?
|
13
|
+
end
|
11
14
|
end
|
12
15
|
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
# For backwards compatibility, will eventually be removed, just need to let the sessions update theirself
|
22
|
-
record = search_for_record("find_by_#{persistence_token_field}", persistence_token)
|
23
|
-
if record
|
24
|
-
controller.session["#{session_key}_id"] = record.send(record.class.primary_key)
|
25
|
-
self.unauthorized_record = record
|
26
|
-
end
|
27
|
-
end
|
28
|
-
valid?
|
29
|
-
else
|
30
|
-
false
|
16
|
+
# Configuration for the session feature.
|
17
|
+
module Config
|
18
|
+
# Works exactly like cookie_key, but for sessions. See cookie_key for more info.
|
19
|
+
#
|
20
|
+
# * <tt>Default:</tt> cookie_key
|
21
|
+
# * <tt>Accepts:</tt> Symbol or String
|
22
|
+
def session_key(value = nil)
|
23
|
+
config(:session_key, value, cookie_key)
|
31
24
|
end
|
25
|
+
alias_method :session_key=, :session_key
|
32
26
|
end
|
33
27
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
28
|
+
# Instance methods for the session feature.
|
29
|
+
module InstanceMethods
|
30
|
+
private
|
31
|
+
# Tries to validate the session from information in the session
|
32
|
+
def persist_by_session
|
33
|
+
persistence_token, record_id = session_credentials
|
34
|
+
if !persistence_token.nil?
|
35
|
+
# Allow finding by persistence token, because when records are created the session is maintained in a before_save, when there is no id.
|
36
|
+
# This is done for performance reasons and to save on queries.
|
37
|
+
record = record_id.nil? ? search_for_record("find_by_persistence_token", persistence_token) : search_for_record("find_by_#{klass.primary_key}", record_id)
|
38
|
+
self.unauthorized_record = record if record && record.persistence_token == persistence_token
|
39
|
+
valid?
|
40
|
+
else
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def session_credentials
|
46
|
+
[controller.session[session_key], controller.session["#{session_key}_#{klass.primary_key}"]].compact
|
47
|
+
end
|
48
|
+
|
49
|
+
def session_key
|
50
|
+
build_key(self.class.session_key)
|
51
|
+
end
|
38
52
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
53
|
+
def update_session
|
54
|
+
controller.session[session_key] = record && record.persistence_token
|
55
|
+
controller.session["#{session_key}_#{klass.primary_key}"] = record && record.send(record.class.primary_key)
|
56
|
+
end
|
57
|
+
end
|
43
58
|
end
|
44
59
|
end
|
45
60
|
end
|
@@ -1,48 +1,82 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session
|
3
|
-
#
|
3
|
+
# Think about financial websites, if you are inactive for a certain period of time you will be asked to
|
4
|
+
# log back in on your next request. You can do this with Authlogic easily, there are 2 parts to this:
|
4
5
|
#
|
5
|
-
#
|
6
|
+
# 1. Define the timeout threshold:
|
6
7
|
#
|
7
|
-
#
|
8
|
-
#
|
8
|
+
# acts_as_authentic do |c|
|
9
|
+
# c.logged_in_timeout = 10.minutes # default is 10.minutes
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# 2. Enable logging out on timeouts
|
13
|
+
#
|
14
|
+
# class UserSession < Authlogic::Session::Base
|
15
|
+
# logout_on_timeout true # default if false
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# This will require a user to log back in if they are inactive for more than 10 minutes. In order for
|
19
|
+
# this feature to be used you must have a last_request_at datetime column in your table for whatever model
|
20
|
+
# you are authenticating with.
|
9
21
|
module Timeout
|
10
22
|
def self.included(klass)
|
11
23
|
klass.class_eval do
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
24
|
+
extend Config
|
25
|
+
include InstanceMethods
|
26
|
+
before_persisting :reset_stale_state
|
27
|
+
after_persisting :enforce_timeout
|
28
|
+
attr_accessor :stale_record
|
16
29
|
end
|
17
30
|
end
|
18
31
|
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
if
|
24
|
-
|
25
|
-
|
32
|
+
# Configuration for the timeout feature.
|
33
|
+
module Config
|
34
|
+
# 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
|
35
|
+
# 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
|
36
|
+
# 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?
|
37
|
+
# 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
|
38
|
+
# 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.
|
39
|
+
# Think about a user that logs in and doesn't log out. There is no action that tells you that the user isn't technically still logged in and
|
40
|
+
# active.
|
41
|
+
#
|
42
|
+
# That being said, you can use that feature to require a new login if their session timesout. Similar to how financial sites work. Just set this option to
|
43
|
+
# true and if your record returns true for stale? then they will be required to log back in.
|
44
|
+
#
|
45
|
+
# Lastly, UserSession.find will still return a object is the session is stale, but you will not get a record. This allows you to determine if the
|
46
|
+
# user needs to log back in because their session went stale, or because they just aren't logged in. Just call current_user_session.stale? as your flag.
|
47
|
+
#
|
48
|
+
# * <tt>Default:</tt> false
|
49
|
+
# * <tt>Accepts:</tt> Boolean
|
50
|
+
def logout_on_timeout(value = nil)
|
51
|
+
config(:logout_on_timeout, value, false)
|
26
52
|
end
|
27
|
-
|
53
|
+
alias_method :logout_on_timeout=, :logout_on_timeout
|
28
54
|
end
|
29
|
-
|
30
|
-
#
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
private
|
37
|
-
def reset_stale_state
|
38
|
-
@stale = nil
|
55
|
+
|
56
|
+
# Instance methods for the timeout feature.
|
57
|
+
module InstanceMethods
|
58
|
+
# 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.
|
59
|
+
# 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.
|
60
|
+
def stale?
|
61
|
+
!stale_record.nil? || (logout_on_timeout? && record && record.logged_out?)
|
39
62
|
end
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
63
|
+
|
64
|
+
private
|
65
|
+
def reset_stale_state
|
66
|
+
self.stale_record = nil
|
44
67
|
end
|
45
|
-
|
68
|
+
|
69
|
+
def enforce_timeout
|
70
|
+
if stale?
|
71
|
+
self.stale_record = record
|
72
|
+
self.record = nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def logout_on_timeout?
|
77
|
+
self.class.logout_on_timeout == true
|
78
|
+
end
|
79
|
+
end
|
46
80
|
end
|
47
81
|
end
|
48
82
|
end
|