authlogic 4.0.1 → 4.1.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 +4 -4
- data/.rubocop.yml +43 -1
- data/.rubocop_todo.yml +23 -132
- data/CHANGELOG.md +12 -0
- data/CONTRIBUTING.md +10 -3
- data/Gemfile +2 -2
- data/Rakefile +6 -6
- data/authlogic.gemspec +13 -12
- data/lib/authlogic/acts_as_authentic/base.rb +12 -7
- data/lib/authlogic/acts_as_authentic/email.rb +16 -6
- data/lib/authlogic/acts_as_authentic/logged_in_status.rb +10 -5
- data/lib/authlogic/acts_as_authentic/login.rb +11 -5
- data/lib/authlogic/acts_as_authentic/password.rb +111 -57
- data/lib/authlogic/acts_as_authentic/perishable_token.rb +6 -2
- data/lib/authlogic/acts_as_authentic/persistence_token.rb +1 -1
- data/lib/authlogic/acts_as_authentic/queries/find_with_case.rb +2 -2
- data/lib/authlogic/acts_as_authentic/restful_authentication.rb +31 -3
- data/lib/authlogic/acts_as_authentic/session_maintenance.rb +11 -3
- data/lib/authlogic/acts_as_authentic/single_access_token.rb +14 -2
- data/lib/authlogic/acts_as_authentic/validations_scope.rb +6 -6
- data/lib/authlogic/authenticates_many/association.rb +2 -2
- data/lib/authlogic/authenticates_many/base.rb +27 -19
- data/lib/authlogic/controller_adapters/rack_adapter.rb +1 -1
- data/lib/authlogic/controller_adapters/rails_adapter.rb +6 -3
- data/lib/authlogic/controller_adapters/sinatra_adapter.rb +2 -2
- data/lib/authlogic/crypto_providers.rb +2 -0
- data/lib/authlogic/crypto_providers/bcrypt.rb +15 -9
- data/lib/authlogic/crypto_providers/md5.rb +2 -1
- data/lib/authlogic/crypto_providers/scrypt.rb +12 -7
- data/lib/authlogic/crypto_providers/sha256.rb +2 -1
- data/lib/authlogic/crypto_providers/wordpress.rb +31 -2
- data/lib/authlogic/i18n.rb +22 -17
- data/lib/authlogic/regex.rb +57 -29
- data/lib/authlogic/session/activation.rb +1 -1
- data/lib/authlogic/session/brute_force_protection.rb +2 -2
- data/lib/authlogic/session/callbacks.rb +43 -36
- data/lib/authlogic/session/cookies.rb +4 -2
- data/lib/authlogic/session/existence.rb +1 -1
- data/lib/authlogic/session/foundation.rb +5 -1
- data/lib/authlogic/session/http_auth.rb +2 -2
- data/lib/authlogic/session/klass.rb +2 -1
- data/lib/authlogic/session/magic_columns.rb +4 -2
- data/lib/authlogic/session/magic_states.rb +9 -10
- data/lib/authlogic/session/params.rb +11 -4
- data/lib/authlogic/session/password.rb +72 -38
- data/lib/authlogic/session/perishable_token.rb +2 -1
- data/lib/authlogic/session/persistence.rb +2 -1
- data/lib/authlogic/session/scopes.rb +26 -16
- data/lib/authlogic/session/unauthorized_record.rb +12 -7
- data/lib/authlogic/session/validation.rb +1 -1
- data/lib/authlogic/test_case/mock_controller.rb +1 -1
- data/lib/authlogic/test_case/mock_cookie_jar.rb +1 -1
- data/lib/authlogic/test_case/mock_request.rb +1 -1
- data/lib/authlogic/version.rb +1 -1
- data/test/acts_as_authentic_test/base_test.rb +1 -1
- data/test/acts_as_authentic_test/email_test.rb +11 -11
- data/test/acts_as_authentic_test/logged_in_status_test.rb +4 -4
- data/test/acts_as_authentic_test/login_test.rb +2 -2
- data/test/acts_as_authentic_test/magic_columns_test.rb +1 -1
- data/test/acts_as_authentic_test/password_test.rb +1 -1
- data/test/acts_as_authentic_test/perishable_token_test.rb +2 -2
- data/test/acts_as_authentic_test/persistence_token_test.rb +1 -1
- data/test/acts_as_authentic_test/restful_authentication_test.rb +12 -3
- data/test/acts_as_authentic_test/session_maintenance_test.rb +1 -1
- data/test/acts_as_authentic_test/single_access_test.rb +1 -1
- data/test/adapter_test.rb +3 -3
- data/test/authenticates_many_test.rb +1 -1
- data/test/config_test.rb +9 -9
- data/test/crypto_provider_test/aes256_test.rb +1 -1
- data/test/crypto_provider_test/bcrypt_test.rb +1 -1
- data/test/crypto_provider_test/scrypt_test.rb +1 -1
- data/test/crypto_provider_test/sha1_test.rb +1 -1
- data/test/crypto_provider_test/sha256_test.rb +1 -1
- data/test/crypto_provider_test/sha512_test.rb +1 -1
- data/test/crypto_provider_test/wordpress_test.rb +24 -0
- data/test/i18n_test.rb +3 -3
- data/test/libs/user_session.rb +2 -2
- data/test/random_test.rb +1 -1
- data/test/session_test/activation_test.rb +1 -1
- data/test/session_test/active_record_trickery_test.rb +3 -3
- data/test/session_test/brute_force_protection_test.rb +1 -1
- data/test/session_test/callbacks_test.rb +9 -3
- data/test/session_test/cookies_test.rb +11 -11
- data/test/session_test/existence_test.rb +1 -1
- data/test/session_test/foundation_test.rb +1 -1
- data/test/session_test/http_auth_test.rb +6 -6
- data/test/session_test/id_test.rb +1 -1
- data/test/session_test/klass_test.rb +1 -1
- data/test/session_test/magic_columns_test.rb +1 -1
- data/test/session_test/magic_states_test.rb +1 -1
- data/test/session_test/params_test.rb +7 -4
- data/test/session_test/password_test.rb +1 -1
- data/test/session_test/perishability_test.rb +1 -1
- data/test/session_test/persistence_test.rb +1 -1
- data/test/session_test/scopes_test.rb +9 -3
- 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/session_test/validation_test.rb +1 -1
- data/test/test_helper.rb +34 -14
- metadata +6 -4
data/lib/authlogic/regex.rb
CHANGED
@@ -1,28 +1,29 @@
|
|
1
1
|
module Authlogic
|
2
|
-
# This is a module the contains regular expressions used throughout Authlogic.
|
3
|
-
# of extracting them out into their own module is to make them
|
4
|
-
# for other uses. Ex:
|
2
|
+
# This is a module the contains regular expressions used throughout Authlogic.
|
3
|
+
# The point of extracting them out into their own module is to make them
|
4
|
+
# easily available to you for other uses. Ex:
|
5
5
|
#
|
6
6
|
# validates_format_of :my_email_field, :with => Authlogic::Regex.email
|
7
7
|
module Regex
|
8
|
-
# A general email regular expression. It allows top level domains (TLD) to
|
9
|
-
# 24 in length. The decisions behind this regular expression
|
10
|
-
# the list of top-level domains maintained by IANA
|
11
|
-
#
|
12
|
-
# regular
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
8
|
+
# A general email regular expression. It allows top level domains (TLD) to
|
9
|
+
# be from 2 - 24 in length. The decisions behind this regular expression
|
10
|
+
# were made by analyzing the list of top-level domains maintained by IANA
|
11
|
+
# and by reading this website:
|
12
|
+
# http://www.regular-expressions.info/email.html, which is an excellent
|
13
|
+
# resource for regular expressions.
|
14
|
+
EMAIL = /
|
15
|
+
\A
|
16
|
+
[A-Z0-9_.&%+\-']+ # mailbox
|
17
|
+
@
|
18
|
+
(?:[A-Z0-9\-]+\.)+ # subdomains
|
19
|
+
(?:[A-Z]{2,25}) # TLD
|
20
|
+
\z
|
21
|
+
/ix
|
21
22
|
|
22
|
-
# A draft regular expression for internationalized email addresses. Given
|
23
|
-
# standard may be in flux, this simply emulates @email_regex but
|
24
|
-
# specific characters for each part, it instead
|
25
|
-
# characters:
|
23
|
+
# A draft regular expression for internationalized email addresses. Given
|
24
|
+
# that the standard may be in flux, this simply emulates @email_regex but
|
25
|
+
# rather than allowing specific characters for each part, it instead
|
26
|
+
# disallows the complement set of characters:
|
26
27
|
#
|
27
28
|
# - email_name_regex disallows: @[]^ !"#$()*,/:;<=>?`{|}~\ and control characters
|
28
29
|
# - domain_head_regex disallows: _%+ and all characters in email_name_regex
|
@@ -33,19 +34,46 @@ module Authlogic
|
|
33
34
|
# http://www.unicode.org/faq/idn.html
|
34
35
|
# http://ruby-doc.org/core-2.1.5/Regexp.html#class-Regexp-label-Character+Classes
|
35
36
|
# http://en.wikipedia.org/wiki/Unicode_character_property#General_Category
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
EMAIL_NONASCII = /
|
38
|
+
\A
|
39
|
+
[^[:cntrl:][@\[\]\^ \!"\#$\(\)*,\/:;<=>?`{|}~\\]]+ # mailbox
|
40
|
+
@
|
41
|
+
(?:[^[:cntrl:][@\[\]\^ \!\"\#$&\(\)*,\/:;<=>\?`{|}~\\_.%+']]+\.)+ # subdomains
|
42
|
+
(?:[^[:cntrl:][@\[\]\^ \!\"\#$&\(\)*,\/:;<=>\?`{|}~\\_.%+\-'0-9]]{2,25}) # TLD
|
43
|
+
\z
|
44
|
+
/x
|
44
45
|
|
45
46
|
# A simple regular expression that only allows for letters, numbers, spaces, and
|
46
47
|
# .-_@+. Just a standard login / username regular expression.
|
48
|
+
LOGIN = /\A[a-zA-Z0-9_][a-zA-Z0-9\.+\-_@ ]+\z/
|
49
|
+
|
50
|
+
# Accessing the above constants using the following methods is deprecated.
|
51
|
+
|
52
|
+
# @deprecated
|
53
|
+
def self.email
|
54
|
+
::ActiveSupport::Deprecation.warn(
|
55
|
+
"Authlogic::Regex.email is deprecated, use Authlogic::Regex::EMAIL",
|
56
|
+
caller(1)
|
57
|
+
)
|
58
|
+
EMAIL
|
59
|
+
end
|
60
|
+
|
61
|
+
# @deprecated
|
62
|
+
def self.email_nonascii
|
63
|
+
::ActiveSupport::Deprecation.warn(
|
64
|
+
"Authlogic::Regex.email_nonascii is deprecated, use Authlogic::Regex::EMAIL_NONASCII",
|
65
|
+
caller(1)
|
66
|
+
)
|
67
|
+
EMAIL_NONASCII
|
68
|
+
end
|
69
|
+
|
70
|
+
# @deprecated
|
47
71
|
def self.login
|
48
|
-
|
72
|
+
::ActiveSupport::Deprecation.warn(
|
73
|
+
"Authlogic::Regex.login is deprecated, use Authlogic::Regex::LOGIN",
|
74
|
+
caller(1)
|
75
|
+
)
|
76
|
+
LOGIN
|
49
77
|
end
|
50
78
|
end
|
51
79
|
end
|
@@ -106,9 +106,9 @@ module Authlogic
|
|
106
106
|
errors.add(
|
107
107
|
:base,
|
108
108
|
I18n.t(
|
109
|
-
|
109
|
+
"error_messages.consecutive_failed_logins_limit_exceeded",
|
110
110
|
default: "Consecutive failed logins limit exceeded, account has been" +
|
111
|
-
(failed_login_ban_for
|
111
|
+
(failed_login_ban_for.zero? ? "" : " temporarily") +
|
112
112
|
" disabled."
|
113
113
|
)
|
114
114
|
)
|
@@ -58,61 +58,68 @@ module Authlogic
|
|
58
58
|
# allow Authlogic to extend properly with multiple extensions. Please ONLY use the
|
59
59
|
# method above.
|
60
60
|
module Callbacks
|
61
|
-
METHODS = [
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
61
|
+
METHODS = %w[
|
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
80
|
].freeze
|
81
81
|
|
82
82
|
def self.included(base) #:nodoc:
|
83
83
|
base.send :include, ActiveSupport::Callbacks
|
84
|
-
|
84
|
+
|
85
|
+
if Gem::Version.new(ActiveSupport::VERSION::STRING) >= Gem::Version.new("5")
|
85
86
|
base.define_callbacks(
|
86
87
|
*METHODS + [{ terminator: ->(_target, result_lambda) { result_lambda.call == false } }]
|
87
88
|
)
|
88
89
|
base.define_callbacks(
|
89
|
-
|
90
|
+
"persist",
|
90
91
|
terminator: ->(_target, result_lambda) { result_lambda.call == true }
|
91
92
|
)
|
92
|
-
elsif Gem::Version.new(ActiveSupport::VERSION::STRING) >= Gem::Version.new('4.1')
|
93
|
-
base.define_callbacks(*METHODS + [{ terminator: ->(_target, result) { result == false } }])
|
94
|
-
base.define_callbacks('persist', terminator: ->(_target, result) { result == true })
|
95
93
|
else
|
96
|
-
base.define_callbacks(
|
97
|
-
|
94
|
+
base.define_callbacks(
|
95
|
+
*METHODS + [{ terminator: ->(_target, result) { result == false } }]
|
96
|
+
)
|
97
|
+
base.define_callbacks("persist", terminator: ->(_target, result) { result == true })
|
98
98
|
end
|
99
99
|
|
100
|
-
#
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
100
|
+
# Now we define the "callback installation methods". These class methods
|
101
|
+
# will be used by other modules to install their callbacks. Examples:
|
102
|
+
#
|
103
|
+
# ```
|
104
|
+
# # Timeout.included
|
105
|
+
# before_persisting :reset_stale_state
|
106
|
+
#
|
107
|
+
# # Session::Password.included
|
108
|
+
# validate :validate_by_password, if: :authenticating_with_password?
|
109
|
+
# ```
|
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
|
109
116
|
end
|
110
117
|
end
|
111
118
|
|
112
119
|
private
|
113
120
|
|
114
121
|
METHODS.each do |method|
|
115
|
-
class_eval <<-EOS, __FILE__, __LINE__
|
122
|
+
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
116
123
|
def #{method}
|
117
124
|
run_callbacks(:#{method})
|
118
125
|
end
|
@@ -3,7 +3,7 @@ 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,
|
6
|
+
VALID_SAME_SITE_VALUES = [nil, "Lax", "Strict"].freeze
|
7
7
|
|
8
8
|
def self.included(klass)
|
9
9
|
klass.class_eval do
|
@@ -244,7 +244,9 @@ module Authlogic
|
|
244
244
|
persistence_token, record_id = cookie_credentials
|
245
245
|
if persistence_token.present?
|
246
246
|
record = search_for_record("find_by_#{klass.primary_key}", record_id)
|
247
|
-
|
247
|
+
if record && record.persistence_token == persistence_token
|
248
|
+
self.unauthorized_record = record
|
249
|
+
end
|
248
250
|
valid?
|
249
251
|
else
|
250
252
|
false
|
@@ -6,7 +6,7 @@ module Authlogic
|
|
6
6
|
class SessionInvalidError < ::StandardError # :nodoc:
|
7
7
|
def initialize(session)
|
8
8
|
message = I18n.t(
|
9
|
-
|
9
|
+
"error_messages.session_invalid",
|
10
10
|
default: "Your session is invalid and has the following errors:"
|
11
11
|
)
|
12
12
|
message += " #{session.errors.full_messages.to_sentence}"
|
@@ -87,7 +87,11 @@ module Authlogic
|
|
87
87
|
end
|
88
88
|
|
89
89
|
def inspect
|
90
|
-
|
90
|
+
format(
|
91
|
+
"#<%s: %s>",
|
92
|
+
self.class.name,
|
93
|
+
credentials.blank? ? "no credentials provided" : credentials.inspect
|
94
|
+
)
|
91
95
|
end
|
92
96
|
|
93
97
|
private
|
@@ -64,7 +64,7 @@ module Authlogic
|
|
64
64
|
# * <tt>Default:</tt> 'Application'
|
65
65
|
# * <tt>Accepts:</tt> String
|
66
66
|
def http_basic_auth_realm(value = nil)
|
67
|
-
rw_config(:http_basic_auth_realm, value,
|
67
|
+
rw_config(:http_basic_auth_realm, value, "Application")
|
68
68
|
end
|
69
69
|
alias_method :http_basic_auth_realm=, :http_basic_auth_realm
|
70
70
|
end
|
@@ -78,7 +78,7 @@ module Authlogic
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def persist_by_http_auth
|
81
|
-
login_proc =
|
81
|
+
login_proc = proc do |login, password|
|
82
82
|
if !login.blank? && !password.blank?
|
83
83
|
send("#{login_field}=", login)
|
84
84
|
send("#{password_field}=", password)
|
@@ -42,7 +42,8 @@ module Authlogic
|
|
42
42
|
end
|
43
43
|
|
44
44
|
module InstanceMethods
|
45
|
-
# Creating an alias method for the "record" method based on the klass
|
45
|
+
# Creating an alias method for the "record" method based on the klass
|
46
|
+
# name, so that we can do:
|
46
47
|
#
|
47
48
|
# session.user
|
48
49
|
#
|
@@ -43,7 +43,8 @@ module Authlogic
|
|
43
43
|
alias_method :last_request_at_threshold=, :last_request_at_threshold
|
44
44
|
end
|
45
45
|
|
46
|
-
# The methods available for an Authlogic::Session::Base object that make
|
46
|
+
# The methods available for an Authlogic::Session::Base object that make
|
47
|
+
# up the magic columns feature.
|
47
48
|
module InstanceMethods
|
48
49
|
private
|
49
50
|
|
@@ -109,7 +110,8 @@ module Authlogic
|
|
109
110
|
if !record || !klass.column_names.include?("last_request_at")
|
110
111
|
return false
|
111
112
|
end
|
112
|
-
if controller.responds_to_last_request_update_allowed? &&
|
113
|
+
if controller.responds_to_last_request_update_allowed? &&
|
114
|
+
!controller.last_request_update_allowed?
|
113
115
|
return false
|
114
116
|
end
|
115
117
|
record.last_request_at.blank? ||
|
@@ -56,7 +56,7 @@ module Authlogic
|
|
56
56
|
|
57
57
|
# @api private
|
58
58
|
def required_magic_states_for(record)
|
59
|
-
[
|
59
|
+
%i[active approved confirmed].select { |state|
|
60
60
|
record.respond_to?("#{state}?")
|
61
61
|
}
|
62
62
|
end
|
@@ -64,16 +64,15 @@ module Authlogic
|
|
64
64
|
def validate_magic_states
|
65
65
|
return true if attempted_record.nil?
|
66
66
|
required_magic_states_for(attempted_record).each do |required_status|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
)
|
67
|
+
next if attempted_record.send("#{required_status}?")
|
68
|
+
errors.add(
|
69
|
+
:base,
|
70
|
+
I18n.t(
|
71
|
+
"error_messages.not_#{required_status}",
|
72
|
+
default: "Your account is not #{required_status}"
|
74
73
|
)
|
75
|
-
|
76
|
-
|
74
|
+
)
|
75
|
+
return false
|
77
76
|
end
|
78
77
|
true
|
79
78
|
end
|
@@ -82,20 +82,27 @@ module Authlogic
|
|
82
82
|
|
83
83
|
def persist_by_params
|
84
84
|
return false unless params_enabled?
|
85
|
-
self.unauthorized_record = search_for_record(
|
85
|
+
self.unauthorized_record = search_for_record(
|
86
|
+
"find_by_single_access_token",
|
87
|
+
params_credentials
|
88
|
+
)
|
86
89
|
self.single_access = valid?
|
87
90
|
end
|
88
91
|
|
89
92
|
def params_enabled?
|
90
|
-
|
91
|
-
|
93
|
+
if !params_credentials || !klass.column_names.include?("single_access_token")
|
94
|
+
return false
|
95
|
+
end
|
96
|
+
if controller.responds_to_single_access_allowed?
|
97
|
+
return controller.single_access_allowed?
|
98
|
+
end
|
92
99
|
|
93
100
|
case single_access_allowed_request_types
|
94
101
|
when Array
|
95
102
|
single_access_allowed_request_types.include?(controller.request_content_type) ||
|
96
103
|
single_access_allowed_request_types.include?(:all)
|
97
104
|
else
|
98
|
-
[
|
105
|
+
%i[all any].include?(single_access_allowed_request_types)
|
99
106
|
end
|
100
107
|
end
|
101
108
|
|
@@ -119,7 +119,7 @@ module Authlogic
|
|
119
119
|
# should be an instance method. It should also be prepared to accept a
|
120
120
|
# raw password and a crytped password.
|
121
121
|
#
|
122
|
-
# * <tt>Default:</tt> "valid_password?"
|
122
|
+
# * <tt>Default:</tt> "valid_password?" defined in acts_as_authentic/password.rb
|
123
123
|
# * <tt>Accepts:</tt> Symbol or String
|
124
124
|
def verify_password_method(value = nil)
|
125
125
|
rw_config(:verify_password_method, value, "valid_password?")
|
@@ -162,7 +162,11 @@ module Authlogic
|
|
162
162
|
super
|
163
163
|
values = Array.wrap(value)
|
164
164
|
if values.first.is_a?(Hash)
|
165
|
-
|
165
|
+
sliced = values
|
166
|
+
.first
|
167
|
+
.with_indifferent_access
|
168
|
+
.slice(login_field, password_field)
|
169
|
+
sliced.each do |field, val|
|
166
170
|
next if val.blank?
|
167
171
|
send("#{field}=", val)
|
168
172
|
end
|
@@ -179,7 +183,10 @@ module Authlogic
|
|
179
183
|
if generalize_credentials_error_messages?
|
180
184
|
add_general_credentials_error
|
181
185
|
else
|
182
|
-
errors.add(
|
186
|
+
errors.add(
|
187
|
+
password_field,
|
188
|
+
I18n.t("error_messages.password_invalid", default: "is not valid")
|
189
|
+
)
|
183
190
|
end
|
184
191
|
end
|
185
192
|
|
@@ -187,60 +194,84 @@ module Authlogic
|
|
187
194
|
if generalize_credentials_error_messages?
|
188
195
|
add_general_credentials_error
|
189
196
|
else
|
190
|
-
errors.add(
|
197
|
+
errors.add(
|
198
|
+
login_field,
|
199
|
+
I18n.t("error_messages.login_not_found", default: "is not valid")
|
200
|
+
)
|
191
201
|
end
|
192
202
|
end
|
193
203
|
|
194
|
-
def
|
195
|
-
|
196
|
-
|
197
|
-
self.class.send(:attr_reader, login_field) unless respond_to?(login_field)
|
198
|
-
end
|
204
|
+
def authenticating_with_password?
|
205
|
+
login_field && (!send(login_field).nil? || !send("protected_#{password_field}").nil?)
|
206
|
+
end
|
199
207
|
|
200
|
-
|
201
|
-
|
202
|
-
|
208
|
+
def configure_password_methods
|
209
|
+
define_login_field_methods
|
210
|
+
define_password_field_methods
|
211
|
+
end
|
203
212
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
self.class.class_eval <<-EOS, __FILE__, __LINE__
|
209
|
-
private
|
210
|
-
def protected_#{password_field}
|
211
|
-
@#{password_field}
|
212
|
-
end
|
213
|
-
EOS
|
214
|
-
end
|
213
|
+
def define_login_field_methods
|
214
|
+
return unless login_field
|
215
|
+
self.class.send(:attr_writer, login_field) unless respond_to?("#{login_field}=")
|
216
|
+
self.class.send(:attr_reader, login_field) unless respond_to?(login_field)
|
215
217
|
end
|
216
218
|
|
217
|
-
def
|
218
|
-
|
219
|
+
def define_password_field_methods
|
220
|
+
return unless password_field
|
221
|
+
self.class.send(:attr_writer, password_field) unless respond_to?("#{password_field}=")
|
222
|
+
self.class.send(:define_method, password_field) {} unless respond_to?(password_field)
|
223
|
+
|
224
|
+
# The password should not be accessible publicly. This way forms
|
225
|
+
# using form_for don't fill the password with the attempted
|
226
|
+
# password. To prevent this we just create this method that is
|
227
|
+
# private.
|
228
|
+
self.class.class_eval <<-EOS, __FILE__, __LINE__ + 1
|
229
|
+
private
|
230
|
+
def protected_#{password_field}
|
231
|
+
@#{password_field}
|
232
|
+
end
|
233
|
+
EOS
|
219
234
|
end
|
220
235
|
|
236
|
+
# In keeping with the metaphor of ActiveRecord, verification of the
|
237
|
+
# password is referred to as a "validation".
|
221
238
|
def validate_by_password
|
222
239
|
self.invalid_password = false
|
223
|
-
|
224
|
-
# check for blank fields
|
225
|
-
if send(login_field).blank?
|
226
|
-
errors.add(login_field, I18n.t('error_messages.login_blank', default: "cannot be blank"))
|
227
|
-
end
|
228
|
-
if send("protected_#{password_field}").blank?
|
229
|
-
errors.add(password_field, I18n.t('error_messages.password_blank', default: "cannot be blank"))
|
230
|
-
end
|
240
|
+
validate_by_password__blank_fields
|
231
241
|
return if errors.count > 0
|
232
|
-
|
233
242
|
self.attempted_record = search_for_record(find_by_login_method, send(login_field))
|
234
243
|
if attempted_record.blank?
|
235
244
|
add_login_not_found_error
|
236
245
|
return
|
237
246
|
end
|
247
|
+
validate_by_password__invalid_password
|
248
|
+
end
|
249
|
+
|
250
|
+
def validate_by_password__blank_fields
|
251
|
+
if send(login_field).blank?
|
252
|
+
errors.add(
|
253
|
+
login_field,
|
254
|
+
I18n.t("error_messages.login_blank", default: "cannot be blank")
|
255
|
+
)
|
256
|
+
end
|
257
|
+
if send("protected_#{password_field}").blank?
|
258
|
+
errors.add(
|
259
|
+
password_field,
|
260
|
+
I18n.t("error_messages.password_blank", default: "cannot be blank")
|
261
|
+
)
|
262
|
+
end
|
263
|
+
end
|
238
264
|
|
239
|
-
|
240
|
-
|
265
|
+
# Verify the password, usually using `valid_password?` in
|
266
|
+
# `acts_as_authentic/password.rb`. If it cannot be verified, we
|
267
|
+
# refer to it as "invalid".
|
268
|
+
def validate_by_password__invalid_password
|
269
|
+
unless attempted_record.send(
|
270
|
+
verify_password_method,
|
271
|
+
send("protected_#{password_field}")
|
272
|
+
)
|
241
273
|
self.invalid_password = true
|
242
274
|
add_invalid_password_error
|
243
|
-
return
|
244
275
|
end
|
245
276
|
end
|
246
277
|
|
@@ -261,7 +292,10 @@ module Authlogic
|
|
261
292
|
else
|
262
293
|
"#{login_field.to_s.humanize}/Password combination is not valid"
|
263
294
|
end
|
264
|
-
errors.add(
|
295
|
+
errors.add(
|
296
|
+
:base,
|
297
|
+
I18n.t("error_messages.general_credentials_error", default: error_message)
|
298
|
+
)
|
265
299
|
end
|
266
300
|
|
267
301
|
def generalize_credentials_error_messages?
|