authlogic 4.0.1 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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?
|