authlogic 4.4.2 → 5.0.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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/lib/authlogic/acts_as_authentic/base.rb +3 -18
  3. data/lib/authlogic/acts_as_authentic/email.rb +3 -170
  4. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +3 -1
  5. data/lib/authlogic/acts_as_authentic/login.rb +7 -174
  6. data/lib/authlogic/acts_as_authentic/magic_columns.rb +7 -4
  7. data/lib/authlogic/acts_as_authentic/password.rb +54 -253
  8. data/lib/authlogic/acts_as_authentic/perishable_token.rb +7 -5
  9. data/lib/authlogic/acts_as_authentic/persistence_token.rb +9 -4
  10. data/lib/authlogic/acts_as_authentic/queries/case_sensitivity.rb +53 -0
  11. data/lib/authlogic/acts_as_authentic/queries/find_with_case.rb +17 -22
  12. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +8 -6
  13. data/lib/authlogic/acts_as_authentic/single_access_token.rb +9 -8
  14. data/lib/authlogic/config.rb +9 -1
  15. data/lib/authlogic/controller_adapters/abstract_adapter.rb +7 -4
  16. data/lib/authlogic/controller_adapters/rack_adapter.rb +2 -0
  17. data/lib/authlogic/controller_adapters/rails_adapter.rb +17 -14
  18. data/lib/authlogic/controller_adapters/sinatra_adapter.rb +6 -0
  19. data/lib/authlogic/crypto_providers/bcrypt.rb +3 -3
  20. data/lib/authlogic/crypto_providers/md5.rb +3 -6
  21. data/lib/authlogic/crypto_providers/scrypt.rb +2 -0
  22. data/lib/authlogic/crypto_providers/sha1.rb +4 -6
  23. data/lib/authlogic/crypto_providers/sha256.rb +2 -0
  24. data/lib/authlogic/crypto_providers/sha512.rb +6 -5
  25. data/lib/authlogic/crypto_providers.rb +5 -20
  26. data/lib/authlogic/i18n/translator.rb +3 -0
  27. data/lib/authlogic/i18n.rb +3 -1
  28. data/lib/authlogic/random.rb +2 -0
  29. data/lib/authlogic/session/base.rb +2089 -39
  30. data/lib/authlogic/session/magic_column/assigns_last_request_at.rb +46 -0
  31. data/lib/authlogic/test_case/mock_controller.rb +2 -0
  32. data/lib/authlogic/test_case/mock_cookie_jar.rb +7 -0
  33. data/lib/authlogic/test_case/mock_logger.rb +2 -0
  34. data/lib/authlogic/test_case/mock_request.rb +2 -0
  35. data/lib/authlogic/test_case/rails_request_adapter.rb +2 -0
  36. data/lib/authlogic/test_case.rb +4 -0
  37. data/lib/authlogic/version.rb +2 -1
  38. data/lib/authlogic.rb +3 -28
  39. metadata +36 -180
  40. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -28
  41. data/.github/ISSUE_TEMPLATE/feature_proposal.md +0 -32
  42. data/.github/triage.md +0 -86
  43. data/.gitignore +0 -15
  44. data/.rubocop.yml +0 -133
  45. data/.rubocop_todo.yml +0 -74
  46. data/.travis.yml +0 -24
  47. data/CHANGELOG.md +0 -326
  48. data/CONTRIBUTING.md +0 -91
  49. data/Gemfile +0 -6
  50. data/LICENSE +0 -20
  51. data/README.md +0 -439
  52. data/Rakefile +0 -21
  53. data/UPGRADING.md +0 -22
  54. data/authlogic.gemspec +0 -40
  55. data/doc/use_normal_rails_validation.md +0 -82
  56. data/gemfiles/Gemfile.rails-4.2.x +0 -6
  57. data/gemfiles/Gemfile.rails-5.1.x +0 -6
  58. data/gemfiles/Gemfile.rails-5.2.x +0 -6
  59. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +0 -106
  60. data/lib/authlogic/acts_as_authentic/validations_scope.rb +0 -35
  61. data/lib/authlogic/authenticates_many/association.rb +0 -50
  62. data/lib/authlogic/authenticates_many/base.rb +0 -81
  63. data/lib/authlogic/crypto_providers/aes256.rb +0 -71
  64. data/lib/authlogic/crypto_providers/wordpress.rb +0 -72
  65. data/lib/authlogic/regex.rb +0 -79
  66. data/lib/authlogic/session/activation.rb +0 -73
  67. data/lib/authlogic/session/active_record_trickery.rb +0 -65
  68. data/lib/authlogic/session/brute_force_protection.rb +0 -127
  69. data/lib/authlogic/session/callbacks.rb +0 -153
  70. data/lib/authlogic/session/cookies.rb +0 -296
  71. data/lib/authlogic/session/existence.rb +0 -103
  72. data/lib/authlogic/session/foundation.rb +0 -105
  73. data/lib/authlogic/session/http_auth.rb +0 -107
  74. data/lib/authlogic/session/id.rb +0 -53
  75. data/lib/authlogic/session/klass.rb +0 -73
  76. data/lib/authlogic/session/magic_columns.rb +0 -119
  77. data/lib/authlogic/session/magic_states.rb +0 -82
  78. data/lib/authlogic/session/params.rb +0 -130
  79. data/lib/authlogic/session/password.rb +0 -318
  80. data/lib/authlogic/session/perishable_token.rb +0 -24
  81. data/lib/authlogic/session/persistence.rb +0 -77
  82. data/lib/authlogic/session/priority_record.rb +0 -38
  83. data/lib/authlogic/session/scopes.rb +0 -138
  84. data/lib/authlogic/session/session.rb +0 -77
  85. data/lib/authlogic/session/timeout.rb +0 -103
  86. data/lib/authlogic/session/unauthorized_record.rb +0 -56
  87. data/lib/authlogic/session/validation.rb +0 -93
  88. data/test/acts_as_authentic_test/base_test.rb +0 -27
  89. data/test/acts_as_authentic_test/email_test.rb +0 -241
  90. data/test/acts_as_authentic_test/logged_in_status_test.rb +0 -64
  91. data/test/acts_as_authentic_test/login_test.rb +0 -153
  92. data/test/acts_as_authentic_test/magic_columns_test.rb +0 -29
  93. data/test/acts_as_authentic_test/password_test.rb +0 -263
  94. data/test/acts_as_authentic_test/perishable_token_test.rb +0 -98
  95. data/test/acts_as_authentic_test/persistence_token_test.rb +0 -62
  96. data/test/acts_as_authentic_test/restful_authentication_test.rb +0 -48
  97. data/test/acts_as_authentic_test/session_maintenance_test.rb +0 -150
  98. data/test/acts_as_authentic_test/single_access_test.rb +0 -46
  99. data/test/adapter_test.rb +0 -23
  100. data/test/authenticates_many_test.rb +0 -33
  101. data/test/config_test.rb +0 -38
  102. data/test/crypto_provider_test/aes256_test.rb +0 -16
  103. data/test/crypto_provider_test/bcrypt_test.rb +0 -16
  104. data/test/crypto_provider_test/scrypt_test.rb +0 -16
  105. data/test/crypto_provider_test/sha1_test.rb +0 -25
  106. data/test/crypto_provider_test/sha256_test.rb +0 -16
  107. data/test/crypto_provider_test/sha512_test.rb +0 -16
  108. data/test/crypto_provider_test/wordpress_test.rb +0 -26
  109. data/test/fixtures/companies.yml +0 -5
  110. data/test/fixtures/employees.yml +0 -17
  111. data/test/fixtures/projects.yml +0 -3
  112. data/test/fixtures/users.yml +0 -41
  113. data/test/i18n/lol.yml +0 -4
  114. data/test/i18n_test.rb +0 -35
  115. data/test/libs/affiliate.rb +0 -9
  116. data/test/libs/company.rb +0 -8
  117. data/test/libs/employee.rb +0 -9
  118. data/test/libs/employee_session.rb +0 -4
  119. data/test/libs/ldaper.rb +0 -5
  120. data/test/libs/project.rb +0 -5
  121. data/test/libs/user.rb +0 -9
  122. data/test/libs/user_session.rb +0 -27
  123. data/test/random_test.rb +0 -15
  124. data/test/session_test/activation_test.rb +0 -45
  125. data/test/session_test/active_record_trickery_test.rb +0 -78
  126. data/test/session_test/brute_force_protection_test.rb +0 -110
  127. data/test/session_test/callbacks_test.rb +0 -42
  128. data/test/session_test/cookies_test.rb +0 -226
  129. data/test/session_test/credentials_test.rb +0 -0
  130. data/test/session_test/existence_test.rb +0 -88
  131. data/test/session_test/foundation_test.rb +0 -24
  132. data/test/session_test/http_auth_test.rb +0 -60
  133. data/test/session_test/id_test.rb +0 -19
  134. data/test/session_test/klass_test.rb +0 -42
  135. data/test/session_test/magic_columns_test.rb +0 -62
  136. data/test/session_test/magic_states_test.rb +0 -60
  137. data/test/session_test/params_test.rb +0 -61
  138. data/test/session_test/password_test.rb +0 -107
  139. data/test/session_test/perishability_test.rb +0 -17
  140. data/test/session_test/persistence_test.rb +0 -35
  141. data/test/session_test/scopes_test.rb +0 -68
  142. data/test/session_test/session_test.rb +0 -80
  143. data/test/session_test/timeout_test.rb +0 -84
  144. data/test/session_test/unauthorized_record_test.rb +0 -15
  145. data/test/session_test/validation_test.rb +0 -25
  146. data/test/test_helper.rb +0 -272
@@ -1,318 +0,0 @@
1
- module Authlogic
2
- module Session
3
- # Handles authenticating via a traditional username and password.
4
- module Password
5
- def self.included(klass)
6
- klass.class_eval do
7
- extend Config
8
- include InstanceMethods
9
- validate :validate_by_password, if: :authenticating_with_password?
10
-
11
- class << self
12
- attr_accessor :configured_password_methods
13
- end
14
- end
15
- end
16
-
17
- # Password configuration
18
- module Config
19
- # Authlogic tries to validate the credentials passed to it. One part of
20
- # validation is actually finding the user and making sure it exists.
21
- # What method it uses the do this is up to you.
22
- #
23
- # Let's say you have a UserSession that is authenticating a User. By
24
- # default UserSession will call User.find_by_login(login). You can
25
- # change what method UserSession calls by specifying it here. Then in
26
- # your User model you can make that method do anything you want, giving
27
- # you complete control of how users are found by the UserSession.
28
- #
29
- # Let's take an example: You want to allow users to login by username or
30
- # email. Set this to the name of the class method that does this in the
31
- # User model. Let's call it "find_by_username_or_email"
32
- #
33
- # class User < ActiveRecord::Base
34
- # def self.find_by_username_or_email(login)
35
- # find_by_username(login) || find_by_email(login)
36
- # end
37
- # end
38
- #
39
- # Now just specify the name of this method for this configuration option
40
- # and you are all set. You can do anything you want here. Maybe you
41
- # allow users to have multiple logins and you want to search a has_many
42
- # relationship, etc. The sky is the limit.
43
- #
44
- # * <tt>Default:</tt> "find_by_smart_case_login_field"
45
- # * <tt>Accepts:</tt> Symbol or String
46
- def find_by_login_method(value = nil)
47
- rw_config(:find_by_login_method, value, "find_by_smart_case_login_field")
48
- end
49
- alias_method :find_by_login_method=, :find_by_login_method
50
-
51
- # The text used to identify credentials (username/password) combination
52
- # when a bad login attempt occurs. When you show error messages for a
53
- # bad login, it's considered good security practice to hide which field
54
- # the user has entered incorrectly (the login field or the password
55
- # field). For a full explanation, see
56
- # http://www.gnucitizen.org/blog/username-enumeration-vulnerabilities/
57
- #
58
- # Example of use:
59
- #
60
- # class UserSession < Authlogic::Session::Base
61
- # generalize_credentials_error_messages true
62
- # end
63
- #
64
- # This would make the error message for bad logins and bad passwords
65
- # look identical:
66
- #
67
- # Login/Password combination is not valid
68
- #
69
- # Alternatively you may use a custom message:
70
- #
71
- # class UserSession < AuthLogic::Session::Base
72
- # generalize_credentials_error_messages "Your login information is invalid"
73
- # end
74
- #
75
- # This will instead show your custom error message when the UserSession is invalid.
76
- #
77
- # The downside to enabling this is that is can be too vague for a user
78
- # that has a hard time remembering their username and password
79
- # combinations. It also disables the ability to to highlight the field
80
- # with the error when you use form_for.
81
- #
82
- # If you are developing an app where security is an extreme priority
83
- # (such as a financial application), then you should enable this.
84
- # Otherwise, leaving this off is fine.
85
- #
86
- # * <tt>Default</tt> false
87
- # * <tt>Accepts:</tt> Boolean
88
- def generalize_credentials_error_messages(value = nil)
89
- rw_config(:generalize_credentials_error_messages, value, false)
90
- end
91
- alias_method :generalize_credentials_error_messages=, :generalize_credentials_error_messages
92
-
93
- # The name of the method you want Authlogic to create for storing the
94
- # login / username. Keep in mind this is just for your
95
- # Authlogic::Session, if you want it can be something completely
96
- # different than the field in your model. So if you wanted people to
97
- # login with a field called "login" and then find users by email this is
98
- # completely doable. See the find_by_login_method configuration option
99
- # for more details.
100
- #
101
- # * <tt>Default:</tt> klass.login_field || klass.email_field
102
- # * <tt>Accepts:</tt> Symbol or String
103
- def login_field(value = nil)
104
- rw_config(:login_field, value, klass.login_field || klass.email_field)
105
- end
106
- alias_method :login_field=, :login_field
107
-
108
- # Works exactly like login_field, but for the password instead. Returns
109
- # :password if a login_field exists.
110
- #
111
- # * <tt>Default:</tt> :password
112
- # * <tt>Accepts:</tt> Symbol or String
113
- def password_field(value = nil)
114
- rw_config(:password_field, value, login_field && :password)
115
- end
116
- alias_method :password_field=, :password_field
117
-
118
- # The name of the method in your model used to verify the password. This
119
- # should be an instance method. It should also be prepared to accept a
120
- # raw password and a crytped password.
121
- #
122
- # * <tt>Default:</tt> "valid_password?" defined in acts_as_authentic/password.rb
123
- # * <tt>Accepts:</tt> Symbol or String
124
- def verify_password_method(value = nil)
125
- rw_config(:verify_password_method, value, "valid_password?")
126
- end
127
- alias_method :verify_password_method=, :verify_password_method
128
- end
129
-
130
- # Password related instance methods
131
- module InstanceMethods
132
- def initialize(*args)
133
- unless self.class.configured_password_methods
134
- configure_password_methods
135
- self.class.configured_password_methods = true
136
- end
137
- instance_variable_set("@#{password_field}", nil)
138
- super
139
- end
140
-
141
- # Returns the login_field / password_field credentials combination in
142
- # hash form.
143
- def credentials
144
- if authenticating_with_password?
145
- details = {}
146
- details[login_field.to_sym] = send(login_field)
147
- details[password_field.to_sym] = "<protected>"
148
- details
149
- else
150
- super
151
- end
152
- end
153
-
154
- # Accepts the login_field / password_field credentials combination in
155
- # hash form.
156
- #
157
- # You must pass an actual Hash, `ActionController::Parameters` is
158
- # specifically not allowed.
159
- #
160
- # See `Authlogic::Session::Foundation#credentials=` for an overview of
161
- # all method signatures.
162
- def credentials=(value)
163
- super
164
- values = Array.wrap(value)
165
- if values.first.is_a?(Hash)
166
- sliced = values
167
- .first
168
- .with_indifferent_access
169
- .slice(login_field, password_field)
170
- sliced.each do |field, val|
171
- next if val.blank?
172
- send("#{field}=", val)
173
- end
174
- end
175
- end
176
-
177
- def invalid_password?
178
- invalid_password == true
179
- end
180
-
181
- private
182
-
183
- def add_invalid_password_error
184
- if generalize_credentials_error_messages?
185
- add_general_credentials_error
186
- else
187
- errors.add(
188
- password_field,
189
- I18n.t("error_messages.password_invalid", default: "is not valid")
190
- )
191
- end
192
- end
193
-
194
- def add_login_not_found_error
195
- if generalize_credentials_error_messages?
196
- add_general_credentials_error
197
- else
198
- errors.add(
199
- login_field,
200
- I18n.t("error_messages.login_not_found", default: "is not valid")
201
- )
202
- end
203
- end
204
-
205
- def authenticating_with_password?
206
- login_field && (!send(login_field).nil? || !send("protected_#{password_field}").nil?)
207
- end
208
-
209
- def configure_password_methods
210
- define_login_field_methods
211
- define_password_field_methods
212
- end
213
-
214
- def define_login_field_methods
215
- return unless login_field
216
- self.class.send(:attr_writer, login_field) unless respond_to?("#{login_field}=")
217
- self.class.send(:attr_reader, login_field) unless respond_to?(login_field)
218
- end
219
-
220
- def define_password_field_methods
221
- return unless password_field
222
- self.class.send(:attr_writer, password_field) unless respond_to?("#{password_field}=")
223
- self.class.send(:define_method, password_field) {} unless respond_to?(password_field)
224
-
225
- # The password should not be accessible publicly. This way forms
226
- # using form_for don't fill the password with the attempted
227
- # password. To prevent this we just create this method that is
228
- # private.
229
- self.class.class_eval(
230
- <<-EOS, __FILE__, __LINE__ + 1
231
- private
232
- def protected_#{password_field}
233
- @#{password_field}
234
- end
235
- EOS
236
- )
237
- end
238
-
239
- # In keeping with the metaphor of ActiveRecord, verification of the
240
- # password is referred to as a "validation".
241
- def validate_by_password
242
- self.invalid_password = false
243
- validate_by_password__blank_fields
244
- return if errors.count > 0
245
- self.attempted_record = search_for_record(find_by_login_method, send(login_field))
246
- if attempted_record.blank?
247
- add_login_not_found_error
248
- return
249
- end
250
- validate_by_password__invalid_password
251
- end
252
-
253
- def validate_by_password__blank_fields
254
- if send(login_field).blank?
255
- errors.add(
256
- login_field,
257
- I18n.t("error_messages.login_blank", default: "cannot be blank")
258
- )
259
- end
260
- if send("protected_#{password_field}").blank?
261
- errors.add(
262
- password_field,
263
- I18n.t("error_messages.password_blank", default: "cannot be blank")
264
- )
265
- end
266
- end
267
-
268
- # Verify the password, usually using `valid_password?` in
269
- # `acts_as_authentic/password.rb`. If it cannot be verified, we
270
- # refer to it as "invalid".
271
- def validate_by_password__invalid_password
272
- unless attempted_record.send(
273
- verify_password_method,
274
- send("protected_#{password_field}")
275
- )
276
- self.invalid_password = true
277
- add_invalid_password_error
278
- end
279
- end
280
-
281
- attr_accessor :invalid_password
282
-
283
- def find_by_login_method
284
- self.class.find_by_login_method
285
- end
286
-
287
- def login_field
288
- self.class.login_field
289
- end
290
-
291
- def add_general_credentials_error
292
- error_message =
293
- if self.class.generalize_credentials_error_messages.is_a? String
294
- self.class.generalize_credentials_error_messages
295
- else
296
- "#{login_field.to_s.humanize}/Password combination is not valid"
297
- end
298
- errors.add(
299
- :base,
300
- I18n.t("error_messages.general_credentials_error", default: error_message)
301
- )
302
- end
303
-
304
- def generalize_credentials_error_messages?
305
- self.class.generalize_credentials_error_messages
306
- end
307
-
308
- def password_field
309
- self.class.password_field
310
- end
311
-
312
- def verify_password_method
313
- self.class.verify_password_method
314
- end
315
- end
316
- end
317
- end
318
- end
@@ -1,24 +0,0 @@
1
- module Authlogic
2
- module Session
3
- # Maintains the perishable token, which is helpful for confirming records or
4
- # authorizing records to reset their password. All that this module does is
5
- # reset it after a session have been saved, just keep it changing. The more
6
- # it changes, the tighter the security.
7
- #
8
- # See Authlogic::ActsAsAuthentic::PerishableToken for more information.
9
- module PerishableToken
10
- def self.included(klass)
11
- klass.after_save :reset_perishable_token!
12
- end
13
-
14
- private
15
-
16
- def reset_perishable_token!
17
- if record.respond_to?(:reset_perishable_token) &&
18
- !record.disable_perishable_token_maintenance?
19
- record.reset_perishable_token
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,77 +0,0 @@
1
- module Authlogic
2
- module Session
3
- # Responsible for allowing you to persist your sessions.
4
- module Persistence
5
- def self.included(klass)
6
- klass.class_eval do
7
- extend ClassMethods
8
- include InstanceMethods
9
- end
10
- end
11
-
12
- module ClassMethods
13
- # This is how you persist a session. This finds the record for the
14
- # current session using a variety of methods. It basically tries to "log
15
- # in" the user without the user having to explicitly log in. Check out
16
- # the other Authlogic::Session modules for more information.
17
- #
18
- # The best way to use this method is something like:
19
- #
20
- # helper_method :current_user_session, :current_user
21
- #
22
- # def current_user_session
23
- # return @current_user_session if defined?(@current_user_session)
24
- # @current_user_session = UserSession.find
25
- # end
26
- #
27
- # def current_user
28
- # return @current_user if defined?(@current_user)
29
- # @current_user = current_user_session && current_user_session.user
30
- # end
31
- #
32
- # Also, this method accepts a single parameter as the id, to find
33
- # session that you marked with an id:
34
- #
35
- # UserSession.find(:secure)
36
- #
37
- # See the id method for more information on ids.
38
- def find(id = nil, priority_record = nil)
39
- session = new({ priority_record: priority_record }, id)
40
- session.priority_record = priority_record
41
- if session.persisting?
42
- session
43
- end
44
- end
45
- end
46
-
47
- module InstanceMethods
48
- # Returns boolean indicating if the session is being persisted or not,
49
- # meaning the user does not have to explicitly log in in order to be
50
- # logged in.
51
- #
52
- # If the session has no associated record, it will try to find a record
53
- # and persist the session.
54
- #
55
- # This is the method that the class level method find uses to ultimately
56
- # persist the session.
57
- def persisting?
58
- return true unless record.nil?
59
- self.attempted_record = nil
60
- self.remember_me = cookie_credentials_remember_me?
61
- before_persisting
62
- persist
63
- ensure_authentication_attempted
64
- if errors.empty? && !attempted_record.nil?
65
- self.record = attempted_record
66
- after_persisting
67
- save_record
68
- self.new_session = false
69
- true
70
- else
71
- false
72
- end
73
- end
74
- end
75
- end
76
- end
77
- end
@@ -1,38 +0,0 @@
1
- module Authlogic
2
- module Session
3
- # The point of this module is to avoid the StaleObjectError raised when
4
- # lock_version is implemented in ActiveRecord. We accomplish this by using a
5
- # "priority record". Meaning this record is used if possible, it gets
6
- # priority. This way we don't save a record behind the scenes thus making an
7
- # object being used stale.
8
- module PriorityRecord
9
- def self.included(klass)
10
- klass.class_eval do
11
- attr_accessor :priority_record
12
- end
13
- end
14
-
15
- # Setting priority record if it is passed. The only way it can be passed
16
- # is through an array:
17
- #
18
- # session.credentials = [real_user_object, priority_user_object]
19
- def credentials=(value)
20
- super
21
- values = value.is_a?(Array) ? value : [value]
22
- self.priority_record = values[1] if values[1].class < ::ActiveRecord::Base
23
- end
24
-
25
- private
26
-
27
- def attempted_record=(value)
28
- value = priority_record if value == priority_record
29
- super
30
- end
31
-
32
- def save_record(alternate_record = nil)
33
- r = alternate_record || record
34
- super if r != priority_record
35
- end
36
- end
37
- end
38
- end
@@ -1,138 +0,0 @@
1
- require "request_store"
2
-
3
- module Authlogic
4
- module Session
5
- # Authentication can be scoped, and it's easy, you just need to define how you want to
6
- # scope everything. This should help you:
7
- #
8
- # 1. Want to scope by a parent object? Ex: An account has many users.
9
- # Checkout Authlogic::AuthenticatesMany
10
- # 2. Want to scope the validations in your model? Ex: 2 users can have the same login
11
- # under different accounts. See Authlogic::ActsAsAuthentic::Scope
12
- module Scopes # :nodoc:
13
- def self.included(klass)
14
- klass.class_eval do
15
- extend ClassMethods
16
- include InstanceMethods
17
- attr_writer :scope
18
- end
19
- end
20
-
21
- # = Scopes
22
- module ClassMethods
23
- # The current scope set, should be used in the block passed to with_scope.
24
- def scope
25
- RequestStore.store[:authlogic_scope]
26
- end
27
-
28
- # What with_scopes focuses on is scoping the query when finding the
29
- # object and the name of the cookie / session. It works very similar to
30
- # ActiveRecord::Base#with_scopes. It accepts a hash with any of the
31
- # following options:
32
- #
33
- # * <tt>find_options:</tt> any options you can pass into ActiveRecord::Base.find.
34
- # This is used when trying to find the record.
35
- # * <tt>id:</tt> The id of the session, this gets merged with the real id. For
36
- # information ids see the id method.
37
- #
38
- # Here is how you use it:
39
- #
40
- # ```
41
- # UserSession.with_scope(find_options: {conditions: "account_id = 2"}, id: "account_2") do
42
- # UserSession.find
43
- # end
44
- # ```
45
- #
46
- # Essentially what the above does is scope the searching of the object
47
- # with the sql you provided. So instead of:
48
- #
49
- # ```
50
- # User.where("login = 'ben'").first
51
- # ```
52
- #
53
- # it would be:
54
- #
55
- # ```
56
- # User.where("login = 'ben' and account_id = 2").first
57
- # ```
58
- #
59
- # You will also notice the :id option. This works just like the id
60
- # method. It scopes your cookies. So the name of your cookie will be:
61
- #
62
- # account_2_user_credentials
63
- #
64
- # instead of:
65
- #
66
- # user_credentials
67
- #
68
- # What is also nifty about scoping with an :id is that it merges your
69
- # id's. So if you do:
70
- #
71
- # UserSession.with_scope(
72
- # find_options: { conditions: "account_id = 2"},
73
- # id: "account_2"
74
- # ) do
75
- # session = UserSession.new
76
- # session.id = :secure
77
- # end
78
- #
79
- # The name of your cookies will be:
80
- #
81
- # secure_account_2_user_credentials
82
- def with_scope(options = {})
83
- raise ArgumentError.new("You must provide a block") unless block_given?
84
- self.scope = options
85
- result = yield
86
- self.scope = nil
87
- result
88
- end
89
-
90
- private
91
-
92
- def scope=(value)
93
- RequestStore.store[:authlogic_scope] = value
94
- end
95
- end
96
-
97
- module InstanceMethods
98
- # Setting the scope if it exists upon instantiation.
99
- def initialize(*args)
100
- self.scope = self.class.scope
101
- super
102
- end
103
-
104
- # The scope of the current object
105
- def scope
106
- @scope ||= {}
107
- end
108
-
109
- private
110
-
111
- # Used for things like cookie_key, session_key, etc.
112
- def build_key(last_part)
113
- [scope[:id], super].compact.join("_")
114
- end
115
-
116
- # `args[0]` is the name of an AR method, like
117
- # `find_by_single_access_token`.
118
- def search_for_record(*args)
119
- search_scope.scoping do
120
- klass.send(*args)
121
- end
122
- end
123
-
124
- # Returns an AR relation representing the scope of the search. The
125
- # relation is either provided directly by, or defined by
126
- # `find_options`.
127
- def search_scope
128
- if scope[:find_options].is_a?(ActiveRecord::Relation)
129
- scope[:find_options]
130
- else
131
- conditions = scope[:find_options] && scope[:find_options][:conditions] || {}
132
- klass.send(:where, conditions)
133
- end
134
- end
135
- end
136
- end
137
- end
138
- end
@@ -1,77 +0,0 @@
1
- module Authlogic
2
- module Session
3
- # Handles all parts of authentication that deal with sessions. Such as persisting a
4
- # session and saving / destroy a session.
5
- module Session
6
- def self.included(klass)
7
- klass.class_eval do
8
- extend Config
9
- include InstanceMethods
10
- persist :persist_by_session
11
- after_save :update_session
12
- after_destroy :update_session
13
- after_persisting :update_session, unless: :single_access?
14
- end
15
- end
16
-
17
- # Configuration for the session feature.
18
- module Config
19
- # Works exactly like cookie_key, but for sessions. See cookie_key for more info.
20
- #
21
- # * <tt>Default:</tt> cookie_key
22
- # * <tt>Accepts:</tt> Symbol or String
23
- def session_key(value = nil)
24
- rw_config(:session_key, value, cookie_key)
25
- end
26
- alias_method :session_key=, :session_key
27
- end
28
-
29
- # Instance methods for the session feature.
30
- module InstanceMethods
31
- private
32
-
33
- # Tries to validate the session from information in the session
34
- def persist_by_session
35
- persistence_token, record_id = session_credentials
36
- if !persistence_token.nil?
37
- record = persist_by_session_search(persistence_token, record_id)
38
- if record && record.persistence_token == persistence_token
39
- self.unauthorized_record = record
40
- end
41
- valid?
42
- else
43
- false
44
- end
45
- end
46
-
47
- # Allow finding by persistence token, because when records are created
48
- # the session is maintained in a before_save, when there is no id.
49
- # This is done for performance reasons and to save on queries.
50
- def persist_by_session_search(persistence_token, record_id)
51
- if record_id.nil?
52
- search_for_record("find_by_persistence_token", persistence_token.to_s)
53
- else
54
- search_for_record("find_by_#{klass.primary_key}", record_id.to_s)
55
- end
56
- end
57
-
58
- def session_credentials
59
- [
60
- controller.session[session_key],
61
- controller.session["#{session_key}_#{klass.primary_key}"]
62
- ].collect { |i| i.nil? ? i : i.to_s }.compact
63
- end
64
-
65
- def session_key
66
- build_key(self.class.session_key)
67
- end
68
-
69
- def update_session
70
- controller.session[session_key] = record && record.persistence_token
71
- compound_key = "#{session_key}_#{klass.primary_key}"
72
- controller.session[compound_key] = record && record.send(record.class.primary_key)
73
- end
74
- end
75
- end
76
- end
77
- end