authlogic 4.1.0 → 4.1.1

Sign up to get free protection for your applications and to get access to all the features.
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) ||