wulffeld_authlogic 2.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/CHANGELOG.rdoc +345 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +246 -0
  4. data/Rakefile +41 -0
  5. data/VERSION.yml +5 -0
  6. data/generators/session/session_generator.rb +9 -0
  7. data/generators/session/templates/session.rb +2 -0
  8. data/init.rb +1 -0
  9. data/lib/authlogic.rb +64 -0
  10. data/lib/authlogic/acts_as_authentic/base.rb +107 -0
  11. data/lib/authlogic/acts_as_authentic/email.rb +110 -0
  12. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +60 -0
  13. data/lib/authlogic/acts_as_authentic/login.rb +141 -0
  14. data/lib/authlogic/acts_as_authentic/magic_columns.rb +24 -0
  15. data/lib/authlogic/acts_as_authentic/password.rb +355 -0
  16. data/lib/authlogic/acts_as_authentic/perishable_token.rb +105 -0
  17. data/lib/authlogic/acts_as_authentic/persistence_token.rb +68 -0
  18. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +61 -0
  19. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +139 -0
  20. data/lib/authlogic/acts_as_authentic/single_access_token.rb +65 -0
  21. data/lib/authlogic/acts_as_authentic/validations_scope.rb +32 -0
  22. data/lib/authlogic/authenticates_many/association.rb +42 -0
  23. data/lib/authlogic/authenticates_many/base.rb +55 -0
  24. data/lib/authlogic/controller_adapters/abstract_adapter.rb +67 -0
  25. data/lib/authlogic/controller_adapters/merb_adapter.rb +30 -0
  26. data/lib/authlogic/controller_adapters/rails_adapter.rb +52 -0
  27. data/lib/authlogic/controller_adapters/sinatra_adapter.rb +61 -0
  28. data/lib/authlogic/crypto_providers/aes256.rb +43 -0
  29. data/lib/authlogic/crypto_providers/bcrypt.rb +90 -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/sha256.rb +50 -0
  33. data/lib/authlogic/crypto_providers/sha512.rb +50 -0
  34. data/lib/authlogic/crypto_providers/wordpress.rb +43 -0
  35. data/lib/authlogic/i18n.rb +83 -0
  36. data/lib/authlogic/i18n/translator.rb +15 -0
  37. data/lib/authlogic/random.rb +33 -0
  38. data/lib/authlogic/regex.rb +25 -0
  39. data/lib/authlogic/session/activation.rb +58 -0
  40. data/lib/authlogic/session/active_record_trickery.rb +64 -0
  41. data/lib/authlogic/session/base.rb +39 -0
  42. data/lib/authlogic/session/brute_force_protection.rb +96 -0
  43. data/lib/authlogic/session/callbacks.rb +99 -0
  44. data/lib/authlogic/session/cookies.rb +130 -0
  45. data/lib/authlogic/session/existence.rb +93 -0
  46. data/lib/authlogic/session/foundation.rb +65 -0
  47. data/lib/authlogic/session/http_auth.rb +58 -0
  48. data/lib/authlogic/session/id.rb +41 -0
  49. data/lib/authlogic/session/klass.rb +78 -0
  50. data/lib/authlogic/session/magic_columns.rb +95 -0
  51. data/lib/authlogic/session/magic_states.rb +59 -0
  52. data/lib/authlogic/session/params.rb +101 -0
  53. data/lib/authlogic/session/password.rb +240 -0
  54. data/lib/authlogic/session/perishable_token.rb +18 -0
  55. data/lib/authlogic/session/persistence.rb +70 -0
  56. data/lib/authlogic/session/priority_record.rb +34 -0
  57. data/lib/authlogic/session/scopes.rb +101 -0
  58. data/lib/authlogic/session/session.rb +62 -0
  59. data/lib/authlogic/session/timeout.rb +82 -0
  60. data/lib/authlogic/session/unauthorized_record.rb +50 -0
  61. data/lib/authlogic/session/validation.rb +82 -0
  62. data/lib/authlogic/test_case.rb +120 -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/generators/authlogic/session/USAGE +5 -0
  69. data/lib/generators/authlogic/session/session_generator.rb +14 -0
  70. data/lib/generators/authlogic/session/templates/session.rb +2 -0
  71. data/rails/init.rb +1 -0
  72. data/shoulda_macros/authlogic.rb +69 -0
  73. data/test/acts_as_authentic_test/base_test.rb +18 -0
  74. data/test/acts_as_authentic_test/email_test.rb +97 -0
  75. data/test/acts_as_authentic_test/logged_in_status_test.rb +36 -0
  76. data/test/acts_as_authentic_test/login_test.rb +109 -0
  77. data/test/acts_as_authentic_test/magic_columns_test.rb +27 -0
  78. data/test/acts_as_authentic_test/password_test.rb +236 -0
  79. data/test/acts_as_authentic_test/perishable_token_test.rb +90 -0
  80. data/test/acts_as_authentic_test/persistence_token_test.rb +55 -0
  81. data/test/acts_as_authentic_test/restful_authentication_test.rb +40 -0
  82. data/test/acts_as_authentic_test/session_maintenance_test.rb +84 -0
  83. data/test/acts_as_authentic_test/single_access_test.rb +44 -0
  84. data/test/authenticates_many_test.rb +16 -0
  85. data/test/crypto_provider_test/aes256_test.rb +14 -0
  86. data/test/crypto_provider_test/bcrypt_test.rb +14 -0
  87. data/test/crypto_provider_test/sha1_test.rb +23 -0
  88. data/test/crypto_provider_test/sha256_test.rb +14 -0
  89. data/test/crypto_provider_test/sha512_test.rb +14 -0
  90. data/test/fixtures/companies.yml +5 -0
  91. data/test/fixtures/employees.yml +17 -0
  92. data/test/fixtures/projects.yml +3 -0
  93. data/test/fixtures/users.yml +24 -0
  94. data/test/i18n_test.rb +33 -0
  95. data/test/libs/affiliate.rb +7 -0
  96. data/test/libs/company.rb +6 -0
  97. data/test/libs/employee.rb +7 -0
  98. data/test/libs/employee_session.rb +2 -0
  99. data/test/libs/ldaper.rb +3 -0
  100. data/test/libs/ordered_hash.rb +9 -0
  101. data/test/libs/project.rb +3 -0
  102. data/test/libs/user.rb +5 -0
  103. data/test/libs/user_session.rb +6 -0
  104. data/test/random_test.rb +49 -0
  105. data/test/session_test/activation_test.rb +43 -0
  106. data/test/session_test/active_record_trickery_test.rb +36 -0
  107. data/test/session_test/brute_force_protection_test.rb +101 -0
  108. data/test/session_test/callbacks_test.rb +6 -0
  109. data/test/session_test/cookies_test.rb +112 -0
  110. data/test/session_test/credentials_test.rb +0 -0
  111. data/test/session_test/existence_test.rb +64 -0
  112. data/test/session_test/http_auth_test.rb +28 -0
  113. data/test/session_test/id_test.rb +17 -0
  114. data/test/session_test/klass_test.rb +40 -0
  115. data/test/session_test/lint_test.rb +9 -0
  116. data/test/session_test/magic_columns_test.rb +62 -0
  117. data/test/session_test/magic_states_test.rb +60 -0
  118. data/test/session_test/params_test.rb +53 -0
  119. data/test/session_test/password_test.rb +106 -0
  120. data/test/session_test/perishability_test.rb +15 -0
  121. data/test/session_test/persistence_test.rb +21 -0
  122. data/test/session_test/scopes_test.rb +60 -0
  123. data/test/session_test/session_test.rb +59 -0
  124. data/test/session_test/timeout_test.rb +52 -0
  125. data/test/session_test/unauthorized_record_test.rb +13 -0
  126. data/test/session_test/validation_test.rb +23 -0
  127. data/test/test_helper.rb +183 -0
  128. data/wulffeld_authlogic.gemspec +220 -0
  129. metadata +258 -0
@@ -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.singleton_class.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(:validate => 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,65 @@
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
+ def persisted?() false end
57
+
58
+ private
59
+ def build_key(last_part)
60
+ last_part
61
+ end
62
+ end
63
+ end
64
+ end
65
+ 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