antlypls-authlogic 3.0.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/Gemfile +10 -0
  2. data/Gemfile.lock +30 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +253 -0
  5. data/Rakefile +42 -0
  6. data/VERSION.yml +5 -0
  7. data/authlogic.gemspec +220 -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.rb +64 -0
  12. data/lib/authlogic/acts_as_authentic/base.rb +109 -0
  13. data/lib/authlogic/acts_as_authentic/email.rb +110 -0
  14. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +60 -0
  15. data/lib/authlogic/acts_as_authentic/login.rb +142 -0
  16. data/lib/authlogic/acts_as_authentic/magic_columns.rb +24 -0
  17. data/lib/authlogic/acts_as_authentic/password.rb +355 -0
  18. data/lib/authlogic/acts_as_authentic/perishable_token.rb +105 -0
  19. data/lib/authlogic/acts_as_authentic/persistence_token.rb +68 -0
  20. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +61 -0
  21. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +139 -0
  22. data/lib/authlogic/acts_as_authentic/single_access_token.rb +65 -0
  23. data/lib/authlogic/acts_as_authentic/validations_scope.rb +32 -0
  24. data/lib/authlogic/authenticates_many/association.rb +42 -0
  25. data/lib/authlogic/authenticates_many/base.rb +54 -0
  26. data/lib/authlogic/controller_adapters/abstract_adapter.rb +67 -0
  27. data/lib/authlogic/controller_adapters/merb_adapter.rb +30 -0
  28. data/lib/authlogic/controller_adapters/rails_adapter.rb +48 -0
  29. data/lib/authlogic/controller_adapters/sinatra_adapter.rb +61 -0
  30. data/lib/authlogic/crypto_providers/aes256.rb +43 -0
  31. data/lib/authlogic/crypto_providers/bcrypt.rb +90 -0
  32. data/lib/authlogic/crypto_providers/md5.rb +34 -0
  33. data/lib/authlogic/crypto_providers/sha1.rb +35 -0
  34. data/lib/authlogic/crypto_providers/sha256.rb +50 -0
  35. data/lib/authlogic/crypto_providers/sha512.rb +50 -0
  36. data/lib/authlogic/crypto_providers/wordpress.rb +43 -0
  37. data/lib/authlogic/i18n.rb +83 -0
  38. data/lib/authlogic/i18n/translator.rb +15 -0
  39. data/lib/authlogic/random.rb +33 -0
  40. data/lib/authlogic/regex.rb +25 -0
  41. data/lib/authlogic/session/activation.rb +58 -0
  42. data/lib/authlogic/session/active_record_trickery.rb +72 -0
  43. data/lib/authlogic/session/base.rb +37 -0
  44. data/lib/authlogic/session/brute_force_protection.rb +96 -0
  45. data/lib/authlogic/session/callbacks.rb +99 -0
  46. data/lib/authlogic/session/cookies.rb +182 -0
  47. data/lib/authlogic/session/existence.rb +93 -0
  48. data/lib/authlogic/session/foundation.rb +77 -0
  49. data/lib/authlogic/session/http_auth.rb +99 -0
  50. data/lib/authlogic/session/id.rb +41 -0
  51. data/lib/authlogic/session/klass.rb +78 -0
  52. data/lib/authlogic/session/magic_columns.rb +95 -0
  53. data/lib/authlogic/session/magic_states.rb +59 -0
  54. data/lib/authlogic/session/params.rb +101 -0
  55. data/lib/authlogic/session/password.rb +240 -0
  56. data/lib/authlogic/session/perishable_token.rb +18 -0
  57. data/lib/authlogic/session/persistence.rb +70 -0
  58. data/lib/authlogic/session/priority_record.rb +34 -0
  59. data/lib/authlogic/session/scopes.rb +101 -0
  60. data/lib/authlogic/session/session.rb +62 -0
  61. data/lib/authlogic/session/timeout.rb +82 -0
  62. data/lib/authlogic/session/unauthorized_record.rb +50 -0
  63. data/lib/authlogic/session/validation.rb +82 -0
  64. data/lib/authlogic/test_case.rb +120 -0
  65. data/lib/authlogic/test_case/mock_controller.rb +55 -0
  66. data/lib/authlogic/test_case/mock_cookie_jar.rb +14 -0
  67. data/lib/authlogic/test_case/mock_logger.rb +10 -0
  68. data/lib/authlogic/test_case/mock_request.rb +19 -0
  69. data/lib/authlogic/test_case/rails_request_adapter.rb +30 -0
  70. data/lib/generators/authlogic/USAGE +8 -0
  71. data/lib/generators/authlogic/session_generator.rb +14 -0
  72. data/lib/generators/authlogic/templates/session.rb +2 -0
  73. data/rails/init.rb +1 -0
  74. data/shoulda_macros/authlogic.rb +69 -0
  75. data/test/acts_as_authentic_test/base_test.rb +18 -0
  76. data/test/acts_as_authentic_test/email_test.rb +105 -0
  77. data/test/acts_as_authentic_test/logged_in_status_test.rb +36 -0
  78. data/test/acts_as_authentic_test/login_test.rb +109 -0
  79. data/test/acts_as_authentic_test/magic_columns_test.rb +27 -0
  80. data/test/acts_as_authentic_test/password_test.rb +236 -0
  81. data/test/acts_as_authentic_test/perishable_token_test.rb +90 -0
  82. data/test/acts_as_authentic_test/persistence_token_test.rb +55 -0
  83. data/test/acts_as_authentic_test/restful_authentication_test.rb +40 -0
  84. data/test/acts_as_authentic_test/session_maintenance_test.rb +84 -0
  85. data/test/acts_as_authentic_test/single_access_test.rb +44 -0
  86. data/test/authenticates_many_test.rb +16 -0
  87. data/test/crypto_provider_test/aes256_test.rb +14 -0
  88. data/test/crypto_provider_test/bcrypt_test.rb +14 -0
  89. data/test/crypto_provider_test/sha1_test.rb +23 -0
  90. data/test/crypto_provider_test/sha256_test.rb +14 -0
  91. data/test/crypto_provider_test/sha512_test.rb +14 -0
  92. data/test/fixtures/companies.yml +5 -0
  93. data/test/fixtures/employees.yml +17 -0
  94. data/test/fixtures/projects.yml +3 -0
  95. data/test/fixtures/users.yml +24 -0
  96. data/test/i18n_test.rb +33 -0
  97. data/test/libs/affiliate.rb +7 -0
  98. data/test/libs/company.rb +6 -0
  99. data/test/libs/employee.rb +7 -0
  100. data/test/libs/employee_session.rb +2 -0
  101. data/test/libs/ldaper.rb +3 -0
  102. data/test/libs/ordered_hash.rb +9 -0
  103. data/test/libs/project.rb +3 -0
  104. data/test/libs/user.rb +5 -0
  105. data/test/libs/user_session.rb +6 -0
  106. data/test/random_test.rb +42 -0
  107. data/test/session_test/activation_test.rb +43 -0
  108. data/test/session_test/active_record_trickery_test.rb +46 -0
  109. data/test/session_test/brute_force_protection_test.rb +101 -0
  110. data/test/session_test/callbacks_test.rb +6 -0
  111. data/test/session_test/cookies_test.rb +136 -0
  112. data/test/session_test/credentials_test.rb +0 -0
  113. data/test/session_test/existence_test.rb +64 -0
  114. data/test/session_test/http_auth_test.rb +56 -0
  115. data/test/session_test/id_test.rb +17 -0
  116. data/test/session_test/klass_test.rb +40 -0
  117. data/test/session_test/magic_columns_test.rb +62 -0
  118. data/test/session_test/magic_states_test.rb +60 -0
  119. data/test/session_test/params_test.rb +53 -0
  120. data/test/session_test/password_test.rb +106 -0
  121. data/test/session_test/perishability_test.rb +15 -0
  122. data/test/session_test/persistence_test.rb +21 -0
  123. data/test/session_test/scopes_test.rb +60 -0
  124. data/test/session_test/session_test.rb +59 -0
  125. data/test/session_test/timeout_test.rb +52 -0
  126. data/test/session_test/unauthorized_record_test.rb +13 -0
  127. data/test/session_test/validation_test.rb +23 -0
  128. data/test/test_helper.rb +168 -0
  129. metadata +224 -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.send(base.respond_to?(:singleton_class) ? :singleton_class : :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(:validate => false) if r && r.changed? && !r.readonly?
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,182 @@
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
+
51
+ # Should the cookie be set as secure? If true, the cookie will only be sent over SSL connections
52
+ #
53
+ # * <tt>Default:</tt> false
54
+ # * <tt>Accepts:</tt> Boolean
55
+ def secure(value = nil)
56
+ rw_config(:secure, value, false)
57
+ end
58
+ alias_method :secure=, :secure
59
+
60
+ # Should the cookie be set as httponly? If true, the cookie will not be accessable from javascript
61
+ #
62
+ # * <tt>Default:</tt> false
63
+ # * <tt>Accepts:</tt> Boolean
64
+ def httponly(value = nil)
65
+ rw_config(:httponly, value, false)
66
+ end
67
+ alias_method :httponly=, :httponly
68
+ end
69
+
70
+ # The methods available for an Authlogic::Session::Base object that make up the cookie feature set.
71
+ module InstanceMethods
72
+ # Allows you to set the remember_me option when passing credentials.
73
+ def credentials=(value)
74
+ super
75
+ values = value.is_a?(Array) ? value : [value]
76
+ case values.first
77
+ when Hash
78
+ self.remember_me = values.first.with_indifferent_access[:remember_me] if values.first.with_indifferent_access.key?(:remember_me)
79
+ else
80
+ r = values.find { |value| value.is_a?(TrueClass) || value.is_a?(FalseClass) }
81
+ self.remember_me = r if !r.nil?
82
+ end
83
+ end
84
+
85
+ # Is the cookie going to expire after the session is over, or will it stick around?
86
+ def remember_me
87
+ return @remember_me if defined?(@remember_me)
88
+ @remember_me = self.class.remember_me
89
+ end
90
+
91
+ # 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".
92
+ def remember_me=(value)
93
+ @remember_me = value
94
+ end
95
+
96
+ # See remember_me
97
+ def remember_me?
98
+ remember_me == true || remember_me == "true" || remember_me == "1"
99
+ end
100
+
101
+ # How long to remember the user if remember_me is true. This is based on the class level configuration: remember_me_for
102
+ def remember_me_for
103
+ return unless remember_me?
104
+ self.class.remember_me_for
105
+ end
106
+
107
+ # When to expire the cookie. See remember_me_for configuration option to change this.
108
+ def remember_me_until
109
+ return unless remember_me?
110
+ remember_me_for.from_now
111
+ end
112
+
113
+ # If the cookie should be marked as secure (SSL only)
114
+ def secure
115
+ return @secure if defined?(@secure)
116
+ @secure = self.class.secure
117
+ end
118
+
119
+ # Accepts a boolean as to whether the cookie should be marked as secure. If true the cookie will only ever be sent over an SSL connection.
120
+ def secure=(value)
121
+ @secure = value
122
+ end
123
+
124
+ # See secure
125
+ def secure?
126
+ secure == true || secure == "true" || secure == "1"
127
+ end
128
+
129
+ # If the cookie should be marked as httponly (not accessable via javascript)
130
+ def httponly
131
+ return @httponly if defined?(@httponly)
132
+ @httponly = self.class.httponly
133
+ end
134
+
135
+ # Accepts a boolean as to whether the cookie should be marked as httponly. If true, the cookie will not be accessable from javascript
136
+ def httponly=(value)
137
+ @httponly = value
138
+ end
139
+
140
+ # See httponly
141
+ def httponly?
142
+ httponly == true || httponly == "true" || httponly == "1"
143
+ end
144
+
145
+ private
146
+ def cookie_key
147
+ build_key(self.class.cookie_key)
148
+ end
149
+
150
+ def cookie_credentials
151
+ controller.cookies[cookie_key] && controller.cookies[cookie_key].split("::")
152
+ end
153
+
154
+ # Tries to validate the session from information in the cookie
155
+ def persist_by_cookie
156
+ persistence_token, record_id = cookie_credentials
157
+ if !persistence_token.nil?
158
+ record = record_id.nil? ? search_for_record("find_by_persistence_token", persistence_token) : search_for_record("find_by_#{klass.primary_key}", record_id)
159
+ self.unauthorized_record = record if record && record.persistence_token == persistence_token
160
+ valid?
161
+ else
162
+ false
163
+ end
164
+ end
165
+
166
+ def save_cookie
167
+ controller.cookies[cookie_key] = {
168
+ :value => "#{record.persistence_token}::#{record.send(record.class.primary_key)}",
169
+ :expires => remember_me_until,
170
+ :secure => secure,
171
+ :httponly => httponly,
172
+ :domain => controller.cookie_domain
173
+ }
174
+ end
175
+
176
+ def destroy_cookie
177
+ controller.cookies.delete cookie_key, :domain => controller.cookie_domain
178
+ end
179
+ end
180
+ end
181
+ end
182
+ 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,77 @@
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
+ class_attribute :acts_as_authentic_config
10
+ self.acts_as_authentic_config ||= {}
11
+
12
+ extend ClassMethods
13
+ include InstanceMethods
14
+ end
15
+ end
16
+
17
+ module ClassMethods
18
+ private
19
+ def rw_config(key, value, default_value = nil, read_value = nil)
20
+ if value == read_value
21
+ return acts_as_authentic_config[key] if acts_as_authentic_config.include?(key)
22
+ rw_config(key, default_value)
23
+ else
24
+ config = acts_as_authentic_config.clone
25
+ config[key] = value
26
+ self.acts_as_authentic_config = config
27
+ value
28
+ end
29
+ end
30
+ end
31
+
32
+ module InstanceMethods
33
+ def initialize(*args)
34
+ self.credentials = args
35
+ end
36
+
37
+ # The credentials you passed to create your session. See credentials= for more info.
38
+ def credentials
39
+ []
40
+ end
41
+
42
+ # Set your credentials before you save your session. You can pass a hash of credentials:
43
+ #
44
+ # session.credentials = {:login => "my login", :password => "my password", :remember_me => true}
45
+ #
46
+ # or you can pass an array of objects:
47
+ #
48
+ # session.credentials = [my_user_object, true]
49
+ #
50
+ # 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
51
+ # you control yourself, it should never be set from a hash or a form. Examples:
52
+ #
53
+ # session.credentials = [{:login => "my login", :password => "my password", :remember_me => true}, :my_id]
54
+ # session.credentials = [my_user_object, true, :my_id]
55
+ def credentials=(values)
56
+ end
57
+
58
+ def inspect
59
+ "#<#{self.class.name}: #{credentials.blank? ? "no credentials provided" : credentials.inspect}>"
60
+ end
61
+
62
+ def persisted?
63
+ !(new_record? || destroyed?)
64
+ end
65
+
66
+ def to_key
67
+ new_record? ? nil : [ self.send(self.class.primary_key) ]
68
+ end
69
+
70
+ private
71
+ def build_key(last_part)
72
+ last_part
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end