Empact-authlogic 2.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. data/.gitignore +9 -0
  2. data/CHANGELOG.rdoc +349 -0
  3. data/Empact-authlogic.gemspec +217 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +246 -0
  6. data/Rakefile +42 -0
  7. data/VERSION.yml +5 -0
  8. data/generators/session/session_generator.rb +9 -0
  9. data/generators/session/templates/session.rb +2 -0
  10. data/init.rb +1 -0
  11. data/lib/authlogic/acts_as_authentic/base.rb +107 -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 +355 -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 +48 -0
  28. data/lib/authlogic/controller_adapters/sinatra_adapter.rb +61 -0
  29. data/lib/authlogic/crypto_providers/aes256.rb +43 -0
  30. data/lib/authlogic/crypto_providers/bcrypt.rb +90 -0
  31. data/lib/authlogic/crypto_providers/md5.rb +34 -0
  32. data/lib/authlogic/crypto_providers/sha1.rb +35 -0
  33. data/lib/authlogic/crypto_providers/sha256.rb +50 -0
  34. data/lib/authlogic/crypto_providers/sha512.rb +50 -0
  35. data/lib/authlogic/crypto_providers/wordpress.rb +43 -0
  36. data/lib/authlogic/i18n/translator.rb +15 -0
  37. data/lib/authlogic/i18n.rb +83 -0
  38. data/lib/authlogic/random.rb +33 -0
  39. data/lib/authlogic/regex.rb +25 -0
  40. data/lib/authlogic/session/activation.rb +58 -0
  41. data/lib/authlogic/session/active_record_trickery.rb +64 -0
  42. data/lib/authlogic/session/base.rb +37 -0
  43. data/lib/authlogic/session/brute_force_protection.rb +96 -0
  44. data/lib/authlogic/session/callbacks.rb +99 -0
  45. data/lib/authlogic/session/cookies.rb +130 -0
  46. data/lib/authlogic/session/existence.rb +93 -0
  47. data/lib/authlogic/session/foundation.rb +63 -0
  48. data/lib/authlogic/session/http_auth.rb +58 -0
  49. data/lib/authlogic/session/id.rb +41 -0
  50. data/lib/authlogic/session/klass.rb +78 -0
  51. data/lib/authlogic/session/magic_columns.rb +95 -0
  52. data/lib/authlogic/session/magic_states.rb +59 -0
  53. data/lib/authlogic/session/params.rb +101 -0
  54. data/lib/authlogic/session/password.rb +240 -0
  55. data/lib/authlogic/session/perishable_token.rb +18 -0
  56. data/lib/authlogic/session/persistence.rb +70 -0
  57. data/lib/authlogic/session/priority_record.rb +34 -0
  58. data/lib/authlogic/session/scopes.rb +101 -0
  59. data/lib/authlogic/session/session.rb +62 -0
  60. data/lib/authlogic/session/timeout.rb +82 -0
  61. data/lib/authlogic/session/unauthorized_record.rb +50 -0
  62. data/lib/authlogic/session/validation.rb +82 -0
  63. data/lib/authlogic/test_case/mock_controller.rb +45 -0
  64. data/lib/authlogic/test_case/mock_cookie_jar.rb +14 -0
  65. data/lib/authlogic/test_case/mock_logger.rb +10 -0
  66. data/lib/authlogic/test_case/mock_request.rb +19 -0
  67. data/lib/authlogic/test_case/rails_request_adapter.rb +30 -0
  68. data/lib/authlogic/test_case.rb +120 -0
  69. data/lib/authlogic.rb +64 -0
  70. data/rails/init.rb +1 -0
  71. data/shoulda_macros/authlogic.rb +69 -0
  72. data/test/acts_as_authentic_test/base_test.rb +18 -0
  73. data/test/acts_as_authentic_test/email_test.rb +105 -0
  74. data/test/acts_as_authentic_test/logged_in_status_test.rb +36 -0
  75. data/test/acts_as_authentic_test/login_test.rb +109 -0
  76. data/test/acts_as_authentic_test/magic_columns_test.rb +27 -0
  77. data/test/acts_as_authentic_test/password_test.rb +236 -0
  78. data/test/acts_as_authentic_test/perishable_token_test.rb +90 -0
  79. data/test/acts_as_authentic_test/persistence_token_test.rb +55 -0
  80. data/test/acts_as_authentic_test/restful_authentication_test.rb +40 -0
  81. data/test/acts_as_authentic_test/session_maintenance_test.rb +84 -0
  82. data/test/acts_as_authentic_test/single_access_test.rb +44 -0
  83. data/test/authenticates_many_test.rb +16 -0
  84. data/test/crypto_provider_test/aes256_test.rb +14 -0
  85. data/test/crypto_provider_test/bcrypt_test.rb +14 -0
  86. data/test/crypto_provider_test/sha1_test.rb +23 -0
  87. data/test/crypto_provider_test/sha256_test.rb +14 -0
  88. data/test/crypto_provider_test/sha512_test.rb +14 -0
  89. data/test/fixtures/companies.yml +5 -0
  90. data/test/fixtures/employees.yml +17 -0
  91. data/test/fixtures/projects.yml +3 -0
  92. data/test/fixtures/users.yml +24 -0
  93. data/test/i18n_test.rb +33 -0
  94. data/test/libs/affiliate.rb +7 -0
  95. data/test/libs/company.rb +6 -0
  96. data/test/libs/employee.rb +7 -0
  97. data/test/libs/employee_session.rb +2 -0
  98. data/test/libs/ldaper.rb +3 -0
  99. data/test/libs/ordered_hash.rb +9 -0
  100. data/test/libs/project.rb +3 -0
  101. data/test/libs/user.rb +5 -0
  102. data/test/libs/user_session.rb +6 -0
  103. data/test/random_test.rb +49 -0
  104. data/test/session_test/activation_test.rb +43 -0
  105. data/test/session_test/active_record_trickery_test.rb +36 -0
  106. data/test/session_test/brute_force_protection_test.rb +101 -0
  107. data/test/session_test/callbacks_test.rb +6 -0
  108. data/test/session_test/cookies_test.rb +112 -0
  109. data/test/session_test/credentials_test.rb +0 -0
  110. data/test/session_test/existence_test.rb +64 -0
  111. data/test/session_test/http_auth_test.rb +28 -0
  112. data/test/session_test/id_test.rb +17 -0
  113. data/test/session_test/klass_test.rb +40 -0
  114. data/test/session_test/magic_columns_test.rb +62 -0
  115. data/test/session_test/magic_states_test.rb +60 -0
  116. data/test/session_test/params_test.rb +53 -0
  117. data/test/session_test/password_test.rb +106 -0
  118. data/test/session_test/perishability_test.rb +15 -0
  119. data/test/session_test/persistence_test.rb +21 -0
  120. data/test/session_test/scopes_test.rb +60 -0
  121. data/test/session_test/session_test.rb +59 -0
  122. data/test/session_test/timeout_test.rb +52 -0
  123. data/test/session_test/unauthorized_record_test.rb +13 -0
  124. data/test/session_test/validation_test.rb +23 -0
  125. data/test/test_helper.rb +182 -0
  126. metadata +248 -0
@@ -0,0 +1,96 @@
1
+ module Authlogic
2
+ module Session
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
4
+ # generally combated with a slow hasing algorithm such as BCrypt. You can increase the cost, which makes the hash generation slower, and ultimately
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
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.
8
+ #
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
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
11
+ # after 50 attempts their account will be suspended. This is a very liberal number and at this point it should be obvious that something is not right.
12
+ # If you wish to lower this number just set the configuration to a lower number:
13
+ #
14
+ # class UserSession < Authlogic::Session::Base
15
+ # consecutive_failed_logins_limit 10
16
+ # end
17
+ module BruteForceProtection
18
+ def self.included(klass)
19
+ klass.class_eval do
20
+ extend Config
21
+ include InstanceMethods
22
+ validate :reset_failed_login_count, :if => :reset_failed_login_count?
23
+ validate :validate_failed_logins, :if => :being_brute_force_protected?
24
+ end
25
+ end
26
+
27
+ # Configuration for the brute force protection feature.
28
+ module Config
29
+ # 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
30
+ # 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.
31
+ #
32
+ # In order to enable this field your model MUST have a failed_login_count (integer) field.
33
+ #
34
+ # 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
35
+ # in possibly millions of attempts to log into an account.
36
+ #
37
+ # * <tt>Default:</tt> 50
38
+ # * <tt>Accepts:</tt> Integer, set to 0 to disable
39
+ def consecutive_failed_logins_limit(value = nil)
40
+ rw_config(:consecutive_failed_logins_limit, value, 50)
41
+ end
42
+ alias_method :consecutive_failed_logins_limit=, :consecutive_failed_logins_limit
43
+
44
+ # 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.
45
+ #
46
+ # * <tt>Default:</tt> 2.hours
47
+ # * <tt>Accepts:</tt> Fixnum, set to 0 for permanent ban
48
+ def failed_login_ban_for(value = nil)
49
+ rw_config(:failed_login_ban_for, (!value.nil? && value) || value, 2.hours.to_i)
50
+ end
51
+ alias_method :failed_login_ban_for=, :failed_login_ban_for
52
+ end
53
+
54
+ # The methods available for an Authlogic::Session::Base object that make up the brute force protection feature.
55
+ module InstanceMethods
56
+ # Returns true when the consecutive_failed_logins_limit has been exceeded and is being temporarily banned.
57
+ # Notice the word temporary, the user will not be permanently banned unless you choose to do so with configuration.
58
+ # By default they will be banned for 2 hours. During that 2 hour period this method will return true.
59
+ def being_brute_force_protected?
60
+ exceeded_failed_logins_limit? && (failed_login_ban_for <= 0 ||
61
+ (attempted_record.respond_to?(:updated_at) && attempted_record.updated_at >= failed_login_ban_for.seconds.ago))
62
+ end
63
+
64
+ private
65
+ def exceeded_failed_logins_limit?
66
+ !attempted_record.nil? && attempted_record.respond_to?(:failed_login_count) && consecutive_failed_logins_limit > 0 &&
67
+ attempted_record.failed_login_count && attempted_record.failed_login_count >= consecutive_failed_logins_limit
68
+ end
69
+
70
+ def reset_failed_login_count?
71
+ exceeded_failed_logins_limit? && !being_brute_force_protected?
72
+ end
73
+
74
+ def reset_failed_login_count
75
+ attempted_record.failed_login_count = 0
76
+ end
77
+
78
+ def validate_failed_logins
79
+ errors.clear # Clear all other error messages, as they are irrelevant at this point and can only provide additional information that is not needed
80
+ errors.add(:base, I18n.t(
81
+ 'error_messages.consecutive_failed_logins_limit_exceeded',
82
+ :default => "Consecutive failed logins limit exceeded, account has been" + (failed_login_ban_for == 0 ? "" : " temporarily") + " disabled."
83
+ ))
84
+ end
85
+
86
+ def consecutive_failed_logins_limit
87
+ self.class.consecutive_failed_logins_limit
88
+ end
89
+
90
+ def failed_login_ban_for
91
+ self.class.failed_login_ban_for
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,99 @@
1
+ module Authlogic
2
+ module Session
3
+ # Between these callsbacks and the configuration, this is the contract between me and you to safely
4
+ # modify Authlogic's behavior. I will do everything I can to make sure these do not change.
5
+ #
6
+ # Check out the sub modules of Authlogic::Session. They are very concise, clear, and to the point. More
7
+ # importantly they use the same API that you would use to extend Authlogic. That being said, they are great
8
+ # examples of how to extend Authlogic and add / modify behavior to Authlogic. These modules could easily be pulled out
9
+ # into their own plugin and become an "add on" without any change.
10
+ #
11
+ # Now to the point of this module. Just like in ActiveRecord you have before_save, before_validation, etc.
12
+ # You have similar callbacks with Authlogic, see the METHODS constant below. The order of execution is as follows:
13
+ #
14
+ # before_persisting
15
+ # persist
16
+ # after_persisting
17
+ # [save record if record.changed?]
18
+ #
19
+ # before_validation
20
+ # before_validation_on_create
21
+ # before_validation_on_update
22
+ # validate
23
+ # after_validation_on_update
24
+ # after_validation_on_create
25
+ # after_validation
26
+ # [save record if record.changed?]
27
+ #
28
+ # before_save
29
+ # before_create
30
+ # before_update
31
+ # after_update
32
+ # after_create
33
+ # after_save
34
+ # [save record if record.changed?]
35
+ #
36
+ # before_destroy
37
+ # [save record if record.changed?]
38
+ # destroy
39
+ # after_destroy
40
+ #
41
+ # Notice the "save record if changed?" lines above. This helps with performance. If you need to make
42
+ # changes to the associated record, there is no need to save the record, Authlogic will do it for you.
43
+ # This allows multiple modules to modify the record and execute as few queries as possible.
44
+ #
45
+ # **WARNING**: unlike ActiveRecord, these callbacks must be set up on the class level:
46
+ #
47
+ # class UserSession < Authlogic::Session::Base
48
+ # before_validation :my_method
49
+ # validate :another_method
50
+ # # ..etc
51
+ # end
52
+ #
53
+ # You can NOT define a "before_validation" method, this is bad practice and does not allow Authlogic
54
+ # to extend properly with multiple extensions. Please ONLY use the method above.
55
+ module Callbacks
56
+ METHODS = [
57
+ "before_persisting", "persist", "after_persisting",
58
+ "before_validation", "before_validation_on_create", "before_validation_on_update", "validate",
59
+ "after_validation_on_update", "after_validation_on_create", "after_validation",
60
+ "before_save", "before_create", "before_update", "after_update", "after_create", "after_save",
61
+ "before_destroy", "after_destroy"
62
+ ]
63
+
64
+ def self.included(base) #:nodoc:
65
+ base.send :include, ActiveSupport::Callbacks
66
+ base.define_callbacks *METHODS
67
+
68
+ # If Rails 3, support the new callback syntax
69
+ if base.metaclass.method_defined?(:set_callback)
70
+ METHODS.each do |method|
71
+ base.class_eval <<-"end_eval", __FILE__, __LINE__
72
+ def self.#{method}(*methods, &block)
73
+ set_callback :#{method}, *methods, &block
74
+ end
75
+ end_eval
76
+ end
77
+ end
78
+ end
79
+
80
+ private
81
+ METHODS.each do |method|
82
+ class_eval <<-"end_eval", __FILE__, __LINE__
83
+ def #{method}
84
+ run_callbacks(:#{method}) { |result, object| result == false }
85
+ end
86
+ end_eval
87
+ end
88
+
89
+ def persist
90
+ run_callbacks(:persist) { |result, object| result == true }
91
+ end
92
+
93
+ def save_record(alternate_record = nil)
94
+ r = alternate_record || record
95
+ r.save_without_session_maintenance(false) if r && r.changed? && !r.readonly?
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,130 @@
1
+ module Authlogic
2
+ module Session
3
+ # Handles all authentication that deals with cookies, such as persisting, saving, and destroying.
4
+ module Cookies
5
+ def self.included(klass)
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
13
+ end
14
+
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> "#{guessed_klass_name.underscore}_credentials"
27
+ # * <tt>Accepts:</tt> String
28
+ def cookie_key(value = nil)
29
+ rw_config(:cookie_key, value, "#{guessed_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
+ rw_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
+ rw_config(:remember_me_for, value, 3.months, :_read)
48
+ end
49
+ alias_method :remember_me_for=, :remember_me_for
50
+ end
51
+
52
+ # The methods available for an Authlogic::Session::Base object that make up the cookie feature set.
53
+ module InstanceMethods
54
+ # Allows you to set the remember_me option when passing credentials.
55
+ def credentials=(value)
56
+ super
57
+ values = value.is_a?(Array) ? value : [value]
58
+ case values.first
59
+ when Hash
60
+ self.remember_me = values.first.with_indifferent_access[:remember_me] if values.first.with_indifferent_access.key?(:remember_me)
61
+ else
62
+ r = values.find { |value| value.is_a?(TrueClass) || value.is_a?(FalseClass) }
63
+ self.remember_me = r if !r.nil?
64
+ end
65
+ end
66
+
67
+ # Is the cookie going to expire after the session is over, or will it stick around?
68
+ def remember_me
69
+ return @remember_me if defined?(@remember_me)
70
+ @remember_me = self.class.remember_me
71
+ end
72
+
73
+ # 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".
74
+ def remember_me=(value)
75
+ @remember_me = value
76
+ end
77
+
78
+ # See remember_me
79
+ def remember_me?
80
+ remember_me == true || remember_me == "true" || remember_me == "1"
81
+ end
82
+
83
+ # How long to remember the user if remember_me is true. This is based on the class level configuration: remember_me_for
84
+ def remember_me_for
85
+ return unless remember_me?
86
+ self.class.remember_me_for
87
+ end
88
+
89
+ # When to expire the cookie. See remember_me_for configuration option to change this.
90
+ def remember_me_until
91
+ return unless remember_me?
92
+ remember_me_for.from_now
93
+ end
94
+
95
+ private
96
+ def cookie_key
97
+ build_key(self.class.cookie_key)
98
+ end
99
+
100
+ def cookie_credentials
101
+ controller.cookies[cookie_key] && controller.cookies[cookie_key].split("::")
102
+ end
103
+
104
+ # Tries to validate the session from information in the cookie
105
+ def persist_by_cookie
106
+ persistence_token, record_id = cookie_credentials
107
+ if !persistence_token.nil?
108
+ record = record_id.nil? ? search_for_record("find_by_persistence_token", persistence_token) : search_for_record("find_by_#{klass.primary_key}", record_id)
109
+ self.unauthorized_record = record if record && record.persistence_token == persistence_token
110
+ valid?
111
+ else
112
+ false
113
+ end
114
+ end
115
+
116
+ def save_cookie
117
+ controller.cookies[cookie_key] = {
118
+ :value => "#{record.persistence_token}::#{record.send(record.class.primary_key)}",
119
+ :expires => remember_me_until,
120
+ :domain => controller.cookie_domain
121
+ }
122
+ end
123
+
124
+ def destroy_cookie
125
+ controller.cookies.delete cookie_key, :domain => controller.cookie_domain
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,93 @@
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
+ session
32
+ end
33
+
34
+ # Same as create but calls create!, which raises an exception when validation fails.
35
+ def create!(*args)
36
+ session = new(*args)
37
+ session.save!
38
+ session
39
+ end
40
+ end
41
+
42
+ module InstanceMethods
43
+ # Clears all errors and the associated record, you should call this terminate a session, thus requring
44
+ # the user to authenticate again if it is needed.
45
+ def destroy
46
+ before_destroy
47
+ save_record
48
+ errors.clear
49
+ @record = nil
50
+ after_destroy
51
+ true
52
+ end
53
+
54
+ # Returns true if the session is new, meaning no action has been taken on it and a successful save
55
+ # has not taken place.
56
+ def new_session?
57
+ new_session != false
58
+ end
59
+
60
+ # After you have specified all of the details for your session you can try to save it. This will
61
+ # run validation checks and find the associated record, if all validation passes. If validation
62
+ # does not pass, the save will fail and the erorrs will be stored in the errors object.
63
+ def save(&block)
64
+ result = nil
65
+ if valid?
66
+ self.record = attempted_record
67
+
68
+ before_save
69
+ new_session? ? before_create : before_update
70
+ new_session? ? after_create : after_update
71
+ after_save
72
+
73
+ save_record
74
+ self.new_session = false
75
+ result = true
76
+ else
77
+ result = false
78
+ end
79
+
80
+ yield result if block_given?
81
+ result
82
+ end
83
+
84
+ # Same as save but raises an exception of validation errors when validation fails
85
+ def save!
86
+ result = save
87
+ raise SessionInvalidError.new(self) unless result
88
+ result
89
+ end
90
+ end
91
+ end
92
+ end
93
+ 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.credentials = [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,78 @@
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 ||= guessed_klass_name
42
+ end
43
+
44
+ # The string of the model name class guessed from the actual session class name.
45
+ def guessed_klass_name
46
+ guessed_name = name.scan(/(.*)Session/)[0]
47
+ guessed_name[0] if guessed_name
48
+ end
49
+ end
50
+
51
+ module InstanceMethods
52
+ # Creating an alias method for the "record" method based on the klass name, so that we can do:
53
+ #
54
+ # session.user
55
+ #
56
+ # instead of:
57
+ #
58
+ # session.record
59
+ def initialize(*args)
60
+ if !self.class.configured_klass_methods
61
+ self.class.send(:alias_method, klass_name.demodulize.underscore.to_sym, :record)
62
+ self.class.configured_klass_methods = true
63
+ end
64
+ super
65
+ end
66
+
67
+ private
68
+ def klass
69
+ self.class.klass
70
+ end
71
+
72
+ def klass_name
73
+ self.class.klass_name
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end