authlogic 3.8.0 → 4.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.
- 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
|