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.

Files changed (131) hide show
  1. data/CHANGELOG.rdoc +19 -0
  2. data/Manifest.txt +111 -0
  3. data/README.rdoc +116 -389
  4. data/Rakefile +14 -7
  5. data/lib/authlogic.rb +33 -35
  6. data/lib/authlogic/acts_as_authentic/base.rb +91 -0
  7. data/lib/authlogic/acts_as_authentic/email.rb +77 -0
  8. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +54 -0
  9. data/lib/authlogic/acts_as_authentic/login.rb +65 -0
  10. data/lib/authlogic/acts_as_authentic/magic_columns.rb +24 -0
  11. data/lib/authlogic/acts_as_authentic/password.rb +215 -0
  12. data/lib/authlogic/acts_as_authentic/perishable_token.rb +100 -0
  13. data/lib/authlogic/acts_as_authentic/persistence_token.rb +66 -0
  14. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +60 -0
  15. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +127 -0
  16. data/lib/authlogic/acts_as_authentic/single_access_token.rb +58 -0
  17. data/lib/authlogic/acts_as_authentic/validations_scope.rb +32 -0
  18. data/lib/authlogic/{session/authenticates_many_association.rb → authenticates_many/association.rb} +10 -6
  19. data/lib/authlogic/authenticates_many/base.rb +55 -0
  20. data/lib/authlogic/controller_adapters/abstract_adapter.rb +2 -3
  21. data/lib/authlogic/controller_adapters/merb_adapter.rb +0 -4
  22. data/lib/authlogic/controller_adapters/rails_adapter.rb +0 -4
  23. data/lib/authlogic/crypto_providers/aes256.rb +0 -2
  24. data/lib/authlogic/crypto_providers/bcrypt.rb +0 -2
  25. data/lib/authlogic/crypto_providers/md5.rb +34 -0
  26. data/lib/authlogic/crypto_providers/sha1.rb +0 -2
  27. data/lib/authlogic/crypto_providers/sha512.rb +1 -3
  28. data/lib/authlogic/i18n.rb +1 -4
  29. data/lib/authlogic/random.rb +33 -0
  30. data/lib/authlogic/session/activation.rb +56 -0
  31. data/lib/authlogic/session/active_record_trickery.rb +15 -7
  32. data/lib/authlogic/session/base.rb +31 -456
  33. data/lib/authlogic/session/brute_force_protection.rb +50 -27
  34. data/lib/authlogic/session/callbacks.rb +24 -15
  35. data/lib/authlogic/session/cookies.rb +108 -22
  36. data/lib/authlogic/session/existence.rb +89 -0
  37. data/lib/authlogic/session/foundation.rb +63 -0
  38. data/lib/authlogic/session/http_auth.rb +23 -0
  39. data/lib/authlogic/session/id.rb +41 -0
  40. data/lib/authlogic/session/klass.rb +75 -0
  41. data/lib/authlogic/session/magic_columns.rb +75 -0
  42. data/lib/authlogic/session/magic_states.rb +58 -0
  43. data/lib/authlogic/session/params.rb +82 -19
  44. data/lib/authlogic/session/password.rb +156 -0
  45. data/lib/authlogic/session/{perishability.rb → perishable_token.rb} +4 -4
  46. data/lib/authlogic/session/persistence.rb +70 -0
  47. data/lib/authlogic/session/priority_record.rb +34 -0
  48. data/lib/authlogic/session/scopes.rb +57 -53
  49. data/lib/authlogic/session/session.rb +46 -31
  50. data/lib/authlogic/session/timeout.rb +65 -31
  51. data/lib/authlogic/session/unauthorized_record.rb +50 -0
  52. data/lib/authlogic/session/validation.rb +76 -0
  53. data/lib/authlogic/testing/test_unit_helpers.rb +3 -3
  54. data/lib/authlogic/version.rb +3 -3
  55. data/test/acts_as_authentic_test/base_test.rb +12 -0
  56. data/test/acts_as_authentic_test/email_test.rb +79 -0
  57. data/test/acts_as_authentic_test/logged_in_status_test.rb +36 -0
  58. data/test/acts_as_authentic_test/login_test.rb +79 -0
  59. data/test/acts_as_authentic_test/magic_columns_test.rb +27 -0
  60. data/test/acts_as_authentic_test/password_test.rb +212 -0
  61. data/test/acts_as_authentic_test/perishable_token_test.rb +56 -0
  62. data/test/acts_as_authentic_test/persistence_token_test.rb +55 -0
  63. data/test/acts_as_authentic_test/session_maintenance_test.rb +68 -0
  64. data/test/acts_as_authentic_test/single_access_test.rb +39 -0
  65. data/test/authenticates_many_test.rb +16 -0
  66. data/test/{crypto_provider_tests → crypto_provider_test}/aes256_test.rb +1 -1
  67. data/test/{crypto_provider_tests → crypto_provider_test}/bcrypt_test.rb +1 -1
  68. data/test/{crypto_provider_tests → crypto_provider_test}/sha1_test.rb +1 -1
  69. data/test/{crypto_provider_tests → crypto_provider_test}/sha512_test.rb +1 -1
  70. data/test/fixtures/employees.yml +4 -4
  71. data/test/fixtures/users.yml +6 -6
  72. data/test/libs/company.rb +6 -0
  73. data/test/libs/employee.rb +7 -0
  74. data/test/libs/employee_session.rb +2 -0
  75. data/test/libs/project.rb +3 -0
  76. data/test/libs/user_session.rb +2 -0
  77. data/test/random_test.rb +49 -0
  78. data/test/session_test/activation_test.rb +43 -0
  79. data/test/session_test/active_record_trickery_test.rb +26 -0
  80. data/test/session_test/brute_force_protection_test.rb +76 -0
  81. data/test/session_test/callbacks_test.rb +6 -0
  82. data/test/session_test/cookies_test.rb +107 -0
  83. data/test/session_test/credentials_test.rb +0 -0
  84. data/test/session_test/existence_test.rb +64 -0
  85. data/test/session_test/http_auth_test.rb +16 -0
  86. data/test/session_test/id_test.rb +17 -0
  87. data/test/session_test/klass_test.rb +35 -0
  88. data/test/session_test/magic_columns_test.rb +59 -0
  89. data/test/session_test/magic_states_test.rb +60 -0
  90. data/test/session_test/params_test.rb +53 -0
  91. data/test/session_test/password_test.rb +84 -0
  92. data/test/{session_tests → session_test}/perishability_test.rb +1 -1
  93. data/test/session_test/persistence_test.rb +21 -0
  94. data/test/{session_tests → session_test}/scopes_test.rb +2 -3
  95. data/test/session_test/session_test.rb +59 -0
  96. data/test/session_test/timeout_test.rb +43 -0
  97. data/test/session_test/unauthorized_record_test.rb +13 -0
  98. data/test/session_test/validation_test.rb +23 -0
  99. data/test/test_helper.rb +14 -29
  100. metadata +120 -112
  101. data/Manifest +0 -76
  102. data/authlogic.gemspec +0 -38
  103. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/base.rb +0 -22
  104. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb +0 -238
  105. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb +0 -155
  106. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb +0 -51
  107. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/perishability.rb +0 -71
  108. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb +0 -94
  109. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb +0 -87
  110. data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb +0 -61
  111. data/lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb +0 -58
  112. data/lib/authlogic/session/config.rb +0 -421
  113. data/lib/authlogic/session/errors.rb +0 -18
  114. data/lib/authlogic/session/record_info.rb +0 -24
  115. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb +0 -154
  116. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb +0 -157
  117. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/logged_in_test.rb +0 -24
  118. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/perishability_test.rb +0 -41
  119. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/persistence_test.rb +0 -54
  120. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/session_maintenance_test.rb +0 -62
  121. data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/single_access_test.rb +0 -41
  122. data/test/orm_adapters_tests/active_record_adapter_tests/authenticates_many_test.rb +0 -32
  123. data/test/session_tests/active_record_trickery_test.rb +0 -14
  124. data/test/session_tests/authenticates_many_association_test.rb +0 -28
  125. data/test/session_tests/base_test.rb +0 -307
  126. data/test/session_tests/brute_force_protection_test.rb +0 -53
  127. data/test/session_tests/config_test.rb +0 -184
  128. data/test/session_tests/cookies_test.rb +0 -32
  129. data/test/session_tests/params_test.rb +0 -32
  130. data/test/session_tests/session_test.rb +0 -45
  131. 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 for hackers
9
- # executing this attack over a network, and it would take centuries.
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.validate :validate_failed_logins, :if => :protect_from_brute_force_attacks?
22
- klass.validate :increase_failed_login_count, :if => :protect_from_brute_force_attacks?
23
- klass.after_save :reset_failed_login_count, :if => :protect_from_brute_force_attacks?
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
- # This allows you to reset the failed_login_count for the associated record, allowing that account to start at 0 and continue
27
- # trying to login. So, if an account exceeds the limit the only way they will be able to log back in is if your execute this
28
- # method, which merely resets the failed_login_count field to 0.
29
- def reset_failed_login_count
30
- record.failed_login_count = 0
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
- private
34
- def protect_from_brute_force_attacks?
35
- r = attempted_record || record
36
- r && r.respond_to?(:failed_login_count) && consecutive_failed_logins_limit > 0
37
- end
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
- def validate_failed_logins
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
- end
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
- # before_find
10
- # after_find
11
- # save record if changed?
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
- "before_find", "after_find",
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
- METHODS.each do |method|
60
- class_eval <<-"end_eval", __FILE__, __LINE__
61
- def #{method}
62
- run_callbacks(:#{method})
63
- end
64
- end_eval
65
- end
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.after_save :save_cookie, :if => :persisting?
9
- klass.after_destroy :destroy_cookie, :if => :persisting?
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
- # Tries to validate the session from information in the cookie
13
- def valid_cookie?
14
- if cookie_credentials
15
- self.unauthorized_record = search_for_record("find_by_#{persistence_token_field}", cookie_credentials)
16
- valid?
17
- else
18
- false
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
- private
23
- def cookie_credentials
24
- controller.cookies[cookie_key]
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 save_cookie
28
- controller.cookies[cookie_key] = {
29
- :value => record.send(persistence_token_field),
30
- :expires => remember_me_until,
31
- :domain => controller.cookie_domain
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
- def destroy_cookie
36
- controller.cookies.delete cookie_key, :domain => controller.cookie_domain
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