authlogic 3.8.0 → 4.5.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.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +28 -0
- data/.github/ISSUE_TEMPLATE/feature_proposal.md +32 -0
- data/.github/triage.md +86 -0
- data/.gitignore +4 -3
- data/.rubocop.yml +109 -9
- data/.rubocop_todo.yml +38 -355
- data/.travis.yml +11 -35
- data/CHANGELOG.md +345 -2
- data/CONTRIBUTING.md +45 -14
- data/Gemfile +3 -2
- data/README.md +244 -90
- data/Rakefile +10 -10
- data/UPGRADING.md +22 -0
- data/authlogic.gemspec +34 -21
- data/doc/use_normal_rails_validation.md +82 -0
- data/gemfiles/Gemfile.rails-4.2.x +6 -0
- data/{test/gemfiles → gemfiles}/Gemfile.rails-5.1.x +2 -2
- data/{test/gemfiles → gemfiles}/Gemfile.rails-5.2.x +2 -2
- data/lib/authlogic/acts_as_authentic/base.rb +36 -24
- data/lib/authlogic/acts_as_authentic/email.rb +65 -31
- data/lib/authlogic/acts_as_authentic/logged_in_status.rb +14 -9
- data/lib/authlogic/acts_as_authentic/login.rb +61 -45
- data/lib/authlogic/acts_as_authentic/magic_columns.rb +6 -6
- data/lib/authlogic/acts_as_authentic/password.rb +267 -146
- data/lib/authlogic/acts_as_authentic/perishable_token.rb +24 -19
- data/lib/authlogic/acts_as_authentic/persistence_token.rb +10 -15
- data/lib/authlogic/acts_as_authentic/queries/find_with_case.rb +67 -0
- data/lib/authlogic/acts_as_authentic/restful_authentication.rb +50 -14
- data/lib/authlogic/acts_as_authentic/session_maintenance.rb +88 -60
- data/lib/authlogic/acts_as_authentic/single_access_token.rb +23 -11
- data/lib/authlogic/acts_as_authentic/validations_scope.rb +9 -6
- data/lib/authlogic/authenticates_many/association.rb +7 -7
- data/lib/authlogic/authenticates_many/base.rb +37 -21
- data/lib/authlogic/config.rb +21 -10
- data/lib/authlogic/controller_adapters/abstract_adapter.rb +38 -11
- data/lib/authlogic/controller_adapters/rack_adapter.rb +9 -5
- data/lib/authlogic/controller_adapters/rails_adapter.rb +12 -7
- data/lib/authlogic/controller_adapters/sinatra_adapter.rb +2 -2
- data/lib/authlogic/crypto_providers/aes256.rb +37 -32
- data/lib/authlogic/crypto_providers/bcrypt.rb +21 -15
- data/lib/authlogic/crypto_providers/md5.rb +4 -2
- data/lib/authlogic/crypto_providers/scrypt.rb +22 -17
- data/lib/authlogic/crypto_providers/sha1.rb +11 -5
- data/lib/authlogic/crypto_providers/sha256.rb +13 -9
- data/lib/authlogic/crypto_providers/sha512.rb +0 -21
- data/lib/authlogic/crypto_providers/wordpress.rb +32 -3
- data/lib/authlogic/crypto_providers.rb +91 -0
- data/lib/authlogic/i18n.rb +26 -19
- data/lib/authlogic/random.rb +10 -28
- data/lib/authlogic/regex.rb +59 -28
- data/lib/authlogic/session/activation.rb +10 -7
- data/lib/authlogic/session/active_record_trickery.rb +13 -9
- data/lib/authlogic/session/base.rb +15 -4
- data/lib/authlogic/session/brute_force_protection.rb +40 -33
- data/lib/authlogic/session/callbacks.rb +94 -46
- data/lib/authlogic/session/cookies.rb +130 -45
- data/lib/authlogic/session/existence.rb +21 -11
- data/lib/authlogic/session/foundation.rb +64 -14
- data/lib/authlogic/session/http_auth.rb +35 -28
- data/lib/authlogic/session/id.rb +9 -4
- data/lib/authlogic/session/klass.rb +15 -12
- data/lib/authlogic/session/magic_columns.rb +58 -55
- data/lib/authlogic/session/magic_states.rb +25 -19
- data/lib/authlogic/session/params.rb +42 -28
- data/lib/authlogic/session/password.rb +130 -120
- data/lib/authlogic/session/perishable_token.rb +5 -4
- data/lib/authlogic/session/persistence.rb +18 -12
- data/lib/authlogic/session/priority_record.rb +15 -12
- data/lib/authlogic/session/scopes.rb +51 -32
- data/lib/authlogic/session/session.rb +38 -28
- data/lib/authlogic/session/timeout.rb +13 -13
- data/lib/authlogic/session/unauthorized_record.rb +18 -13
- data/lib/authlogic/session/validation.rb +9 -9
- data/lib/authlogic/test_case/mock_controller.rb +5 -4
- data/lib/authlogic/test_case/mock_cookie_jar.rb +47 -3
- data/lib/authlogic/test_case/mock_request.rb +6 -3
- data/lib/authlogic/test_case/rails_request_adapter.rb +3 -2
- data/lib/authlogic/test_case.rb +70 -2
- data/lib/authlogic/version.rb +21 -0
- data/lib/authlogic.rb +51 -49
- data/test/acts_as_authentic_test/base_test.rb +3 -1
- data/test/acts_as_authentic_test/email_test.rb +43 -42
- data/test/acts_as_authentic_test/logged_in_status_test.rb +6 -4
- data/test/acts_as_authentic_test/login_test.rb +77 -80
- data/test/acts_as_authentic_test/magic_columns_test.rb +3 -1
- data/test/acts_as_authentic_test/password_test.rb +51 -37
- data/test/acts_as_authentic_test/perishable_token_test.rb +13 -5
- data/test/acts_as_authentic_test/persistence_token_test.rb +7 -1
- data/test/acts_as_authentic_test/restful_authentication_test.rb +14 -3
- data/test/acts_as_authentic_test/session_maintenance_test.rb +69 -15
- data/test/acts_as_authentic_test/single_access_test.rb +3 -1
- data/test/adapter_test.rb +23 -0
- data/test/authenticates_many_test.rb +3 -1
- data/test/config_test.rb +11 -9
- data/test/crypto_provider_test/aes256_test.rb +3 -1
- data/test/crypto_provider_test/bcrypt_test.rb +3 -1
- data/test/crypto_provider_test/scrypt_test.rb +3 -1
- data/test/crypto_provider_test/sha1_test.rb +3 -1
- data/test/crypto_provider_test/sha256_test.rb +3 -1
- data/test/crypto_provider_test/sha512_test.rb +3 -1
- data/test/crypto_provider_test/wordpress_test.rb +26 -0
- data/test/fixtures/companies.yml +2 -2
- data/test/fixtures/employees.yml +1 -1
- data/test/i18n_test.rb +6 -4
- data/test/libs/affiliate.rb +2 -0
- data/test/libs/company.rb +4 -2
- data/test/libs/employee.rb +2 -0
- data/test/libs/employee_session.rb +2 -0
- data/test/libs/ldaper.rb +2 -0
- data/test/libs/project.rb +2 -0
- data/test/libs/user.rb +2 -0
- data/test/libs/user_session.rb +4 -2
- data/test/random_test.rb +10 -38
- data/test/session_test/activation_test.rb +3 -1
- data/test/session_test/active_record_trickery_test.rb +7 -4
- data/test/session_test/brute_force_protection_test.rb +11 -9
- data/test/session_test/callbacks_test.rb +12 -4
- data/test/session_test/cookies_test.rb +48 -5
- data/test/session_test/existence_test.rb +18 -5
- data/test/session_test/foundation_test.rb +19 -1
- data/test/session_test/http_auth_test.rb +11 -7
- data/test/session_test/id_test.rb +3 -1
- data/test/session_test/klass_test.rb +3 -1
- data/test/session_test/magic_columns_test.rb +13 -13
- data/test/session_test/magic_states_test.rb +3 -1
- data/test/session_test/params_test.rb +13 -5
- data/test/session_test/password_test.rb +10 -8
- data/test/session_test/perishability_test.rb +3 -1
- data/test/session_test/persistence_test.rb +4 -1
- data/test/session_test/scopes_test.rb +16 -8
- data/test/session_test/session_test.rb +6 -4
- data/test/session_test/timeout_test.rb +4 -2
- data/test/session_test/unauthorized_record_test.rb +4 -2
- data/test/session_test/validation_test.rb +3 -1
- data/test/test_helper.rb +84 -45
- metadata +87 -73
- data/.github/ISSUE_TEMPLATE.md +0 -13
- data/test/gemfiles/Gemfile.rails-3.2.x +0 -7
- data/test/gemfiles/Gemfile.rails-4.0.x +0 -7
- data/test/gemfiles/Gemfile.rails-4.1.x +0 -7
- data/test/gemfiles/Gemfile.rails-4.2.x +0 -7
- data/test/gemfiles/Gemfile.rails-5.0.x +0 -6
@@ -22,7 +22,13 @@ module Authlogic
|
|
22
22
|
rw_config(
|
23
23
|
:crypted_password_field,
|
24
24
|
value,
|
25
|
-
first_column_to_exist(
|
25
|
+
first_column_to_exist(
|
26
|
+
nil,
|
27
|
+
:crypted_password,
|
28
|
+
:encrypted_password,
|
29
|
+
:password_hash,
|
30
|
+
:pw_hash
|
31
|
+
)
|
26
32
|
)
|
27
33
|
end
|
28
34
|
alias_method :crypted_password_field=, :crypted_password_field
|
@@ -91,6 +97,8 @@ module Authlogic
|
|
91
97
|
#
|
92
98
|
# * <tt>Default:</tt> true
|
93
99
|
# * <tt>Accepts:</tt> Boolean
|
100
|
+
#
|
101
|
+
# @deprecated
|
94
102
|
def validate_password_field(value = nil)
|
95
103
|
rw_config(:validate_password_field, value, true)
|
96
104
|
end
|
@@ -99,17 +107,28 @@ module Authlogic
|
|
99
107
|
# A hash of options for the validates_length_of call for the password field.
|
100
108
|
# Allows you to change this however you want.
|
101
109
|
#
|
102
|
-
#
|
103
|
-
# you can completely replace the hash or merge options into
|
104
|
-
#
|
105
|
-
# options
|
110
|
+
# **Keep in mind this is ruby. I wanted to keep this as flexible as
|
111
|
+
# possible, so you can completely replace the hash or merge options into
|
112
|
+
# it. Checkout the convenience function
|
113
|
+
# merge_validates_length_of_password_field_options to merge options.**
|
106
114
|
#
|
107
115
|
# * <tt>Default:</tt> {:minimum => 8, :if => :require_password?}
|
108
116
|
# * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
|
117
|
+
#
|
118
|
+
# @deprecated
|
109
119
|
def validates_length_of_password_field_options(value = nil)
|
110
|
-
|
120
|
+
deprecate_authlogic_config("validates_length_of_password_field_options") if value
|
121
|
+
rw_config(
|
122
|
+
:validates_length_of_password_field_options,
|
123
|
+
value,
|
124
|
+
minimum: 8,
|
125
|
+
if: :require_password?
|
126
|
+
)
|
111
127
|
end
|
112
|
-
alias_method
|
128
|
+
alias_method(
|
129
|
+
:validates_length_of_password_field_options=,
|
130
|
+
:validates_length_of_password_field_options
|
131
|
+
)
|
113
132
|
|
114
133
|
# A convenience function to merge options into the
|
115
134
|
# validates_length_of_login_field_options. So instead of:
|
@@ -120,29 +139,53 @@ module Authlogic
|
|
120
139
|
# You can do this:
|
121
140
|
#
|
122
141
|
# merge_validates_length_of_password_field_options :my_option => my_value
|
142
|
+
#
|
143
|
+
# @deprecated
|
123
144
|
def merge_validates_length_of_password_field_options(options = {})
|
124
|
-
|
145
|
+
deprecate_authlogic_config(
|
146
|
+
"merge_validates_length_of_password_field_options"
|
147
|
+
)
|
148
|
+
self.validates_length_of_password_field_options =
|
149
|
+
validates_length_of_password_field_options.merge(options)
|
125
150
|
end
|
126
151
|
|
127
|
-
# A hash of options for the validates_confirmation_of call for the
|
128
|
-
# Allows you to change this however you want.
|
152
|
+
# A hash of options for the validates_confirmation_of call for the
|
153
|
+
# password field. Allows you to change this however you want.
|
129
154
|
#
|
130
|
-
#
|
131
|
-
# you can completely replace the hash or merge options into
|
132
|
-
#
|
133
|
-
# options
|
155
|
+
# **Keep in mind this is ruby. I wanted to keep this as flexible as
|
156
|
+
# possible, so you can completely replace the hash or merge options into
|
157
|
+
# it. Checkout the convenience function
|
158
|
+
# merge_validates_length_of_password_field_options to merge options.**
|
134
159
|
#
|
135
160
|
# * <tt>Default:</tt> {:if => :require_password?}
|
136
161
|
# * <tt>Accepts:</tt> Hash of options accepted by validates_confirmation_of
|
162
|
+
#
|
163
|
+
# @deprecated
|
137
164
|
def validates_confirmation_of_password_field_options(value = nil)
|
138
|
-
|
165
|
+
if value
|
166
|
+
deprecate_authlogic_config(
|
167
|
+
"validates_confirmation_of_password_field_options"
|
168
|
+
)
|
169
|
+
end
|
170
|
+
rw_config(
|
171
|
+
:validates_confirmation_of_password_field_options,
|
172
|
+
value,
|
173
|
+
if: :require_password?
|
174
|
+
)
|
139
175
|
end
|
140
|
-
alias_method :validates_confirmation_of_password_field_options=,
|
176
|
+
alias_method :validates_confirmation_of_password_field_options=,
|
177
|
+
:validates_confirmation_of_password_field_options
|
141
178
|
|
142
179
|
# See merge_validates_length_of_password_field_options. The same thing, except for
|
143
180
|
# validates_confirmation_of_password_field_options
|
181
|
+
#
|
182
|
+
# @deprecated
|
144
183
|
def merge_validates_confirmation_of_password_field_options(options = {})
|
145
|
-
|
184
|
+
deprecate_authlogic_config(
|
185
|
+
"merge_validates_confirmation_of_password_field_options"
|
186
|
+
)
|
187
|
+
self.validates_confirmation_of_password_field_options =
|
188
|
+
validates_confirmation_of_password_field_options.merge(options)
|
146
189
|
end
|
147
190
|
|
148
191
|
# A hash of options for the validates_length_of call for the password_confirmation
|
@@ -155,7 +198,14 @@ module Authlogic
|
|
155
198
|
#
|
156
199
|
# * <tt>Default:</tt> validates_length_of_password_field_options
|
157
200
|
# * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
|
201
|
+
#
|
202
|
+
# @deprecated
|
158
203
|
def validates_length_of_password_confirmation_field_options(value = nil)
|
204
|
+
if value
|
205
|
+
deprecate_authlogic_config(
|
206
|
+
"validates_length_of_password_confirmation_field_options"
|
207
|
+
)
|
208
|
+
end
|
159
209
|
rw_config(
|
160
210
|
:validates_length_of_password_confirmation_field_options,
|
161
211
|
value,
|
@@ -169,74 +219,101 @@ module Authlogic
|
|
169
219
|
|
170
220
|
# See merge_validates_length_of_password_field_options. The same thing, except for
|
171
221
|
# validates_length_of_password_confirmation_field_options
|
222
|
+
#
|
223
|
+
# @deprecated
|
172
224
|
def merge_validates_length_of_password_confirmation_field_options(options = {})
|
225
|
+
deprecate_authlogic_config(
|
226
|
+
"merge_validates_length_of_password_confirmation_field_options"
|
227
|
+
)
|
173
228
|
self.validates_length_of_password_confirmation_field_options =
|
174
229
|
validates_length_of_password_confirmation_field_options.merge(options)
|
175
230
|
end
|
176
231
|
|
177
|
-
# The class you want to use to encrypt and verify your encrypted
|
178
|
-
# the Authlogic::CryptoProviders module for more info on
|
179
|
-
# how to create your own.
|
232
|
+
# The class you want to use to encrypt and verify your encrypted
|
233
|
+
# passwords. See the Authlogic::CryptoProviders module for more info on
|
234
|
+
# the available methods and how to create your own.
|
235
|
+
#
|
236
|
+
# The family of adaptive hash functions (BCrypt, SCrypt, PBKDF2) is the
|
237
|
+
# best choice for password storage today. We recommend SCrypt. Other
|
238
|
+
# one-way functions like SHA512 are inferior, but widely used.
|
239
|
+
# Reverisbile functions like AES256 are the worst choice.
|
240
|
+
#
|
241
|
+
# You can use the `transition_from_crypto_providers` option to gradually
|
242
|
+
# transition to a better crypto provider without causing your users any
|
243
|
+
# pain.
|
180
244
|
#
|
181
245
|
# * <tt>Default:</tt> CryptoProviders::SCrypt
|
182
246
|
# * <tt>Accepts:</tt> Class
|
183
247
|
def crypto_provider(value = nil)
|
248
|
+
CryptoProviders::Guidance.new(value).impart_wisdom
|
184
249
|
rw_config(:crypto_provider, value, CryptoProviders::SCrypt)
|
185
250
|
end
|
186
251
|
alias_method :crypto_provider=, :crypto_provider
|
187
252
|
|
188
|
-
# Let's say you originally encrypted your passwords with Sha1. Sha1 is
|
189
|
-
# join the party with MD5 and you want to switch to
|
190
|
-
# problem, just specify your new and improved
|
191
|
-
# option and then let Authlogic know
|
192
|
-
#
|
193
|
-
#
|
194
|
-
#
|
195
|
-
#
|
253
|
+
# Let's say you originally encrypted your passwords with Sha1. Sha1 is
|
254
|
+
# starting to join the party with MD5 and you want to switch to
|
255
|
+
# something stronger. No problem, just specify your new and improved
|
256
|
+
# algorithm with the crypt_provider option and then let Authlogic know
|
257
|
+
# you are transitioning from Sha1 using this option. Authlogic will take
|
258
|
+
# care of everything, including transitioning your users to the new
|
259
|
+
# algorithm. The next time a user logs in, they will be granted access
|
260
|
+
# using the old algorithm and their password will be resaved with the
|
261
|
+
# new algorithm. All new users will obviously use the new algorithm as
|
262
|
+
# well.
|
196
263
|
#
|
197
|
-
# Lastly, if you want to transition again, you can pass an array of
|
198
|
-
# providers. So you can transition from as many algorithms as you
|
264
|
+
# Lastly, if you want to transition again, you can pass an array of
|
265
|
+
# crypto providers. So you can transition from as many algorithms as you
|
266
|
+
# want.
|
199
267
|
#
|
200
268
|
# * <tt>Default:</tt> nil
|
201
269
|
# * <tt>Accepts:</tt> Class or Array
|
202
270
|
def transition_from_crypto_providers(value = nil)
|
203
|
-
rw_config(
|
271
|
+
rw_config(
|
272
|
+
:transition_from_crypto_providers,
|
273
|
+
(!value.nil? && [value].flatten.compact) || value,
|
274
|
+
[]
|
275
|
+
)
|
204
276
|
end
|
205
277
|
alias_method :transition_from_crypto_providers=, :transition_from_crypto_providers
|
206
278
|
end
|
207
279
|
|
208
280
|
# Callbacks / hooks to allow other modules to modify the behavior of this module.
|
209
281
|
module Callbacks
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
282
|
+
# Does the order of this array matter?
|
283
|
+
METHODS = %w[
|
284
|
+
before_password_set
|
285
|
+
after_password_set
|
286
|
+
before_password_verification
|
287
|
+
after_password_verification
|
288
|
+
].freeze
|
214
289
|
|
215
290
|
def self.included(klass)
|
216
291
|
return if klass.crypted_password_field.nil?
|
217
|
-
klass.define_callbacks
|
292
|
+
klass.define_callbacks(*METHODS)
|
218
293
|
|
219
294
|
# If Rails 3, support the new callback syntax
|
220
|
-
if klass.
|
295
|
+
if klass.singleton_class.method_defined?(:set_callback)
|
221
296
|
METHODS.each do |method|
|
222
|
-
klass.class_eval <<-
|
297
|
+
klass.class_eval <<-EOS, __FILE__, __LINE__ + 1
|
223
298
|
def self.#{method}(*methods, &block)
|
224
299
|
set_callback :#{method}, *methods, &block
|
225
300
|
end
|
226
|
-
|
301
|
+
EOS
|
227
302
|
end
|
228
303
|
end
|
229
304
|
end
|
230
305
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
306
|
+
# TODO: Ideally, once this module is included, the included copies of
|
307
|
+
# the following methods would be private. This cannot be accomplished
|
308
|
+
# by using calling `private` here in the module. Maybe we can set the
|
309
|
+
# privacy inside `included`?
|
310
|
+
METHODS.each do |method|
|
311
|
+
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
312
|
+
def #{method}
|
313
|
+
run_callbacks(:#{method}) { |result, object| result == false }
|
314
|
+
end
|
315
|
+
EOS
|
316
|
+
end
|
240
317
|
end
|
241
318
|
|
242
319
|
# The methods related to the password field.
|
@@ -251,8 +328,14 @@ module Authlogic
|
|
251
328
|
validates_length_of :password, validates_length_of_password_field_options
|
252
329
|
|
253
330
|
if require_password_confirmation
|
254
|
-
validates_confirmation_of
|
255
|
-
|
331
|
+
validates_confirmation_of(
|
332
|
+
:password,
|
333
|
+
validates_confirmation_of_password_field_options
|
334
|
+
)
|
335
|
+
validates_length_of(
|
336
|
+
:password_confirmation,
|
337
|
+
validates_length_of_password_confirmation_field_options
|
338
|
+
)
|
256
339
|
end
|
257
340
|
end
|
258
341
|
|
@@ -260,9 +343,11 @@ module Authlogic
|
|
260
343
|
end
|
261
344
|
end
|
262
345
|
|
346
|
+
# :nodoc:
|
263
347
|
module InstanceMethods
|
264
348
|
# The password
|
265
349
|
def password
|
350
|
+
return nil unless defined?(@password)
|
266
351
|
@password
|
267
352
|
end
|
268
353
|
|
@@ -272,40 +357,48 @@ module Authlogic
|
|
272
357
|
return if ignore_blank_passwords? && pass.blank?
|
273
358
|
before_password_set
|
274
359
|
@password = pass
|
275
|
-
|
276
|
-
|
360
|
+
if password_salt_field
|
361
|
+
send("#{password_salt_field}=", Authlogic::Random.friendly_token)
|
362
|
+
end
|
363
|
+
encryptor_args_type = act_like_restful_authentication? ? :restful_authentication : nil
|
277
364
|
send(
|
278
365
|
"#{crypted_password_field}=",
|
279
|
-
crypto_provider.encrypt(
|
366
|
+
crypto_provider.encrypt(
|
367
|
+
*encrypt_arguments(@password, false, encryptor_args_type)
|
368
|
+
)
|
280
369
|
)
|
281
370
|
@password_changed = true
|
282
371
|
after_password_set
|
283
372
|
end
|
284
373
|
|
285
|
-
# Accepts a raw password to determine if it is the correct password
|
286
|
-
#
|
287
|
-
#
|
288
|
-
#
|
289
|
-
# the database or the value in the object
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
374
|
+
# Accepts a raw password to determine if it is the correct password.
|
375
|
+
#
|
376
|
+
# - attempted_password [String] - password entered by user
|
377
|
+
# - check_against_database [boolean] - Should we check the password
|
378
|
+
# against the value in the database or the value in the object?
|
379
|
+
# Default taken from config option check_passwords_against_database.
|
380
|
+
# See config method for more information.
|
381
|
+
def valid_password?(
|
382
|
+
attempted_password,
|
383
|
+
check_against_database = check_passwords_against_database?
|
384
|
+
)
|
385
|
+
crypted = crypted_password_to_validate_against(check_against_database)
|
298
386
|
return false if attempted_password.blank? || crypted.blank?
|
299
387
|
before_password_verification
|
300
388
|
|
301
389
|
crypto_providers.each_with_index do |encryptor, index|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
390
|
+
next unless encryptor_matches?(
|
391
|
+
crypted,
|
392
|
+
encryptor,
|
393
|
+
index,
|
394
|
+
attempted_password,
|
395
|
+
check_against_database
|
396
|
+
)
|
397
|
+
if transition_password?(index, encryptor, check_against_database)
|
398
|
+
transition_password(attempted_password)
|
308
399
|
end
|
400
|
+
after_password_verification
|
401
|
+
return true
|
309
402
|
end
|
310
403
|
|
311
404
|
false
|
@@ -322,102 +415,130 @@ module Authlogic
|
|
322
415
|
# Resets the password to a random friendly token and then saves the record.
|
323
416
|
def reset_password!
|
324
417
|
reset_password
|
325
|
-
save_without_session_maintenance(:
|
418
|
+
save_without_session_maintenance(validate: false)
|
326
419
|
end
|
327
420
|
alias_method :randomize_password!, :reset_password!
|
328
421
|
|
329
422
|
private
|
330
423
|
|
331
|
-
|
332
|
-
|
424
|
+
def crypted_password_to_validate_against(check_against_database)
|
425
|
+
if check_against_database && send("#{crypted_password_field}_changed?")
|
426
|
+
send("#{crypted_password_field}_was")
|
427
|
+
else
|
428
|
+
send(crypted_password_field)
|
333
429
|
end
|
430
|
+
end
|
334
431
|
|
335
|
-
|
336
|
-
|
337
|
-
|
432
|
+
def check_passwords_against_database?
|
433
|
+
self.class.check_passwords_against_database == true
|
434
|
+
end
|
338
435
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
salt = nil
|
343
|
-
if password_salt_field
|
344
|
-
salt =
|
345
|
-
if check_against_database && send("#{password_salt_field}_changed?")
|
346
|
-
send("#{password_salt_field}_was")
|
347
|
-
else
|
348
|
-
send(password_salt_field)
|
349
|
-
end
|
350
|
-
end
|
436
|
+
def crypto_providers
|
437
|
+
[crypto_provider] + transition_from_crypto_providers
|
438
|
+
end
|
351
439
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
440
|
+
# Returns an array of arguments to be passed to a crypto provider, either its
|
441
|
+
# `matches?` or its `encrypt` method.
|
442
|
+
def encrypt_arguments(raw_password, check_against_database, arguments_type = nil)
|
443
|
+
salt = nil
|
444
|
+
if password_salt_field
|
445
|
+
salt =
|
446
|
+
if check_against_database && send("#{password_salt_field}_changed?")
|
447
|
+
send("#{password_salt_field}_was")
|
448
|
+
else
|
449
|
+
send(password_salt_field)
|
450
|
+
end
|
360
451
|
end
|
361
452
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
restful = acting_restful || transitioning
|
370
|
-
arguments_type = restful ? :restful_authentication : nil
|
371
|
-
encryptor_args = encrypt_arguments(attempted_password, check_against_database, arguments_type)
|
372
|
-
encryptor.matches?(crypted, *encryptor_args)
|
453
|
+
case arguments_type
|
454
|
+
when :restful_authentication
|
455
|
+
[REST_AUTH_SITE_KEY, salt, raw_password, REST_AUTH_SITE_KEY].compact
|
456
|
+
when nil
|
457
|
+
[raw_password, salt].compact
|
458
|
+
else
|
459
|
+
raise "Invalid encryptor arguments_type: #{arguments_type}"
|
373
460
|
end
|
461
|
+
end
|
374
462
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
463
|
+
# Given `encryptor`, does `attempted_password` match the `crypted` password?
|
464
|
+
def encryptor_matches?(
|
465
|
+
crypted,
|
466
|
+
encryptor,
|
467
|
+
index,
|
468
|
+
attempted_password,
|
469
|
+
check_against_database
|
470
|
+
)
|
471
|
+
# The arguments_type for the transitioning from restful_authentication
|
472
|
+
acting_restful = act_like_restful_authentication? && index.zero?
|
473
|
+
transitioning = transition_from_restful_authentication? &&
|
474
|
+
index > 0 &&
|
475
|
+
encryptor == Authlogic::CryptoProviders::Sha1
|
476
|
+
restful = acting_restful || transitioning
|
477
|
+
arguments_type = restful ? :restful_authentication : nil
|
478
|
+
encryptor_args = encrypt_arguments(
|
479
|
+
attempted_password,
|
480
|
+
check_against_database,
|
481
|
+
arguments_type
|
482
|
+
)
|
483
|
+
encryptor.matches?(crypted, *encryptor_args)
|
484
|
+
end
|
384
485
|
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
486
|
+
# Determines if we need to transition the password.
|
487
|
+
#
|
488
|
+
# - If the index > 0 then we are using an "transition from" crypto
|
489
|
+
# provider.
|
490
|
+
# - If the encryptor has a cost and the cost it outdated.
|
491
|
+
# - If we aren't using database values
|
492
|
+
# - If we are using database values, only if the password hasn't
|
493
|
+
# changed so we don't overwrite any changes
|
494
|
+
def transition_password?(index, encryptor, check_against_database)
|
495
|
+
(
|
496
|
+
index > 0 ||
|
497
|
+
(encryptor.respond_to?(:cost_matches?) &&
|
498
|
+
!encryptor.cost_matches?(send(crypted_password_field)))
|
499
|
+
) &&
|
500
|
+
(
|
501
|
+
!check_against_database ||
|
502
|
+
!send("#{crypted_password_field}_changed?")
|
503
|
+
)
|
504
|
+
end
|
389
505
|
|
390
|
-
|
391
|
-
|
392
|
-
|
506
|
+
def transition_password(attempted_password)
|
507
|
+
self.password = attempted_password
|
508
|
+
save(validate: false)
|
509
|
+
end
|
393
510
|
|
394
|
-
|
395
|
-
|
396
|
-
|
511
|
+
def require_password?
|
512
|
+
new_record? || password_changed? || send(crypted_password_field).blank?
|
513
|
+
end
|
397
514
|
|
398
|
-
|
399
|
-
|
400
|
-
|
515
|
+
def ignore_blank_passwords?
|
516
|
+
self.class.ignore_blank_passwords == true
|
517
|
+
end
|
401
518
|
|
402
|
-
|
403
|
-
|
404
|
-
|
519
|
+
def password_changed?
|
520
|
+
defined?(@password_changed) && @password_changed == true
|
521
|
+
end
|
405
522
|
|
406
|
-
|
407
|
-
|
408
|
-
|
523
|
+
def reset_password_changed
|
524
|
+
@password_changed = nil
|
525
|
+
end
|
409
526
|
|
410
|
-
|
411
|
-
|
412
|
-
|
527
|
+
def crypted_password_field
|
528
|
+
self.class.crypted_password_field
|
529
|
+
end
|
413
530
|
|
414
|
-
|
415
|
-
|
416
|
-
|
531
|
+
def password_salt_field
|
532
|
+
self.class.password_salt_field
|
533
|
+
end
|
417
534
|
|
418
|
-
|
419
|
-
|
420
|
-
|
535
|
+
def crypto_provider
|
536
|
+
self.class.crypto_provider
|
537
|
+
end
|
538
|
+
|
539
|
+
def transition_from_crypto_providers
|
540
|
+
self.class.transition_from_crypto_providers
|
541
|
+
end
|
421
542
|
end
|
422
543
|
end
|
423
544
|
end
|