binarylogic-authlogic 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. data/.gitignore +9 -0
  2. data/CHANGELOG.rdoc +334 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +245 -0
  5. data/Rakefile +49 -0
  6. data/VERSION.yml +4 -0
  7. data/generators/session/session_generator.rb +9 -0
  8. data/generators/session/templates/session.rb +2 -0
  9. data/init.rb +1 -0
  10. data/lib/authlogic.rb +55 -0
  11. data/lib/authlogic/acts_as_authentic/base.rb +112 -0
  12. data/lib/authlogic/acts_as_authentic/email.rb +110 -0
  13. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +60 -0
  14. data/lib/authlogic/acts_as_authentic/login.rb +141 -0
  15. data/lib/authlogic/acts_as_authentic/magic_columns.rb +24 -0
  16. data/lib/authlogic/acts_as_authentic/password.rb +344 -0
  17. data/lib/authlogic/acts_as_authentic/perishable_token.rb +105 -0
  18. data/lib/authlogic/acts_as_authentic/persistence_token.rb +68 -0
  19. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +61 -0
  20. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +139 -0
  21. data/lib/authlogic/acts_as_authentic/single_access_token.rb +65 -0
  22. data/lib/authlogic/acts_as_authentic/validations_scope.rb +32 -0
  23. data/lib/authlogic/authenticates_many/association.rb +42 -0
  24. data/lib/authlogic/authenticates_many/base.rb +55 -0
  25. data/lib/authlogic/controller_adapters/abstract_adapter.rb +67 -0
  26. data/lib/authlogic/controller_adapters/merb_adapter.rb +30 -0
  27. data/lib/authlogic/controller_adapters/rails_adapter.rb +38 -0
  28. data/lib/authlogic/crypto_providers/aes256.rb +43 -0
  29. data/lib/authlogic/crypto_providers/bcrypt.rb +89 -0
  30. data/lib/authlogic/crypto_providers/md5.rb +34 -0
  31. data/lib/authlogic/crypto_providers/sha1.rb +35 -0
  32. data/lib/authlogic/crypto_providers/sha512.rb +50 -0
  33. data/lib/authlogic/i18n.rb +63 -0
  34. data/lib/authlogic/random.rb +33 -0
  35. data/lib/authlogic/regex.rb +25 -0
  36. data/lib/authlogic/session/activation.rb +58 -0
  37. data/lib/authlogic/session/active_record_trickery.rb +50 -0
  38. data/lib/authlogic/session/base.rb +37 -0
  39. data/lib/authlogic/session/brute_force_protection.rb +92 -0
  40. data/lib/authlogic/session/callbacks.rb +87 -0
  41. data/lib/authlogic/session/cookies.rb +130 -0
  42. data/lib/authlogic/session/existence.rb +91 -0
  43. data/lib/authlogic/session/foundation.rb +63 -0
  44. data/lib/authlogic/session/http_auth.rb +58 -0
  45. data/lib/authlogic/session/id.rb +41 -0
  46. data/lib/authlogic/session/klass.rb +75 -0
  47. data/lib/authlogic/session/magic_columns.rb +94 -0
  48. data/lib/authlogic/session/magic_states.rb +58 -0
  49. data/lib/authlogic/session/params.rb +100 -0
  50. data/lib/authlogic/session/password.rb +218 -0
  51. data/lib/authlogic/session/perishable_token.rb +18 -0
  52. data/lib/authlogic/session/persistence.rb +70 -0
  53. data/lib/authlogic/session/priority_record.rb +34 -0
  54. data/lib/authlogic/session/scopes.rb +101 -0
  55. data/lib/authlogic/session/session.rb +60 -0
  56. data/lib/authlogic/session/timeout.rb +82 -0
  57. data/lib/authlogic/session/unauthorized_record.rb +50 -0
  58. data/lib/authlogic/session/validation.rb +80 -0
  59. data/lib/authlogic/test_case.rb +114 -0
  60. data/lib/authlogic/test_case/mock_controller.rb +45 -0
  61. data/lib/authlogic/test_case/mock_cookie_jar.rb +14 -0
  62. data/lib/authlogic/test_case/mock_logger.rb +10 -0
  63. data/lib/authlogic/test_case/mock_request.rb +19 -0
  64. data/lib/authlogic/test_case/rails_request_adapter.rb +30 -0
  65. data/rails/init.rb +1 -0
  66. data/shoulda_macros/authlogic.rb +13 -0
  67. data/test/acts_as_authentic_test/base_test.rb +18 -0
  68. data/test/acts_as_authentic_test/email_test.rb +97 -0
  69. data/test/acts_as_authentic_test/logged_in_status_test.rb +36 -0
  70. data/test/acts_as_authentic_test/login_test.rb +109 -0
  71. data/test/acts_as_authentic_test/magic_columns_test.rb +27 -0
  72. data/test/acts_as_authentic_test/password_test.rb +236 -0
  73. data/test/acts_as_authentic_test/perishable_token_test.rb +90 -0
  74. data/test/acts_as_authentic_test/persistence_token_test.rb +55 -0
  75. data/test/acts_as_authentic_test/restful_authentication_test.rb +40 -0
  76. data/test/acts_as_authentic_test/session_maintenance_test.rb +84 -0
  77. data/test/acts_as_authentic_test/single_access_test.rb +44 -0
  78. data/test/authenticates_many_test.rb +16 -0
  79. data/test/crypto_provider_test/aes256_test.rb +14 -0
  80. data/test/crypto_provider_test/bcrypt_test.rb +14 -0
  81. data/test/crypto_provider_test/sha1_test.rb +23 -0
  82. data/test/crypto_provider_test/sha512_test.rb +14 -0
  83. data/test/fixtures/companies.yml +5 -0
  84. data/test/fixtures/employees.yml +17 -0
  85. data/test/fixtures/projects.yml +3 -0
  86. data/test/fixtures/users.yml +24 -0
  87. data/test/libs/affiliate.rb +7 -0
  88. data/test/libs/company.rb +6 -0
  89. data/test/libs/employee.rb +7 -0
  90. data/test/libs/employee_session.rb +2 -0
  91. data/test/libs/ldaper.rb +3 -0
  92. data/test/libs/ordered_hash.rb +9 -0
  93. data/test/libs/project.rb +3 -0
  94. data/test/libs/user.rb +5 -0
  95. data/test/libs/user_session.rb +2 -0
  96. data/test/random_test.rb +49 -0
  97. data/test/session_test/activation_test.rb +43 -0
  98. data/test/session_test/active_record_trickery_test.rb +27 -0
  99. data/test/session_test/brute_force_protection_test.rb +101 -0
  100. data/test/session_test/callbacks_test.rb +6 -0
  101. data/test/session_test/cookies_test.rb +107 -0
  102. data/test/session_test/credentials_test.rb +0 -0
  103. data/test/session_test/existence_test.rb +64 -0
  104. data/test/session_test/http_auth_test.rb +28 -0
  105. data/test/session_test/id_test.rb +17 -0
  106. data/test/session_test/klass_test.rb +35 -0
  107. data/test/session_test/magic_columns_test.rb +62 -0
  108. data/test/session_test/magic_states_test.rb +60 -0
  109. data/test/session_test/params_test.rb +53 -0
  110. data/test/session_test/password_test.rb +92 -0
  111. data/test/session_test/perishability_test.rb +15 -0
  112. data/test/session_test/persistence_test.rb +21 -0
  113. data/test/session_test/scopes_test.rb +60 -0
  114. data/test/session_test/session_test.rb +59 -0
  115. data/test/session_test/timeout_test.rb +52 -0
  116. data/test/session_test/unauthorized_record_test.rb +13 -0
  117. data/test/session_test/validation_test.rb +23 -0
  118. data/test/test_helper.rb +174 -0
  119. metadata +227 -0
@@ -0,0 +1,91 @@
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.save
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
+ save_record
46
+ errors.clear
47
+ @record = nil
48
+ after_destroy
49
+ true
50
+ end
51
+
52
+ # Returns true if the session is new, meaning no action has been taken on it and a successful save
53
+ # has not taken place.
54
+ def new_session?
55
+ new_session != false
56
+ end
57
+
58
+ # After you have specified all of the details for your session you can try to save it. This will
59
+ # run validation checks and find the associated record, if all validation passes. If validation
60
+ # does not pass, the save will fail and the erorrs will be stored in the errors object.
61
+ def save(&block)
62
+ result = nil
63
+ if valid?
64
+ self.record = attempted_record
65
+
66
+ before_save
67
+ new_session? ? before_create : before_update
68
+ new_session? ? after_create : after_update
69
+ after_save
70
+
71
+ save_record
72
+ self.new_session = false
73
+ result = true
74
+ else
75
+ result = false
76
+ end
77
+
78
+ yield result if block_given?
79
+ result
80
+ end
81
+
82
+ # Same as save but raises an exception of validation errors when validation fails
83
+ def save!
84
+ result = save
85
+ raise SessionInvalidError.new(self) unless result
86
+ result
87
+ end
88
+ end
89
+ end
90
+ end
91
+ 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 rw_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
@@ -0,0 +1,58 @@
1
+ module Authlogic
2
+ module Session
3
+ # Handles all authentication that deals with basic HTTP auth. Which is authentication built into the HTTP protocol:
4
+ #
5
+ # http://username:password@whatever.com
6
+ #
7
+ # Also, if you are not comfortable letting users pass their raw username and password you can always use the single
8
+ # access token. See Authlogic::Session::Params for more info.
9
+ module HttpAuth
10
+ def self.included(klass)
11
+ klass.class_eval do
12
+ extend Config
13
+ include InstanceMethods
14
+ persist :persist_by_http_auth, :if => :persist_by_http_auth?
15
+ end
16
+ end
17
+
18
+ # Configuration for the HTTP basic auth feature of Authlogic.
19
+ module Config
20
+ # Do you want to allow your users to log in via HTTP basic auth?
21
+ #
22
+ # I recommend keeping this enabled. The only time I feel this should be disabled is if you are not comfortable
23
+ # having your users provide their raw username and password. Whatever the reason, you can disable it here.
24
+ #
25
+ # * <tt>Default:</tt> true
26
+ # * <tt>Accepts:</tt> Boolean
27
+ def allow_http_basic_auth(value = nil)
28
+ rw_config(:allow_http_basic_auth, value, true)
29
+ end
30
+ alias_method :allow_http_basic_auth=, :allow_http_basic_auth
31
+ end
32
+
33
+ # Instance methods for the HTTP basic auth feature of authlogic.
34
+ module InstanceMethods
35
+ private
36
+ def persist_by_http_auth?
37
+ allow_http_basic_auth? && login_field && password_field
38
+ end
39
+
40
+ def persist_by_http_auth
41
+ controller.authenticate_with_http_basic do |login, password|
42
+ if !login.blank? && !password.blank?
43
+ send("#{login_field}=", login)
44
+ send("#{password_field}=", password)
45
+ return valid?
46
+ end
47
+ end
48
+
49
+ false
50
+ end
51
+
52
+ def allow_http_basic_auth?
53
+ self.class.allow_http_basic_auth == true
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,41 @@
1
+ module Authlogic
2
+ module Session
3
+ # Allows you to separate sessions with an id, ultimately letting you create multiple sessions for the same user.
4
+ module Id
5
+ def self.included(klass)
6
+ klass.class_eval do
7
+ attr_writer :id
8
+ end
9
+ end
10
+
11
+ # Setting the id if it is passed in the credentials.
12
+ def credentials=(value)
13
+ super
14
+ values = value.is_a?(Array) ? value : [value]
15
+ self.id = values.last if values.last.is_a?(Symbol)
16
+ end
17
+
18
+ # Allows you to set a unique identifier for your session, so that you can have more than 1 session at a time.
19
+ # A good example when this might be needed is when you want to have a normal user session and a "secure" user session.
20
+ # The secure user session would be created only when they want to modify their billing information, or other sensitive
21
+ # information. Similar to me.com. This requires 2 user sessions. Just use an id for the "secure" session and you should be good.
22
+ #
23
+ # You can set the id during initialization (see initialize for more information), or as an attribute:
24
+ #
25
+ # session.id = :my_id
26
+ #
27
+ # Just be sure and set your id before you save your session.
28
+ #
29
+ # Lastly, to retrieve your session with the id check out the find class method.
30
+ def id
31
+ @id
32
+ end
33
+
34
+ private
35
+ # Used for things like cookie_key, session_key, etc.
36
+ def build_key(last_part)
37
+ [id, super].compact.join("_")
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,75 @@
1
+ module Authlogic
2
+ module Session
3
+ # Handles authenticating via a traditional username and password.
4
+ module Klass
5
+ def self.included(klass)
6
+ klass.class_eval do
7
+ extend Config
8
+ include InstanceMethods
9
+
10
+ class << self
11
+ attr_accessor :configured_klass_methods
12
+ end
13
+ end
14
+ end
15
+
16
+ module Config
17
+ # Lets you change which model to use for authentication.
18
+ #
19
+ # * <tt>Default:</tt> inferred from the class name. UserSession would automatically try User
20
+ # * <tt>Accepts:</tt> an ActiveRecord class
21
+ def authenticate_with(klass)
22
+ @klass_name = klass.name
23
+ @klass = klass
24
+ end
25
+ alias_method :authenticate_with=, :authenticate_with
26
+
27
+ # The name of the class that this session is authenticating with. For example, the UserSession class will
28
+ # authenticate with the User class unless you specify otherwise in your configuration. See authenticate_with
29
+ # for information on how to change this value.
30
+ def klass
31
+ @klass ||=
32
+ if klass_name
33
+ klass_name.constantize
34
+ else
35
+ nil
36
+ end
37
+ end
38
+
39
+ # Same as klass, just returns a string instead of the actual constant.
40
+ def klass_name
41
+ @klass_name ||=
42
+ if guessed_name = name.scan(/(.*)Session/)[0]
43
+ @klass_name = guessed_name[0]
44
+ end
45
+ end
46
+ end
47
+
48
+ module InstanceMethods
49
+ # Creating an alias method for the "record" method based on the klass name, so that we can do:
50
+ #
51
+ # session.user
52
+ #
53
+ # instead of:
54
+ #
55
+ # session.record
56
+ def initialize(*args)
57
+ if !self.class.configured_klass_methods
58
+ self.class.send(:alias_method, klass_name.demodulize.underscore.to_sym, :record)
59
+ self.class.configured_klass_methods = true
60
+ end
61
+ super
62
+ end
63
+
64
+ private
65
+ def klass
66
+ self.class.klass
67
+ end
68
+
69
+ def klass_name
70
+ self.class.klass_name
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,94 @@
1
+ module Authlogic
2
+ module Session
3
+ # Just like ActiveRecord has "magic" columns, such as: created_at and updated_at. Authlogic has its own "magic" columns too:
4
+ #
5
+ # Column name Description
6
+ # login_count Increased every time an explicit login is made. This will *NOT* increase if logging in by a session, cookie, or basic http auth
7
+ # failed_login_count This increases for each consecutive failed login. See Authlogic::Session::BruteForceProtection and the consecutive_failed_logins_limit config option for more details.
8
+ # last_request_at Updates every time the user logs in, either by explicitly logging in, or logging in by cookie, session, or http auth
9
+ # current_login_at Updates with the current time when an explicit login is made.
10
+ # last_login_at Updates with the value of current_login_at before it is reset.
11
+ # current_login_ip Updates with the request remote_ip when an explicit login is made.
12
+ # last_login_ip Updates with the value of current_login_ip before it is reset.
13
+ module MagicColumns
14
+ def self.included(klass)
15
+ klass.class_eval do
16
+ extend Config
17
+ include InstanceMethods
18
+ after_persisting :set_last_request_at, :if => :set_last_request_at?
19
+ validate :increase_failed_login_count
20
+ before_save :update_info
21
+ before_save :set_last_request_at, :if => :set_last_request_at?
22
+ end
23
+ end
24
+
25
+ # Configuration for the magic columns feature.
26
+ module Config
27
+ # Every time a session is found the last_request_at field for that record is updatd with the current time, if that field exists. If you want to limit how frequent that field is updated specify the threshold
28
+ # here. For example, if your user is making a request every 5 seconds, and you feel this is too frequent, and feel a minute is a good threashold. Set this to 1.minute. Once a minute has passed in between
29
+ # requests the field will be updated.
30
+ #
31
+ # * <tt>Default:</tt> 0
32
+ # * <tt>Accepts:</tt> integer representing time in seconds
33
+ def last_request_at_threshold(value = nil)
34
+ rw_config(:last_request_at_threshold, value, 0)
35
+ end
36
+ alias_method :last_request_at_threshold=, :last_request_at_threshold
37
+ end
38
+
39
+ # The methods available for an Authlogic::Session::Base object that make up the magic columns feature.
40
+ module InstanceMethods
41
+ private
42
+ def increase_failed_login_count
43
+ if invalid_password? && attempted_record.respond_to?(:failed_login_count)
44
+ attempted_record.failed_login_count ||= 0
45
+ attempted_record.failed_login_count += 1
46
+ end
47
+ end
48
+
49
+ def update_info
50
+ record.login_count = (record.login_count.blank? ? 1 : record.login_count + 1) if record.respond_to?(:login_count)
51
+ record.failed_login_count = 0 if record.respond_to?(:failed_login_count)
52
+
53
+ if record.respond_to?(:current_login_at)
54
+ record.last_login_at = record.current_login_at if record.respond_to?(:last_login_at)
55
+ record.current_login_at = klass.default_timezone == :utc ? Time.now.utc : Time.now
56
+ end
57
+
58
+ if record.respond_to?(:current_login_ip)
59
+ record.last_login_ip = record.current_login_ip if record.respond_to?(:last_login_ip)
60
+ record.current_login_ip = controller.request.remote_ip
61
+ end
62
+ end
63
+
64
+ # This method lets authlogic know whether it should allow the last_request_at field to be updated
65
+ # with the current time (Time.now). One thing to note here is that it also checks for the existence of a
66
+ # last_request_update_allowed? method in your controller. This allows you to control this method pragmatically
67
+ # in your controller.
68
+ #
69
+ # For example, what if you had a javascript function that polled the server updating how much time is left in their
70
+ # session before it times out. Obviously you would want to ignore this request, because then the user would never time out.
71
+ # So you can do something like this in your controller:
72
+ #
73
+ # def last_request_update_allowed?
74
+ # action_name =! "update_session_time_left"
75
+ # end
76
+ #
77
+ # You can do whatever you want with that method.
78
+ def set_last_request_at? # :doc:
79
+ return false if !record || !klass.column_names.include?("last_request_at")
80
+ return controller.last_request_update_allowed? if controller.responds_to_last_request_update_allowed?
81
+ record.last_request_at.blank? || last_request_at_threshold.to_i.seconds.ago >= record.last_request_at
82
+ end
83
+
84
+ def set_last_request_at
85
+ record.last_request_at = klass.default_timezone == :utc ? Time.now.utc : Time.now
86
+ end
87
+
88
+ def last_request_at_threshold
89
+ self.class.last_request_at_threshold
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,58 @@
1
+ module Authlogic
2
+ module Session
3
+ # Authlogic tries to check the state of the record before creating the session. If your record responds to the following methods and any of them return false, validation will fail:
4
+ #
5
+ # Method name Description
6
+ # active? Is the record marked as active?
7
+ # approved? Has the record been approved?
8
+ # confirmed? Has the record been conirmed?
9
+ #
10
+ # Authlogic does nothing to define these methods for you, its up to you to define what they mean. If your object responds to these methods Authlogic will use them, otherwise they are ignored.
11
+ #
12
+ # What's neat about this is that these are checked upon any type of login. When logging in explicitly, by cookie, session, or basic http auth. So if you mark a user inactive in the middle of their session they wont be logged back in next time they refresh the page. Giving you complete control.
13
+ #
14
+ # Need Authlogic to check your own "state"? No problem, check out the hooks section below. Add in a before_validation to do your own checking. The sky is the limit.
15
+ module MagicStates
16
+ def self.included(klass)
17
+ klass.class_eval do
18
+ extend Config
19
+ include InstanceMethods
20
+ validate :validate_magic_states, :unless => :disable_magic_states?
21
+ end
22
+ end
23
+
24
+ # Configuration for the magic states feature.
25
+ module Config
26
+ # Set this to true if you want to disable the checking of active?, approved?, and confirmed? on your record. This is more or less of a
27
+ # convenience feature, since 99% of the time if those methods exist and return false you will not want the user logging in. You could
28
+ # easily accomplish this same thing with a before_validation method or other callbacks.
29
+ #
30
+ # * <tt>Default:</tt> false
31
+ # * <tt>Accepts:</tt> Boolean
32
+ def disable_magic_states(value = nil)
33
+ rw_config(:disable_magic_states, value, false)
34
+ end
35
+ alias_method :disable_magic_states=, :disable_magic_states
36
+ end
37
+
38
+ # The methods available for an Authlogic::Session::Base object that make up the magic states feature.
39
+ module InstanceMethods
40
+ private
41
+ def disable_magic_states?
42
+ self.class.disable_magic_states == true
43
+ end
44
+
45
+ def validate_magic_states
46
+ return true if attempted_record.nil?
47
+ [:active, :approved, :confirmed].each do |required_status|
48
+ if attempted_record.respond_to?("#{required_status}?") && !attempted_record.send("#{required_status}?")
49
+ errors.add(:base, I18n.t("error_messages.not_#{required_status}", :default => "Your account is not #{required_status}"))
50
+ return false
51
+ end
52
+ end
53
+ true
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end