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,12 +1,10 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session
|
3
|
-
# = Brute Force Protection
|
4
|
-
#
|
5
3
|
# 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
4
|
# generally combated with a slow hasing algorithm such as BCrypt. You can increase the cost, which makes the hash generation slower, and ultimately
|
7
5
|
# 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
|
9
|
-
#
|
6
|
+
# and execute a brute force attack locally, meaning there is no network lag, it would probably take decades to complete. Now throw in network lag
|
7
|
+
# and it would take MUCH longer.
|
10
8
|
#
|
11
9
|
# 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
10
|
# 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
|
@@ -18,37 +16,62 @@ module Authlogic
|
|
18
16
|
# end
|
19
17
|
module BruteForceProtection
|
20
18
|
def self.included(klass)
|
21
|
-
klass.
|
22
|
-
|
23
|
-
|
19
|
+
klass.class_eval do
|
20
|
+
extend Config
|
21
|
+
include InstanceMethods
|
22
|
+
validate :validate_failed_logins, :if => :protect_from_brute_force_attacks?
|
23
|
+
end
|
24
24
|
end
|
25
25
|
|
26
|
-
#
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
# Configuration for the brute force protection feature.
|
27
|
+
module Config
|
28
|
+
# 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
|
29
|
+
# 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.
|
30
|
+
#
|
31
|
+
# In order to enable this field your model MUST have a failed_login_count (integer) field.
|
32
|
+
#
|
33
|
+
# 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
|
34
|
+
# in possibly millions of attempts to log into an account.
|
35
|
+
#
|
36
|
+
# * <tt>Default:</tt> 50
|
37
|
+
# * <tt>Accepts:</tt> Integer, set to 0 to disable
|
38
|
+
def consecutive_failed_logins_limit(value = nil)
|
39
|
+
config(:consecutive_failed_logins_limit, value, 50)
|
40
|
+
end
|
41
|
+
alias_method :consecutive_failed_logins_limit=, :consecutive_failed_logins_limit
|
42
|
+
|
43
|
+
# Once the failed logins limit has been exceed, how long do you want to ban the user? This can be a temporary or permanent ban.
|
44
|
+
#
|
45
|
+
# * <tt>Default:</tt> 2.hours
|
46
|
+
# * <tt>Accepts:</tt> Fixnum, set to 0 for permanent ban
|
47
|
+
def failed_login_ban_for(value = nil)
|
48
|
+
config(:failed_login_ban_for, (!value.nil? && value) || value, 2.hours.to_i)
|
49
|
+
end
|
50
|
+
alias_method :failed_login_ban_for=, :failed_login_ban_for
|
31
51
|
end
|
32
52
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
53
|
+
# The methods available for an Authlogic::Session::Base object that make up the brute force protection feature.
|
54
|
+
module InstanceMethods
|
55
|
+
private
|
56
|
+
def protect_from_brute_force_attacks?
|
57
|
+
!attempted_record.nil? && attempted_record.respond_to?(:failed_login_count) && consecutive_failed_logins_limit > 0 &&
|
58
|
+
attempted_record.failed_login_count && attempted_record.failed_login_count >= consecutive_failed_logins_limit &&
|
59
|
+
(failed_login_ban_for <= 0 || (attempted_record.respond_to?(:updated_at) && attempted_record.updated_at >= failed_login_ban_for.seconds.ago))
|
60
|
+
end
|
61
|
+
|
62
|
+
def consecutive_failed_logins_limit
|
63
|
+
self.class.consecutive_failed_logins_limit
|
64
|
+
end
|
65
|
+
|
66
|
+
def failed_login_ban_for
|
67
|
+
self.class.failed_login_ban_for
|
68
|
+
end
|
38
69
|
|
39
|
-
|
40
|
-
if attempted_record.failed_login_count && attempted_record.failed_login_count >= consecutive_failed_logins_limit
|
70
|
+
def validate_failed_logins
|
41
71
|
errors.clear # Clear all other error messages, as they are irrelevant at this point and can only provide additional information that is not needed
|
42
72
|
errors.add_to_base(I18n.t('error_messages.consecutive_failed_logins_limit_exceeded', :default => "Consecutive failed logins limit exceeded, account is disabled."))
|
43
73
|
end
|
44
|
-
|
45
|
-
|
46
|
-
def increase_failed_login_count
|
47
|
-
if errors.on(password_field)
|
48
|
-
attempted_record.failed_login_count ||= 0
|
49
|
-
attempted_record.failed_login_count += 1
|
50
|
-
end
|
51
|
-
end
|
74
|
+
end
|
52
75
|
end
|
53
76
|
end
|
54
77
|
end
|
@@ -1,14 +1,13 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session
|
3
|
-
# = Callbacks
|
4
|
-
#
|
5
3
|
# 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
4
|
#
|
7
5
|
# Here is the order they execute
|
8
6
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
7
|
+
# before_persisting
|
8
|
+
# persist
|
9
|
+
# after_persisting
|
10
|
+
# [save record if record.changed?]
|
12
11
|
#
|
13
12
|
# before_validation
|
14
13
|
# before_validation_on_create
|
@@ -17,7 +16,7 @@ module Authlogic
|
|
17
16
|
# after_validation_on_update
|
18
17
|
# after_validation_on_create
|
19
18
|
# after_validation
|
20
|
-
# save record if changed?
|
19
|
+
# [save record if record.changed?]
|
21
20
|
#
|
22
21
|
# before_save
|
23
22
|
# before_create
|
@@ -25,7 +24,7 @@ module Authlogic
|
|
25
24
|
# after_update
|
26
25
|
# after_create
|
27
26
|
# after_save
|
28
|
-
# save record if changed?
|
27
|
+
# [save record if record.changed?]
|
29
28
|
#
|
30
29
|
# before_destroy
|
31
30
|
# destroy
|
@@ -45,7 +44,7 @@ module Authlogic
|
|
45
44
|
# 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.
|
46
45
|
module Callbacks
|
47
46
|
METHODS = [
|
48
|
-
"
|
47
|
+
"before_persisting", "persist", "after_persisting",
|
49
48
|
"before_validation", "before_validation_on_create", "before_validation_on_update", "validate", "after_validation_on_update", "after_validation_on_create", "after_validation",
|
50
49
|
"before_save", "before_create", "before_update", "after_update", "after_create", "after_save",
|
51
50
|
"before_destroy", "after_destroy"
|
@@ -56,13 +55,23 @@ module Authlogic
|
|
56
55
|
base.define_callbacks *METHODS
|
57
56
|
end
|
58
57
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
58
|
+
private
|
59
|
+
METHODS.each do |method|
|
60
|
+
class_eval <<-"end_eval", __FILE__, __LINE__
|
61
|
+
def #{method}
|
62
|
+
run_callbacks(:#{method}) { |result, object| result == false }
|
63
|
+
end
|
64
|
+
end_eval
|
65
|
+
end
|
66
|
+
|
67
|
+
def persist
|
68
|
+
run_callbacks(:persist) { |result, object| result == true }
|
69
|
+
end
|
70
|
+
|
71
|
+
def save_record(alternate_record = nil)
|
72
|
+
r = alternate_record || record
|
73
|
+
r.save_without_session_maintenance(false) if r && r.changed?
|
74
|
+
end
|
66
75
|
end
|
67
76
|
end
|
68
77
|
end
|
@@ -1,40 +1,126 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session
|
3
|
-
# = Cookies
|
4
|
-
#
|
5
3
|
# Handles all authentication that deals with cookies, such as persisting a session and saving / destroying a session.
|
6
4
|
module Cookies
|
7
5
|
def self.included(klass)
|
8
|
-
klass.
|
9
|
-
|
6
|
+
klass.class_eval do
|
7
|
+
extend Config
|
8
|
+
include InstanceMethods
|
9
|
+
persist :persist_by_cookie
|
10
|
+
after_save :save_cookie
|
11
|
+
after_destroy :destroy_cookie
|
12
|
+
end
|
10
13
|
end
|
11
14
|
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
# Configuration for the cookie feature set.
|
16
|
+
module Config
|
17
|
+
# The name of the cookie or the key in the cookies hash. Be sure and use a unique name. If you have multiple sessions and they use the same cookie it will cause problems.
|
18
|
+
# Also, if a id is set it will be inserted into the beginning of the string. Exmaple:
|
19
|
+
#
|
20
|
+
# session = UserSession.new
|
21
|
+
# session.cookie_key => "user_credentials"
|
22
|
+
#
|
23
|
+
# session = UserSession.new(:super_high_secret)
|
24
|
+
# session.cookie_key => "super_high_secret_user_credentials"
|
25
|
+
#
|
26
|
+
# * <tt>Default:</tt> "#{klass_name.underscore}_credentials"
|
27
|
+
# * <tt>Accepts:</tt> String
|
28
|
+
def cookie_key(value = nil)
|
29
|
+
config(:cookie_key, value, "#{klass_name.underscore}_credentials")
|
30
|
+
end
|
31
|
+
alias_method :cookie_key=, :cookie_key
|
32
|
+
|
33
|
+
# If sessions should be remembered by default or not.
|
34
|
+
#
|
35
|
+
# * <tt>Default:</tt> false
|
36
|
+
# * <tt>Accepts:</tt> Boolean
|
37
|
+
def remember_me(value = nil)
|
38
|
+
config(:remember_me, value, false)
|
39
|
+
end
|
40
|
+
alias_method :remember_me=, :remember_me
|
41
|
+
|
42
|
+
# The length of time until the cookie expires.
|
43
|
+
#
|
44
|
+
# * <tt>Default:</tt> 3.months
|
45
|
+
# * <tt>Accepts:</tt> Integer, length of time in seconds, such as 60 or 3.months
|
46
|
+
def remember_me_for(value = :_read)
|
47
|
+
config(:remember_me_for, value, 3.months, :_read)
|
19
48
|
end
|
49
|
+
alias_method :remember_me_for=, :remember_me_for
|
20
50
|
end
|
21
51
|
|
22
|
-
|
23
|
-
|
24
|
-
|
52
|
+
# The methods available for an Authlogic::Session::Base object that make up the cookie feature set.
|
53
|
+
module InstanceMethods
|
54
|
+
def credentials=(value)
|
55
|
+
super
|
56
|
+
values = value.is_a?(Array) ? value : [value]
|
57
|
+
case values.first
|
58
|
+
when Hash
|
59
|
+
self.remember_me = values.first.with_indifferent_access[:remember_me]
|
60
|
+
else
|
61
|
+
r = values.find { |value| value.is_a?(TrueClass) || value.is_a?(FalseClass) }
|
62
|
+
self.remember_me = r if !r.nil?
|
63
|
+
end
|
25
64
|
end
|
26
65
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
66
|
+
def remember_me # :nodoc:
|
67
|
+
return @remember_me if defined?(@remember_me)
|
68
|
+
@remember_me = self.class.remember_me
|
69
|
+
end
|
70
|
+
|
71
|
+
# Accepts a boolean as a flag to remember the session or not. Basically to expire the cookie at the end of the session or keep it for "remember_me_until".
|
72
|
+
def remember_me=(value)
|
73
|
+
@remember_me = value
|
74
|
+
end
|
75
|
+
|
76
|
+
# Allows users to be remembered via a cookie.
|
77
|
+
def remember_me?
|
78
|
+
remember_me == true || remember_me == "true" || remember_me == "1"
|
33
79
|
end
|
34
80
|
|
35
|
-
|
36
|
-
|
81
|
+
# How long to remember the user if remember_me is true. This is based on the class level configuration: remember_me_for
|
82
|
+
def remember_me_for
|
83
|
+
return unless remember_me?
|
84
|
+
self.class.remember_me_for
|
85
|
+
end
|
86
|
+
|
87
|
+
# When to expire the cookie. See remember_me_for configuration option to change this.
|
88
|
+
def remember_me_until
|
89
|
+
return unless remember_me?
|
90
|
+
remember_me_for.from_now
|
37
91
|
end
|
92
|
+
|
93
|
+
private
|
94
|
+
def cookie_key
|
95
|
+
build_key(self.class.cookie_key)
|
96
|
+
end
|
97
|
+
|
98
|
+
def cookie_credentials
|
99
|
+
controller.cookies[cookie_key]
|
100
|
+
end
|
101
|
+
|
102
|
+
# Tries to validate the session from information in the cookie
|
103
|
+
def persist_by_cookie
|
104
|
+
if cookie_credentials
|
105
|
+
self.unauthorized_record = search_for_record("find_by_persistence_token", cookie_credentials)
|
106
|
+
valid?
|
107
|
+
else
|
108
|
+
false
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def save_cookie
|
113
|
+
controller.cookies[cookie_key] = {
|
114
|
+
:value => record.persistence_token,
|
115
|
+
:expires => remember_me_until,
|
116
|
+
:domain => controller.cookie_domain
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
120
|
+
def destroy_cookie
|
121
|
+
controller.cookies.delete cookie_key, :domain => controller.cookie_domain
|
122
|
+
end
|
123
|
+
end
|
38
124
|
end
|
39
125
|
end
|
40
126
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Authlogic
|
2
|
+
module Session
|
3
|
+
# Provides methods to create and destroy objects. Basically controls their "existence".
|
4
|
+
module Existence
|
5
|
+
class SessionInvalidError < ::StandardError # :nodoc:
|
6
|
+
def initialize(session)
|
7
|
+
super("Your session is invalid and has the following errors: #{session.errors.full_messages.to_sentence}")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.included(klass)
|
12
|
+
klass.class_eval do
|
13
|
+
extend ClassMethods
|
14
|
+
include InstanceMethods
|
15
|
+
attr_accessor :new_session, :record
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
# A convenince method. The same as:
|
21
|
+
#
|
22
|
+
# session = UserSession.new(*args)
|
23
|
+
# session.create
|
24
|
+
#
|
25
|
+
# Instead you can do:
|
26
|
+
#
|
27
|
+
# UserSession.create(*args)
|
28
|
+
def create(*args, &block)
|
29
|
+
session = new(*args)
|
30
|
+
session.save(&block)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Same as create but calls create!, which raises an exception when validation fails.
|
34
|
+
def create!(*args)
|
35
|
+
session = new(*args)
|
36
|
+
session.save!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module InstanceMethods
|
41
|
+
# Clears all errors and the associated record, you should call this terminate a session, thus requring
|
42
|
+
# the user to authenticate again if it is needed.
|
43
|
+
def destroy
|
44
|
+
before_destroy
|
45
|
+
errors.clear
|
46
|
+
@record = nil
|
47
|
+
after_destroy
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns true if the session has not been saved yet.
|
52
|
+
def new_session?
|
53
|
+
new_session != false
|
54
|
+
end
|
55
|
+
|
56
|
+
# After you have specified all of the details for your session you can try to save it. This will
|
57
|
+
# run validation checks and find the associated record, if all validation passes. If validation
|
58
|
+
# does not pass, the save will fail and the erorrs will be stored in the errors object.
|
59
|
+
def save(&block)
|
60
|
+
result = nil
|
61
|
+
if valid?
|
62
|
+
self.record = attempted_record
|
63
|
+
|
64
|
+
before_save
|
65
|
+
new_session? ? before_create : before_update
|
66
|
+
new_session? ? after_create : after_update
|
67
|
+
after_save
|
68
|
+
|
69
|
+
save_record
|
70
|
+
self.new_session = false
|
71
|
+
result = true
|
72
|
+
else
|
73
|
+
result = false
|
74
|
+
end
|
75
|
+
|
76
|
+
yield result if block_given?
|
77
|
+
result
|
78
|
+
end
|
79
|
+
|
80
|
+
# Same as save but raises an exception of validation errors when validation fails
|
81
|
+
def save!
|
82
|
+
result = save
|
83
|
+
raise SessionInvalidError.new(self) unless result
|
84
|
+
result
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Authlogic
|
2
|
+
module Session
|
3
|
+
# Sort of like an interface, it sets the foundation for the class, such as the required methods. This also allows
|
4
|
+
# other modules to overwrite methods and call super on them. It's also a place to put "utility" methods used
|
5
|
+
# throughout Authlogic.
|
6
|
+
module Foundation
|
7
|
+
def self.included(klass)
|
8
|
+
klass.class_eval do
|
9
|
+
extend ClassMethods
|
10
|
+
include InstanceMethods
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
private
|
16
|
+
def config(key, value, default_value = nil, read_value = nil)
|
17
|
+
if value == read_value
|
18
|
+
return read_inheritable_attribute(key) if inheritable_attributes.include?(key)
|
19
|
+
write_inheritable_attribute(key, default_value)
|
20
|
+
else
|
21
|
+
write_inheritable_attribute(key, value)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module InstanceMethods
|
27
|
+
def initialize(*args)
|
28
|
+
self.credentials = args
|
29
|
+
end
|
30
|
+
|
31
|
+
# The credentials you passed to create your session. See credentials= for more info.
|
32
|
+
def credentials
|
33
|
+
[]
|
34
|
+
end
|
35
|
+
|
36
|
+
# Set your credentials before you save your session. You can pass a hash of credentials:
|
37
|
+
#
|
38
|
+
# session.credentials = {:login => "my login", :password => "my password", :remember_me => true}
|
39
|
+
#
|
40
|
+
# or you can pass an array of objects:
|
41
|
+
#
|
42
|
+
# session.credentails = [my_user_object, true]
|
43
|
+
#
|
44
|
+
# and if you need to set an id, just pass it last. This value need be the last item in the array you pass, since the id is something that
|
45
|
+
# you control yourself, it should never be set from a hash or a form. Examples:
|
46
|
+
#
|
47
|
+
# session.credentials = [{:login => "my login", :password => "my password", :remember_me => true}, :my_id]
|
48
|
+
# session.credentials = [my_user_object, true, :my_id]
|
49
|
+
def credentials=(values)
|
50
|
+
end
|
51
|
+
|
52
|
+
def inspect
|
53
|
+
"#<#{self.class.name}: #{credentials.blank? ? "no credentials provided" : credentials.inspect}>"
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def build_key(last_part)
|
58
|
+
last_part
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|