authlogic 4.1.0 → 4.1.1

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +0 -4
  4. data/.rubocop_todo.yml +32 -33
  5. data/CHANGELOG.md +15 -0
  6. data/Rakefile +2 -4
  7. data/authlogic.gemspec +2 -1
  8. data/lib/authlogic/acts_as_authentic/base.rb +13 -13
  9. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +3 -3
  10. data/lib/authlogic/acts_as_authentic/login.rb +4 -4
  11. data/lib/authlogic/acts_as_authentic/password.rb +99 -98
  12. data/lib/authlogic/acts_as_authentic/persistence_token.rb +3 -3
  13. data/lib/authlogic/acts_as_authentic/queries/find_with_case.rb +32 -32
  14. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +14 -14
  15. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +60 -60
  16. data/lib/authlogic/acts_as_authentic/single_access_token.rb +6 -6
  17. data/lib/authlogic/authenticates_many/association.rb +3 -3
  18. data/lib/authlogic/config.rb +9 -9
  19. data/lib/authlogic/controller_adapters/abstract_adapter.rb +28 -8
  20. data/lib/authlogic/controller_adapters/rails_adapter.rb +3 -3
  21. data/lib/authlogic/crypto_providers/aes256.rb +20 -20
  22. data/lib/authlogic/crypto_providers/bcrypt.rb +8 -8
  23. data/lib/authlogic/crypto_providers/scrypt.rb +8 -8
  24. data/lib/authlogic/session/activation.rb +3 -3
  25. data/lib/authlogic/session/brute_force_protection.rb +32 -32
  26. data/lib/authlogic/session/callbacks.rb +49 -35
  27. data/lib/authlogic/session/cookies.rb +58 -49
  28. data/lib/authlogic/session/foundation.rb +3 -3
  29. data/lib/authlogic/session/id.rb +9 -4
  30. data/lib/authlogic/session/klass.rb +6 -6
  31. data/lib/authlogic/session/magic_columns.rb +5 -17
  32. data/lib/authlogic/session/params.rb +3 -0
  33. data/lib/authlogic/session/password.rb +105 -104
  34. data/lib/authlogic/session/perishable_token.rb +5 -5
  35. data/lib/authlogic/session/persistence.rb +5 -4
  36. data/lib/authlogic/session/priority_record.rb +8 -8
  37. data/lib/authlogic/session/scopes.rb +23 -23
  38. data/lib/authlogic/session/timeout.rb +11 -11
  39. data/lib/authlogic/session/unauthorized_record.rb +6 -6
  40. data/lib/authlogic/session/validation.rb +9 -9
  41. data/lib/authlogic/test_case.rb +5 -0
  42. data/lib/authlogic/test_case/mock_request.rb +2 -2
  43. data/lib/authlogic/version.rb +4 -3
  44. data/test/acts_as_authentic_test/password_test.rb +23 -23
  45. data/test/test_helper.rb +96 -93
  46. metadata +18 -4
@@ -75,15 +75,15 @@ module Authlogic
75
75
 
76
76
  private
77
77
 
78
- def join_tokens(tokens)
79
- tokens.flatten.join
80
- end
78
+ def join_tokens(tokens)
79
+ tokens.flatten.join
80
+ end
81
81
 
82
- def new_from_hash(hash)
83
- ::SCrypt::Password.new(hash)
84
- rescue ::SCrypt::Errors::InvalidHash
85
- nil
86
- end
82
+ def new_from_hash(hash)
83
+ ::SCrypt::Password.new(hash)
84
+ rescue ::SCrypt::Errors::InvalidHash
85
+ nil
86
+ end
87
87
  end
88
88
  end
89
89
  end
@@ -64,9 +64,9 @@ module Authlogic
64
64
 
65
65
  private
66
66
 
67
- def controller
68
- self.class.controller
69
- end
67
+ def controller
68
+ self.class.controller
69
+ end
70
70
  end
71
71
  end
72
72
  end
@@ -83,44 +83,44 @@ module Authlogic
83
83
 
84
84
  private
85
85
 
86
- def exceeded_failed_logins_limit?
87
- !attempted_record.nil? &&
88
- attempted_record.respond_to?(:failed_login_count) &&
89
- consecutive_failed_logins_limit > 0 &&
90
- attempted_record.failed_login_count &&
91
- attempted_record.failed_login_count >= consecutive_failed_logins_limit
92
- end
86
+ def exceeded_failed_logins_limit?
87
+ !attempted_record.nil? &&
88
+ attempted_record.respond_to?(:failed_login_count) &&
89
+ consecutive_failed_logins_limit > 0 &&
90
+ attempted_record.failed_login_count &&
91
+ attempted_record.failed_login_count >= consecutive_failed_logins_limit
92
+ end
93
93
 
94
- def reset_failed_login_count?
95
- exceeded_failed_logins_limit? && !being_brute_force_protected?
96
- end
94
+ def reset_failed_login_count?
95
+ exceeded_failed_logins_limit? && !being_brute_force_protected?
96
+ end
97
97
 
98
- def reset_failed_login_count
99
- attempted_record.failed_login_count = 0
100
- end
98
+ def reset_failed_login_count
99
+ attempted_record.failed_login_count = 0
100
+ end
101
101
 
102
- def validate_failed_logins
103
- # Clear all other error messages, as they are irrelevant at this point and can
104
- # only provide additional information that is not needed
105
- errors.clear
106
- errors.add(
107
- :base,
108
- I18n.t(
109
- "error_messages.consecutive_failed_logins_limit_exceeded",
110
- default: "Consecutive failed logins limit exceeded, account has been" +
111
- (failed_login_ban_for.zero? ? "" : " temporarily") +
112
- " disabled."
113
- )
102
+ def validate_failed_logins
103
+ # Clear all other error messages, as they are irrelevant at this point and can
104
+ # only provide additional information that is not needed
105
+ errors.clear
106
+ errors.add(
107
+ :base,
108
+ I18n.t(
109
+ "error_messages.consecutive_failed_logins_limit_exceeded",
110
+ default: "Consecutive failed logins limit exceeded, account has been" +
111
+ (failed_login_ban_for.zero? ? "" : " temporarily") +
112
+ " disabled."
114
113
  )
115
- end
114
+ )
115
+ end
116
116
 
117
- def consecutive_failed_logins_limit
118
- self.class.consecutive_failed_logins_limit
119
- end
117
+ def consecutive_failed_logins_limit
118
+ self.class.consecutive_failed_logins_limit
119
+ end
120
120
 
121
- def failed_login_ban_for
122
- self.class.failed_login_ban_for
123
- end
121
+ def failed_login_ban_for
122
+ self.class.failed_login_ban_for
123
+ end
124
124
  end
125
125
  end
126
126
  end
@@ -79,57 +79,71 @@ module Authlogic
79
79
  after_destroy
80
80
  ].freeze
81
81
 
82
- def self.included(base) #:nodoc:
83
- base.send :include, ActiveSupport::Callbacks
84
-
85
- if Gem::Version.new(ActiveSupport::VERSION::STRING) >= Gem::Version.new("5")
86
- base.define_callbacks(
87
- *METHODS + [{ terminator: ->(_target, result_lambda) { result_lambda.call == false } }]
88
- )
89
- base.define_callbacks(
90
- "persist",
91
- terminator: ->(_target, result_lambda) { result_lambda.call == true }
92
- )
93
- else
94
- base.define_callbacks(
95
- *METHODS + [{ terminator: ->(_target, result) { result == false } }]
96
- )
97
- base.define_callbacks("persist", terminator: ->(_target, result) { result == true })
82
+ class << self
83
+ def included(base) #:nodoc:
84
+ base.send :include, ActiveSupport::Callbacks
85
+ define_session_callbacks(base)
86
+ define_session_callback_installation_methods(base)
98
87
  end
99
88
 
100
- # Now we define the "callback installation methods". These class methods
101
- # will be used by other modules to install their callbacks. Examples:
89
+ private
90
+
91
+ # Defines the "callback installation methods". Other modules will use
92
+ # these class methods to install their callbacks. Examples:
102
93
  #
103
94
  # ```
104
- # # Timeout.included
95
+ # # session/timeout.rb, in `included`
105
96
  # before_persisting :reset_stale_state
106
97
  #
107
- # # Session::Password.included
98
+ # # session/password.rb, in `included`
108
99
  # validate :validate_by_password, if: :authenticating_with_password?
109
100
  # ```
110
- METHODS.each do |method|
111
- base.class_eval <<-EOS, __FILE__, __LINE__ + 1
112
- def self.#{method}(*methods, &block)
113
- set_callback :#{method}, *methods, &block
114
- end
115
- EOS
101
+ def define_session_callback_installation_methods(base)
102
+ METHODS.each do |method|
103
+ base.class_eval <<-EOS, __FILE__, __LINE__ + 1
104
+ def self.#{method}(*filter_list, &block)
105
+ set_callback(:#{method}, *filter_list, &block)
106
+ end
107
+ EOS
108
+ end
116
109
  end
117
- end
118
110
 
119
- private
111
+ # Defines session life cycle events that support callbacks.
112
+ def define_session_callbacks(base)
113
+ if Gem::Version.new(ActiveSupport::VERSION::STRING) >= Gem::Version.new("5")
114
+ base.define_callbacks(
115
+ *METHODS,
116
+ terminator: ->(_target, result_lambda) { result_lambda.call == false }
117
+ )
118
+ base.define_callbacks(
119
+ "persist",
120
+ terminator: ->(_target, result_lambda) { result_lambda.call == true }
121
+ )
122
+ else
123
+ base.define_callbacks(
124
+ *METHODS,
125
+ terminator: ->(_target, result) { result == false }
126
+ )
127
+ base.define_callbacks(
128
+ "persist",
129
+ terminator: ->(_target, result) { result == true }
130
+ )
131
+ end
132
+ end
133
+ end
120
134
 
121
- METHODS.each do |method|
122
- class_eval <<-EOS, __FILE__, __LINE__ + 1
135
+ METHODS.each do |method|
136
+ class_eval <<-EOS, __FILE__, __LINE__ + 1
123
137
  def #{method}
124
138
  run_callbacks(:#{method})
125
139
  end
126
140
  EOS
127
- end
141
+ end
128
142
 
129
- def save_record(alternate_record = nil)
130
- r = alternate_record || record
131
- r.save_without_session_maintenance(validate: false) if r && r.changed? && !r.readonly?
132
- end
143
+ def save_record(alternate_record = nil)
144
+ r = alternate_record || record
145
+ r.save_without_session_maintenance(validate: false) if r && r.changed? && !r.readonly?
146
+ end
133
147
  end
134
148
  end
135
149
  end
@@ -222,65 +222,74 @@ module Authlogic
222
222
 
223
223
  private
224
224
 
225
- def cookie_key
226
- build_key(self.class.cookie_key)
227
- end
225
+ def cookie_key
226
+ build_key(self.class.cookie_key)
227
+ end
228
228
 
229
- def cookie_credentials
230
- cookie = cookie_jar[cookie_key]
231
- cookie && cookie.split("::")
232
- end
229
+ # Returns an array of cookie elements. See cookie format in
230
+ # `generate_cookie_for_saving`. If no cookie is found, returns nil.
231
+ def cookie_credentials
232
+ cookie = cookie_jar[cookie_key]
233
+ cookie && cookie.split("::")
234
+ end
233
235
 
234
- def cookie_jar
235
- if self.class.sign_cookie
236
- controller.cookies.signed
237
- else
238
- controller.cookies
239
- end
240
- end
236
+ # The third element of the cookie indicates whether the user wanted
237
+ # to be remembered (Actually, it's a timestamp, `remember_me_until`)
238
+ # See cookie format in `generate_cookie_for_saving`.
239
+ def cookie_credentials_remember_me?
240
+ !cookie_credentials.nil? && !cookie_credentials[2].nil?
241
+ end
241
242
 
242
- # Tries to validate the session from information in the cookie
243
- def persist_by_cookie
244
- persistence_token, record_id = cookie_credentials
245
- if persistence_token.present?
246
- record = search_for_record("find_by_#{klass.primary_key}", record_id)
247
- if record && record.persistence_token == persistence_token
248
- self.unauthorized_record = record
249
- end
250
- valid?
251
- else
252
- false
253
- end
243
+ def cookie_jar
244
+ if self.class.sign_cookie
245
+ controller.cookies.signed
246
+ else
247
+ controller.cookies
254
248
  end
249
+ end
255
250
 
256
- def save_cookie
257
- if sign_cookie?
258
- controller.cookies.signed[cookie_key] = generate_cookie_for_saving
259
- else
260
- controller.cookies[cookie_key] = generate_cookie_for_saving
251
+ # Tries to validate the session from information in the cookie
252
+ def persist_by_cookie
253
+ persistence_token, record_id = cookie_credentials
254
+ if persistence_token.present?
255
+ record = search_for_record("find_by_#{klass.primary_key}", record_id)
256
+ if record && record.persistence_token == persistence_token
257
+ self.unauthorized_record = record
261
258
  end
259
+ valid?
260
+ else
261
+ false
262
262
  end
263
+ end
263
264
 
264
- def generate_cookie_for_saving
265
- value = format(
266
- "%s::%s%s",
267
- record.persistence_token,
268
- record.send(record.class.primary_key),
269
- remember_me? ? "::#{remember_me_until.iso8601}" : ""
270
- )
271
- {
272
- value: value,
273
- expires: remember_me_until,
274
- secure: secure,
275
- httponly: httponly,
276
- same_site: same_site,
277
- domain: controller.cookie_domain
278
- }
265
+ def save_cookie
266
+ if sign_cookie?
267
+ controller.cookies.signed[cookie_key] = generate_cookie_for_saving
268
+ else
269
+ controller.cookies[cookie_key] = generate_cookie_for_saving
279
270
  end
271
+ end
280
272
 
281
- def destroy_cookie
282
- controller.cookies.delete cookie_key, domain: controller.cookie_domain
283
- end
273
+ def generate_cookie_for_saving
274
+ value = format(
275
+ "%s::%s%s",
276
+ record.persistence_token,
277
+ record.send(record.class.primary_key),
278
+ remember_me? ? "::#{remember_me_until.iso8601}" : ""
279
+ )
280
+ {
281
+ value: value,
282
+ expires: remember_me_until,
283
+ secure: secure,
284
+ httponly: httponly,
285
+ same_site: same_site,
286
+ domain: controller.cookie_domain
287
+ }
288
+ end
289
+
290
+ def destroy_cookie
291
+ controller.cookies.delete cookie_key, domain: controller.cookie_domain
292
+ end
284
293
  end
285
294
  end
286
295
  end
@@ -96,9 +96,9 @@ module Authlogic
96
96
 
97
97
  private
98
98
 
99
- def build_key(last_part)
100
- last_part
101
- end
99
+ def build_key(last_part)
100
+ last_part
101
+ end
102
102
  end
103
103
  end
104
104
  end
@@ -3,6 +3,11 @@ module Authlogic
3
3
  # Allows you to separate sessions with an id, ultimately letting you create
4
4
  # multiple sessions for the same user.
5
5
  module Id
6
+ def initialize(*args)
7
+ @id = nil
8
+ super
9
+ end
10
+
6
11
  def self.included(klass)
7
12
  klass.class_eval do
8
13
  attr_writer :id
@@ -39,10 +44,10 @@ module Authlogic
39
44
 
40
45
  private
41
46
 
42
- # Used for things like cookie_key, session_key, etc.
43
- def build_key(last_part)
44
- [id, super].compact.join("_")
45
- end
47
+ # Used for things like cookie_key, session_key, etc.
48
+ def build_key(last_part)
49
+ [id, super].compact.join("_")
50
+ end
46
51
  end
47
52
  end
48
53
  end
@@ -60,13 +60,13 @@ module Authlogic
60
60
 
61
61
  private
62
62
 
63
- def klass
64
- self.class.klass
65
- end
63
+ def klass
64
+ self.class.klass
65
+ end
66
66
 
67
- def klass_name
68
- self.class.klass_name
69
- end
67
+ def klass_name
68
+ self.class.klass_name
69
+ end
70
70
  end
71
71
  end
72
72
  end
@@ -89,29 +89,17 @@ module Authlogic
89
89
  end
90
90
 
91
91
  # This method lets authlogic know whether it should allow the
92
- # last_request_at field to be updated with the current time
93
- # (Time.now). One thing to note here is that it also checks for the
94
- # existence of a last_request_update_allowed? method in your
95
- # controller. This allows you to control this method pragmatically in
96
- # your controller.
92
+ # last_request_at field to be updated with the current time.
97
93
  #
98
- # For example, what if you had a javascript function that polled the
99
- # server updating how much time is left in their session before it
100
- # times out. Obviously you would want to ignore this request, because
101
- # then the user would never time out. So you can do something like
102
- # this in your controller:
94
+ # See also `last_request_update_allowed?` in
95
+ # `Authlogic::ControllerAdapters::AbstractAdapter`
103
96
  #
104
- # def last_request_update_allowed?
105
- # action_name != "update_session_time_left"
106
- # end
107
- #
108
- # You can do whatever you want with that method.
97
+ # @api private
109
98
  def set_last_request_at?
110
99
  if !record || !klass.column_names.include?("last_request_at")
111
100
  return false
112
101
  end
113
- if controller.responds_to_last_request_update_allowed? &&
114
- !controller.last_request_update_allowed?
102
+ unless controller.last_request_update_allowed?
115
103
  return false
116
104
  end
117
105
  record.last_request_at.blank? ||
@@ -96,7 +96,10 @@ module Authlogic
96
96
  if controller.responds_to_single_access_allowed?
97
97
  return controller.single_access_allowed?
98
98
  end
99
+ params_enabled_by_allowed_request_types?
100
+ end
99
101
 
102
+ def params_enabled_by_allowed_request_types?
100
103
  case single_access_allowed_request_types
101
104
  when Array
102
105
  single_access_allowed_request_types.include?(controller.request_content_type) ||