authlogic 3.8.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/triage.md +87 -0
- data/.gitignore +2 -1
- data/.rubocop.yml +62 -6
- data/.rubocop_todo.yml +51 -267
- data/.travis.yml +4 -26
- data/CHANGELOG.md +226 -2
- data/CONTRIBUTING.md +15 -5
- data/Gemfile +2 -2
- data/README.md +183 -91
- data/Rakefile +1 -1
- data/UPGRADING.md +20 -0
- data/authlogic.gemspec +25 -16
- data/lib/authlogic.rb +45 -45
- data/lib/authlogic/acts_as_authentic/base.rb +18 -11
- data/lib/authlogic/acts_as_authentic/email.rb +32 -28
- data/lib/authlogic/acts_as_authentic/logged_in_status.rb +1 -1
- data/lib/authlogic/acts_as_authentic/login.rb +32 -42
- data/lib/authlogic/acts_as_authentic/magic_columns.rb +6 -6
- data/lib/authlogic/acts_as_authentic/password.rb +53 -31
- data/lib/authlogic/acts_as_authentic/perishable_token.rb +18 -17
- data/lib/authlogic/acts_as_authentic/persistence_token.rb +7 -12
- data/lib/authlogic/acts_as_authentic/queries/find_with_case.rb +64 -0
- data/lib/authlogic/acts_as_authentic/restful_authentication.rb +11 -3
- data/lib/authlogic/acts_as_authentic/session_maintenance.rb +30 -10
- data/lib/authlogic/acts_as_authentic/single_access_token.rb +4 -4
- data/lib/authlogic/authenticates_many/association.rb +3 -3
- data/lib/authlogic/authenticates_many/base.rb +2 -2
- data/lib/authlogic/config.rb +0 -1
- data/lib/authlogic/controller_adapters/abstract_adapter.rb +11 -4
- data/lib/authlogic/controller_adapters/rack_adapter.rb +7 -3
- data/lib/authlogic/controller_adapters/rails_adapter.rb +2 -0
- data/lib/authlogic/crypto_providers/aes256.rb +1 -1
- data/lib/authlogic/crypto_providers/bcrypt.rb +1 -1
- data/lib/authlogic/crypto_providers/scrypt.rb +6 -6
- data/lib/authlogic/crypto_providers/sha1.rb +10 -5
- data/lib/authlogic/crypto_providers/sha256.rb +11 -8
- data/lib/authlogic/crypto_providers/wordpress.rb +2 -2
- data/lib/authlogic/i18n.rb +4 -2
- data/lib/authlogic/random.rb +10 -28
- data/lib/authlogic/regex.rb +11 -8
- data/lib/authlogic/session/activation.rb +6 -3
- 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 +14 -7
- data/lib/authlogic/session/callbacks.rb +53 -30
- data/lib/authlogic/session/cookies.rb +57 -16
- data/lib/authlogic/session/existence.rb +21 -11
- data/lib/authlogic/session/foundation.rb +56 -10
- data/lib/authlogic/session/http_auth.rb +15 -8
- data/lib/authlogic/session/klass.rb +7 -5
- data/lib/authlogic/session/magic_columns.rb +24 -11
- data/lib/authlogic/session/magic_states.rb +11 -4
- data/lib/authlogic/session/params.rb +6 -2
- data/lib/authlogic/session/password.rb +46 -73
- data/lib/authlogic/session/persistence.rb +11 -7
- data/lib/authlogic/session/priority_record.rb +7 -4
- data/lib/authlogic/session/scopes.rb +15 -6
- data/lib/authlogic/session/session.rb +20 -10
- data/lib/authlogic/session/timeout.rb +2 -2
- data/lib/authlogic/session/unauthorized_record.rb +1 -1
- data/lib/authlogic/session/validation.rb +1 -1
- data/lib/authlogic/test_case.rb +65 -2
- data/lib/authlogic/test_case/mock_controller.rb +5 -4
- data/lib/authlogic/test_case/mock_cookie_jar.rb +11 -2
- data/lib/authlogic/test_case/mock_request.rb +5 -1
- data/lib/authlogic/test_case/rails_request_adapter.rb +3 -2
- data/lib/authlogic/version.rb +16 -0
- data/test/acts_as_authentic_test/email_test.rb +33 -34
- data/test/acts_as_authentic_test/logged_in_status_test.rb +1 -1
- data/test/acts_as_authentic_test/login_test.rb +73 -78
- data/test/acts_as_authentic_test/password_test.rb +30 -18
- data/test/acts_as_authentic_test/perishable_token_test.rb +9 -3
- data/test/acts_as_authentic_test/persistence_token_test.rb +4 -0
- data/test/acts_as_authentic_test/session_maintenance_test.rb +66 -14
- data/test/adapter_test.rb +21 -0
- data/test/gemfiles/Gemfile.rails-4.2.x +2 -2
- data/test/gemfiles/Gemfile.rails-5.0.x +2 -2
- data/test/gemfiles/Gemfile.rails-master +6 -0
- data/test/i18n_test.rb +1 -1
- data/test/libs/company.rb +2 -2
- data/test/random_test.rb +7 -37
- data/test/session_test/active_record_trickery_test.rb +4 -3
- data/test/session_test/brute_force_protection_test.rb +8 -8
- data/test/session_test/callbacks_test.rb +1 -1
- data/test/session_test/cookies_test.rb +27 -4
- data/test/session_test/existence_test.rb +15 -4
- data/test/session_test/foundation_test.rb +16 -0
- data/test/session_test/http_auth_test.rb +3 -1
- data/test/session_test/magic_columns_test.rb +10 -12
- data/test/session_test/params_test.rb +4 -1
- data/test/session_test/password_test.rb +7 -7
- data/test/session_test/persistence_test.rb +1 -0
- data/test/session_test/scopes_test.rb +7 -7
- data/test/session_test/session_test.rb +2 -2
- data/test/session_test/timeout_test.rb +1 -1
- data/test/session_test/unauthorized_record_test.rb +1 -1
- data/test/test_helper.rb +111 -103
- metadata +68 -64
- 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
@@ -1,7 +1,18 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session # :nodoc:
|
3
|
-
# This is the
|
4
|
-
#
|
3
|
+
# This is the most important class in Authlogic. You will inherit this class
|
4
|
+
# for your own eg. `UserSession`.
|
5
|
+
#
|
6
|
+
# Code is organized topically. Each topic is represented by a module. So, to
|
7
|
+
# learn about password-based authentication, read the `Password` module.
|
8
|
+
#
|
9
|
+
# It is common for methods (.initialize and #credentials=, for example) to
|
10
|
+
# be implemented in multiple mixins. Those methods will call `super`, so the
|
11
|
+
# order of `include`s here is important.
|
12
|
+
#
|
13
|
+
# Also, to fully understand such a method (like #credentials=) you will need
|
14
|
+
# to mentally combine all of its definitions. This is perhaps the primary
|
15
|
+
# disadvantage of topical organization using modules.
|
5
16
|
class Base
|
6
17
|
include Foundation
|
7
18
|
include Callbacks
|
@@ -15,8 +26,8 @@ module Authlogic
|
|
15
26
|
include Session
|
16
27
|
include HttpAuth
|
17
28
|
|
18
|
-
# Included in a specific order so magic states gets
|
19
|
-
# TODO: What does "magic states gets
|
29
|
+
# Included in a specific order so magic states gets run after a record is found
|
30
|
+
# TODO: What does "magic states gets run" mean? Be specific.
|
20
31
|
include Password
|
21
32
|
include UnauthorizedRecord
|
22
33
|
include MagicStates
|
@@ -25,8 +25,8 @@ module Authlogic
|
|
25
25
|
klass.class_eval do
|
26
26
|
extend Config
|
27
27
|
include InstanceMethods
|
28
|
-
validate :reset_failed_login_count, :
|
29
|
-
validate :validate_failed_logins, :
|
28
|
+
validate :reset_failed_login_count, if: :reset_failed_login_count?
|
29
|
+
validate :validate_failed_logins, if: :being_brute_force_protected?
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -73,15 +73,22 @@ module Authlogic
|
|
73
73
|
# with configuration. By default they will be banned for 2 hours. During
|
74
74
|
# that 2 hour period this method will return true.
|
75
75
|
def being_brute_force_protected?
|
76
|
-
exceeded_failed_logins_limit? &&
|
77
|
-
(
|
76
|
+
exceeded_failed_logins_limit? &&
|
77
|
+
(
|
78
|
+
failed_login_ban_for <= 0 ||
|
79
|
+
attempted_record.respond_to?(:updated_at) &&
|
80
|
+
attempted_record.updated_at >= failed_login_ban_for.seconds.ago
|
81
|
+
)
|
78
82
|
end
|
79
83
|
|
80
84
|
private
|
81
85
|
|
82
86
|
def exceeded_failed_logins_limit?
|
83
|
-
!attempted_record.nil? &&
|
84
|
-
attempted_record.failed_login_count &&
|
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
|
85
92
|
end
|
86
93
|
|
87
94
|
def reset_failed_login_count?
|
@@ -100,7 +107,7 @@ module Authlogic
|
|
100
107
|
:base,
|
101
108
|
I18n.t(
|
102
109
|
'error_messages.consecutive_failed_logins_limit_exceeded',
|
103
|
-
:
|
110
|
+
default: "Consecutive failed logins limit exceeded, account has been" +
|
104
111
|
(failed_login_ban_for == 0 ? "" : " temporarily") +
|
105
112
|
" disabled."
|
106
113
|
)
|
@@ -1,15 +1,18 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session
|
3
|
-
# Between these callbacks and the configuration, this is the contract between me and
|
4
|
-
# modify Authlogic's behavior. I will do everything I can to make sure
|
3
|
+
# Between these callbacks and the configuration, this is the contract between me and
|
4
|
+
# you to safely modify Authlogic's behavior. I will do everything I can to make sure
|
5
|
+
# these do not change.
|
5
6
|
#
|
6
|
-
# Check out the sub modules of Authlogic::Session. They are very concise, clear, and
|
7
|
-
# importantly they use the same API that you would use to extend
|
8
|
-
#
|
9
|
-
#
|
7
|
+
# Check out the sub modules of Authlogic::Session. They are very concise, clear, and
|
8
|
+
# to the point. More importantly they use the same API that you would use to extend
|
9
|
+
# Authlogic. That being said, they are great examples of how to extend Authlogic and
|
10
|
+
# add / modify behavior to Authlogic. These modules could easily be pulled out into
|
11
|
+
# their own plugin and become an "add on" without any change.
|
10
12
|
#
|
11
|
-
# Now to the point of this module. Just like in ActiveRecord you have before_save,
|
12
|
-
# You have similar callbacks with Authlogic, see the METHODS
|
13
|
+
# Now to the point of this module. Just like in ActiveRecord you have before_save,
|
14
|
+
# before_validation, etc. You have similar callbacks with Authlogic, see the METHODS
|
15
|
+
# constant below. The order of execution is as follows:
|
13
16
|
#
|
14
17
|
# before_persisting
|
15
18
|
# persist
|
@@ -38,9 +41,10 @@ module Authlogic
|
|
38
41
|
# destroy
|
39
42
|
# after_destroy
|
40
43
|
#
|
41
|
-
# Notice the "save record if changed?" lines above. This helps with performance. If
|
42
|
-
# changes to the associated record, there is no need to save the
|
43
|
-
# This allows multiple modules to modify the
|
44
|
+
# Notice the "save record if changed?" lines above. This helps with performance. If
|
45
|
+
# you need to make changes to the associated record, there is no need to save the
|
46
|
+
# record, Authlogic will do it for you. This allows multiple modules to modify the
|
47
|
+
# record and execute as few queries as possible.
|
44
48
|
#
|
45
49
|
# **WARNING**: unlike ActiveRecord, these callbacks must be set up on the class level:
|
46
50
|
#
|
@@ -50,38 +54,57 @@ module Authlogic
|
|
50
54
|
# # ..etc
|
51
55
|
# end
|
52
56
|
#
|
53
|
-
# You can NOT define a "before_validation" method, this is bad practice and does not
|
54
|
-
# to extend properly with multiple extensions. Please ONLY use the
|
57
|
+
# You can NOT define a "before_validation" method, this is bad practice and does not
|
58
|
+
# allow Authlogic to extend properly with multiple extensions. Please ONLY use the
|
59
|
+
# method above.
|
55
60
|
module Callbacks
|
56
61
|
METHODS = [
|
57
|
-
"before_persisting",
|
58
|
-
"
|
59
|
-
"
|
60
|
-
"
|
61
|
-
"
|
62
|
-
|
62
|
+
"before_persisting",
|
63
|
+
"persist",
|
64
|
+
"after_persisting",
|
65
|
+
"before_validation",
|
66
|
+
"before_validation_on_create",
|
67
|
+
"before_validation_on_update",
|
68
|
+
"validate",
|
69
|
+
"after_validation_on_update",
|
70
|
+
"after_validation_on_create",
|
71
|
+
"after_validation",
|
72
|
+
"before_save",
|
73
|
+
"before_create",
|
74
|
+
"before_update",
|
75
|
+
"after_update",
|
76
|
+
"after_create",
|
77
|
+
"after_save",
|
78
|
+
"before_destroy",
|
79
|
+
"after_destroy"
|
80
|
+
].freeze
|
63
81
|
|
64
82
|
def self.included(base) #:nodoc:
|
65
83
|
base.send :include, ActiveSupport::Callbacks
|
66
84
|
if Gem::Version.new(ActiveSupport::VERSION::STRING) >= Gem::Version.new('5')
|
67
|
-
base.define_callbacks
|
68
|
-
|
85
|
+
base.define_callbacks(
|
86
|
+
*METHODS + [{ terminator: ->(_target, result_lambda) { result_lambda.call == false } }]
|
87
|
+
)
|
88
|
+
base.define_callbacks(
|
89
|
+
'persist',
|
90
|
+
terminator: ->(_target, result_lambda) { result_lambda.call == true }
|
91
|
+
)
|
69
92
|
elsif Gem::Version.new(ActiveSupport::VERSION::STRING) >= Gem::Version.new('4.1')
|
70
|
-
base.define_callbacks
|
71
|
-
base.define_callbacks
|
93
|
+
base.define_callbacks(*METHODS + [{ terminator: ->(_target, result) { result == false } }])
|
94
|
+
base.define_callbacks('persist', terminator: ->(_target, result) { result == true })
|
72
95
|
else
|
73
|
-
base.define_callbacks
|
74
|
-
base.define_callbacks
|
96
|
+
base.define_callbacks(*METHODS + [{ terminator: 'result == false' }])
|
97
|
+
base.define_callbacks('persist', terminator: 'result == true')
|
75
98
|
end
|
76
99
|
|
77
100
|
# If Rails 3, support the new callback syntax
|
78
101
|
if base.singleton_class.method_defined?(:set_callback)
|
79
102
|
METHODS.each do |method|
|
80
|
-
base.class_eval <<-
|
103
|
+
base.class_eval <<-EOS, __FILE__, __LINE__
|
81
104
|
def self.#{method}(*methods, &block)
|
82
105
|
set_callback :#{method}, *methods, &block
|
83
106
|
end
|
84
|
-
|
107
|
+
EOS
|
85
108
|
end
|
86
109
|
end
|
87
110
|
end
|
@@ -89,16 +112,16 @@ module Authlogic
|
|
89
112
|
private
|
90
113
|
|
91
114
|
METHODS.each do |method|
|
92
|
-
class_eval <<-
|
115
|
+
class_eval <<-EOS, __FILE__, __LINE__
|
93
116
|
def #{method}
|
94
117
|
run_callbacks(:#{method})
|
95
118
|
end
|
96
|
-
|
119
|
+
EOS
|
97
120
|
end
|
98
121
|
|
99
122
|
def save_record(alternate_record = nil)
|
100
123
|
r = alternate_record || record
|
101
|
-
r.save_without_session_maintenance(:
|
124
|
+
r.save_without_session_maintenance(validate: false) if r && r.changed? && !r.readonly?
|
102
125
|
end
|
103
126
|
end
|
104
127
|
end
|
@@ -3,6 +3,8 @@ module Authlogic
|
|
3
3
|
# Handles all authentication that deals with cookies, such as persisting,
|
4
4
|
# saving, and destroying.
|
5
5
|
module Cookies
|
6
|
+
VALID_SAME_SITE_VALUES = [nil, 'Lax', 'Strict'].freeze
|
7
|
+
|
6
8
|
def self.included(klass)
|
7
9
|
klass.class_eval do
|
8
10
|
extend Config
|
@@ -54,23 +56,37 @@ module Authlogic
|
|
54
56
|
# Should the cookie be set as secure? If true, the cookie will only be sent over
|
55
57
|
# SSL connections
|
56
58
|
#
|
57
|
-
# * <tt>Default:</tt>
|
59
|
+
# * <tt>Default:</tt> true
|
58
60
|
# * <tt>Accepts:</tt> Boolean
|
59
61
|
def secure(value = nil)
|
60
|
-
rw_config(:secure, value,
|
62
|
+
rw_config(:secure, value, true)
|
61
63
|
end
|
62
64
|
alias_method :secure=, :secure
|
63
65
|
|
64
66
|
# Should the cookie be set as httponly? If true, the cookie will not be
|
65
67
|
# accessible from javascript
|
66
68
|
#
|
67
|
-
# * <tt>Default:</tt>
|
69
|
+
# * <tt>Default:</tt> true
|
68
70
|
# * <tt>Accepts:</tt> Boolean
|
69
71
|
def httponly(value = nil)
|
70
|
-
rw_config(:httponly, value,
|
72
|
+
rw_config(:httponly, value, true)
|
71
73
|
end
|
72
74
|
alias_method :httponly=, :httponly
|
73
75
|
|
76
|
+
# Should the cookie be prevented from being send along with cross-site
|
77
|
+
# requests?
|
78
|
+
#
|
79
|
+
# * <tt>Default:</tt> nil
|
80
|
+
# * <tt>Accepts:</tt> String, one of nil, 'Lax' or 'Strict'
|
81
|
+
def same_site(value = nil)
|
82
|
+
unless VALID_SAME_SITE_VALUES.include?(value)
|
83
|
+
msg = "Invalid same_site value: #{value}. Valid: #{VALID_SAME_SITE_VALUES.inspect}"
|
84
|
+
raise ArgumentError.new(msg)
|
85
|
+
end
|
86
|
+
rw_config(:same_site, value)
|
87
|
+
end
|
88
|
+
alias_method :same_site=, :same_site
|
89
|
+
|
74
90
|
# Should the cookie be signed? If the controller adapter supports it, this is a
|
75
91
|
# measure against cookie tampering.
|
76
92
|
def sign_cookie(value = nil)
|
@@ -95,8 +111,8 @@ module Authlogic
|
|
95
111
|
self.remember_me = values.first.with_indifferent_access[:remember_me]
|
96
112
|
end
|
97
113
|
else
|
98
|
-
r = values.find { |
|
99
|
-
self.remember_me = r
|
114
|
+
r = values.find { |val| val.is_a?(TrueClass) || val.is_a?(FalseClass) }
|
115
|
+
self.remember_me = r unless r.nil?
|
100
116
|
end
|
101
117
|
end
|
102
118
|
|
@@ -172,6 +188,21 @@ module Authlogic
|
|
172
188
|
httponly == true || httponly == "true" || httponly == "1"
|
173
189
|
end
|
174
190
|
|
191
|
+
# If the cookie should be marked as SameSite with 'Lax' or 'Strict' flag.
|
192
|
+
def same_site
|
193
|
+
return @same_site if defined?(@same_site)
|
194
|
+
@same_site = self.class.same_site(nil)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Accepts nil, 'Lax' or 'Strict' as possible flags.
|
198
|
+
def same_site=(value)
|
199
|
+
unless VALID_SAME_SITE_VALUES.include?(value)
|
200
|
+
msg = "Invalid same_site value: #{value}. Valid: #{VALID_SAME_SITE_VALUES.inspect}"
|
201
|
+
raise ArgumentError.new(msg)
|
202
|
+
end
|
203
|
+
@same_site = value
|
204
|
+
end
|
205
|
+
|
175
206
|
# If the cookie should be signed
|
176
207
|
def sign_cookie
|
177
208
|
return @sign_cookie if defined?(@sign_cookie)
|
@@ -196,12 +227,16 @@ module Authlogic
|
|
196
227
|
end
|
197
228
|
|
198
229
|
def cookie_credentials
|
230
|
+
cookie = cookie_jar[cookie_key]
|
231
|
+
cookie && cookie.split("::")
|
232
|
+
end
|
233
|
+
|
234
|
+
def cookie_jar
|
199
235
|
if self.class.sign_cookie
|
200
|
-
|
236
|
+
controller.cookies.signed
|
201
237
|
else
|
202
|
-
|
238
|
+
controller.cookies
|
203
239
|
end
|
204
|
-
cookie && cookie.split("::")
|
205
240
|
end
|
206
241
|
|
207
242
|
# Tries to validate the session from information in the cookie
|
@@ -225,18 +260,24 @@ module Authlogic
|
|
225
260
|
end
|
226
261
|
|
227
262
|
def generate_cookie_for_saving
|
228
|
-
|
263
|
+
value = format(
|
264
|
+
"%s::%s%s",
|
265
|
+
record.persistence_token,
|
266
|
+
record.send(record.class.primary_key),
|
267
|
+
remember_me? ? "::#{remember_me_until.iso8601}" : ""
|
268
|
+
)
|
229
269
|
{
|
230
|
-
:value
|
231
|
-
:
|
232
|
-
:
|
233
|
-
:
|
234
|
-
:
|
270
|
+
value: value,
|
271
|
+
expires: remember_me_until,
|
272
|
+
secure: secure,
|
273
|
+
httponly: httponly,
|
274
|
+
same_site: same_site,
|
275
|
+
domain: controller.cookie_domain
|
235
276
|
}
|
236
277
|
end
|
237
278
|
|
238
279
|
def destroy_cookie
|
239
|
-
controller.cookies.delete cookie_key, :
|
280
|
+
controller.cookies.delete cookie_key, domain: controller.cookie_domain
|
240
281
|
end
|
241
282
|
end
|
242
283
|
end
|
@@ -1,10 +1,16 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session
|
3
|
-
# Provides methods to create and destroy objects. Basically controls their
|
3
|
+
# Provides methods to create and destroy objects. Basically controls their
|
4
|
+
# "existence".
|
4
5
|
module Existence
|
5
6
|
class SessionInvalidError < ::StandardError # :nodoc:
|
6
7
|
def initialize(session)
|
7
|
-
|
8
|
+
message = I18n.t(
|
9
|
+
'error_messages.session_invalid',
|
10
|
+
default: "Your session is invalid and has the following errors:"
|
11
|
+
)
|
12
|
+
message += " #{session.errors.full_messages.to_sentence}"
|
13
|
+
super message
|
8
14
|
end
|
9
15
|
end
|
10
16
|
|
@@ -40,8 +46,9 @@ module Authlogic
|
|
40
46
|
end
|
41
47
|
|
42
48
|
module InstanceMethods
|
43
|
-
# Clears all errors and the associated record, you should call this
|
44
|
-
# the user to authenticate again if
|
49
|
+
# Clears all errors and the associated record, you should call this
|
50
|
+
# terminate a session, thus requiring the user to authenticate again if
|
51
|
+
# it is needed.
|
45
52
|
def destroy
|
46
53
|
before_destroy
|
47
54
|
save_record
|
@@ -51,16 +58,18 @@ module Authlogic
|
|
51
58
|
true
|
52
59
|
end
|
53
60
|
|
54
|
-
# Returns true if the session is new, meaning no action has been taken
|
55
|
-
# has not taken place.
|
61
|
+
# Returns true if the session is new, meaning no action has been taken
|
62
|
+
# on it and a successful save has not taken place.
|
56
63
|
def new_session?
|
57
64
|
new_session != false
|
58
65
|
end
|
59
66
|
|
60
|
-
# After you have specified all of the details for your session you can
|
61
|
-
# run validation checks and find the
|
62
|
-
#
|
63
|
-
|
67
|
+
# After you have specified all of the details for your session you can
|
68
|
+
# try to save it. This will run validation checks and find the
|
69
|
+
# associated record, if all validation passes. If validation does not
|
70
|
+
# pass, the save will fail and the errors will be stored in the errors
|
71
|
+
# object.
|
72
|
+
def save
|
64
73
|
result = nil
|
65
74
|
if valid?
|
66
75
|
self.record = attempted_record
|
@@ -81,7 +90,8 @@ module Authlogic
|
|
81
90
|
result
|
82
91
|
end
|
83
92
|
|
84
|
-
# Same as save but raises an exception of validation errors when
|
93
|
+
# Same as save but raises an exception of validation errors when
|
94
|
+
# validation fails
|
85
95
|
def save!
|
86
96
|
result = save
|
87
97
|
raise SessionInvalidError.new(self) unless result
|
@@ -12,6 +12,37 @@ module Authlogic
|
|
12
12
|
end
|
13
13
|
|
14
14
|
module InstanceMethods
|
15
|
+
E_AC_PARAMETERS = <<-EOS.strip_heredoc.freeze
|
16
|
+
Passing an ActionController::Parameters to Authlogic is not allowed.
|
17
|
+
|
18
|
+
In Authlogic 3, especially during the transition of rails to Strong
|
19
|
+
Parameters, it was common for Authlogic users to forget to `permit`
|
20
|
+
their params. They would pass their params into Authlogic, we'd call
|
21
|
+
`to_h`, and they'd be surprised when authentication failed.
|
22
|
+
|
23
|
+
In 2018, people are still making this mistake. We'd like to help them
|
24
|
+
and make authlogic a little simpler at the same time, so in Authlogic
|
25
|
+
3.7.0, we deprecated the use of ActionController::Parameters. Instead,
|
26
|
+
pass a plain Hash. Please replace:
|
27
|
+
|
28
|
+
UserSession.new(user_session_params)
|
29
|
+
UserSession.create(user_session_params)
|
30
|
+
|
31
|
+
with
|
32
|
+
|
33
|
+
UserSession.new(user_session_params.to_h)
|
34
|
+
UserSession.create(user_session_params.to_h)
|
35
|
+
|
36
|
+
And don't forget to `permit`!
|
37
|
+
|
38
|
+
We discussed this issue thoroughly between late 2016 and early
|
39
|
+
2018. Notable discussions include:
|
40
|
+
|
41
|
+
- https://github.com/binarylogic/authlogic/issues/512
|
42
|
+
- https://github.com/binarylogic/authlogic/pull/558
|
43
|
+
- https://github.com/binarylogic/authlogic/pull/577
|
44
|
+
EOS
|
45
|
+
|
15
46
|
def initialize(*args)
|
16
47
|
self.credentials = args
|
17
48
|
end
|
@@ -22,22 +53,37 @@ module Authlogic
|
|
22
53
|
[]
|
23
54
|
end
|
24
55
|
|
25
|
-
# Set your credentials before you save your session.
|
26
|
-
#
|
56
|
+
# Set your credentials before you save your session. There are many
|
57
|
+
# method signatures.
|
27
58
|
#
|
28
|
-
#
|
59
|
+
# ```
|
60
|
+
# # A hash of credentials is most common
|
61
|
+
# session.credentials = { login: "foo", password: "bar", remember_me: true }
|
29
62
|
#
|
30
|
-
#
|
63
|
+
# # You must pass an actual Hash, `ActionController::Parameters` is
|
64
|
+
# # specifically not allowed.
|
31
65
|
#
|
32
|
-
#
|
66
|
+
# # You can pass an array of objects:
|
67
|
+
# session.credentials = [my_user_object, true]
|
33
68
|
#
|
34
|
-
#
|
35
|
-
# item in the array you pass, since the id
|
36
|
-
# it should never be set from
|
69
|
+
# # If you need to set an id (see `Authlogic::Session::Id`) pass it
|
70
|
+
# # last. It needs be the last item in the array you pass, since the id
|
71
|
+
# # is something that you control yourself, it should never be set from
|
72
|
+
# # a hash or a form. Examples:
|
73
|
+
# session.credentials = [
|
74
|
+
# {:login => "foo", :password => "bar", :remember_me => true},
|
75
|
+
# :my_id
|
76
|
+
# ]
|
77
|
+
# session.credentials = [my_user_object, true, :my_id]
|
37
78
|
#
|
38
|
-
#
|
39
|
-
#
|
79
|
+
# # Finally, there's priority_record
|
80
|
+
# [{ priority_record: my_object }, :my_id]
|
81
|
+
# ```
|
40
82
|
def credentials=(values)
|
83
|
+
normalized = Array.wrap(values)
|
84
|
+
if normalized.first.class.name == "ActionController::Parameters"
|
85
|
+
raise TypeError.new(E_AC_PARAMETERS)
|
86
|
+
end
|
41
87
|
end
|
42
88
|
|
43
89
|
def inspect
|