authlogic 3.4.6 → 4.2.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 +5 -5
- data/.github/ISSUE_TEMPLATE.md +13 -0
- data/.github/triage.md +87 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +127 -0
- data/.rubocop_todo.yml +65 -0
- data/.travis.yml +18 -10
- data/CHANGELOG.md +156 -6
- data/CONTRIBUTING.md +71 -3
- data/Gemfile +2 -2
- data/README.md +386 -0
- data/Rakefile +13 -7
- data/UPGRADING.md +22 -0
- data/authlogic.gemspec +33 -22
- data/lib/authlogic.rb +60 -52
- data/lib/authlogic/acts_as_authentic/base.rb +40 -26
- data/lib/authlogic/acts_as_authentic/email.rb +96 -32
- data/lib/authlogic/acts_as_authentic/logged_in_status.rb +36 -12
- data/lib/authlogic/acts_as_authentic/login.rb +114 -49
- data/lib/authlogic/acts_as_authentic/magic_columns.rb +17 -6
- data/lib/authlogic/acts_as_authentic/password.rb +296 -139
- data/lib/authlogic/acts_as_authentic/perishable_token.rb +34 -20
- data/lib/authlogic/acts_as_authentic/persistence_token.rb +20 -24
- data/lib/authlogic/acts_as_authentic/queries/find_with_case.rb +67 -0
- data/lib/authlogic/acts_as_authentic/restful_authentication.rb +68 -23
- data/lib/authlogic/acts_as_authentic/session_maintenance.rb +128 -85
- data/lib/authlogic/acts_as_authentic/single_access_token.rb +41 -25
- data/lib/authlogic/acts_as_authentic/validations_scope.rb +8 -8
- data/lib/authlogic/authenticates_many/association.rb +22 -14
- data/lib/authlogic/authenticates_many/base.rb +35 -16
- data/lib/authlogic/config.rb +10 -10
- data/lib/authlogic/controller_adapters/abstract_adapter.rb +40 -12
- data/lib/authlogic/controller_adapters/rack_adapter.rb +15 -8
- data/lib/authlogic/controller_adapters/rails_adapter.rb +42 -22
- data/lib/authlogic/controller_adapters/sinatra_adapter.rb +3 -3
- data/lib/authlogic/crypto_providers.rb +91 -0
- data/lib/authlogic/crypto_providers/aes256.rb +42 -14
- data/lib/authlogic/crypto_providers/bcrypt.rb +35 -20
- data/lib/authlogic/crypto_providers/md5.rb +11 -9
- data/lib/authlogic/crypto_providers/scrypt.rb +26 -13
- data/lib/authlogic/crypto_providers/sha1.rb +14 -8
- data/lib/authlogic/crypto_providers/sha256.rb +16 -12
- data/lib/authlogic/crypto_providers/sha512.rb +8 -24
- data/lib/authlogic/crypto_providers/wordpress.rb +44 -15
- data/lib/authlogic/i18n.rb +33 -20
- data/lib/authlogic/i18n/translator.rb +1 -1
- data/lib/authlogic/random.rb +12 -29
- data/lib/authlogic/regex.rb +59 -27
- data/lib/authlogic/session/activation.rb +36 -23
- data/lib/authlogic/session/active_record_trickery.rb +13 -10
- data/lib/authlogic/session/base.rb +20 -8
- data/lib/authlogic/session/brute_force_protection.rb +87 -56
- data/lib/authlogic/session/callbacks.rb +99 -49
- data/lib/authlogic/session/cookies.rb +128 -59
- data/lib/authlogic/session/existence.rb +29 -19
- data/lib/authlogic/session/foundation.rb +70 -16
- data/lib/authlogic/session/http_auth.rb +39 -31
- data/lib/authlogic/session/id.rb +27 -15
- data/lib/authlogic/session/klass.rb +17 -13
- data/lib/authlogic/session/magic_columns.rb +78 -59
- data/lib/authlogic/session/magic_states.rb +50 -27
- data/lib/authlogic/session/params.rb +79 -50
- data/lib/authlogic/session/password.rb +197 -118
- data/lib/authlogic/session/perishable_token.rb +12 -6
- data/lib/authlogic/session/persistence.rb +20 -14
- data/lib/authlogic/session/priority_record.rb +20 -16
- data/lib/authlogic/session/scopes.rb +63 -33
- data/lib/authlogic/session/session.rb +40 -25
- data/lib/authlogic/session/timeout.rb +51 -34
- data/lib/authlogic/session/unauthorized_record.rb +24 -18
- data/lib/authlogic/session/validation.rb +32 -21
- data/lib/authlogic/test_case.rb +123 -35
- data/lib/authlogic/test_case/mock_controller.rb +14 -13
- data/lib/authlogic/test_case/mock_cookie_jar.rb +14 -5
- data/lib/authlogic/test_case/mock_logger.rb +1 -1
- data/lib/authlogic/test_case/mock_request.rb +9 -4
- data/lib/authlogic/test_case/rails_request_adapter.rb +8 -7
- data/lib/authlogic/version.rb +21 -0
- data/test/acts_as_authentic_test/base_test.rb +1 -1
- data/test/acts_as_authentic_test/email_test.rb +80 -63
- data/test/acts_as_authentic_test/logged_in_status_test.rb +14 -8
- data/test/acts_as_authentic_test/login_test.rb +91 -49
- data/test/acts_as_authentic_test/magic_columns_test.rb +13 -13
- data/test/acts_as_authentic_test/password_test.rb +82 -60
- data/test/acts_as_authentic_test/perishable_token_test.rb +31 -25
- data/test/acts_as_authentic_test/persistence_token_test.rb +9 -5
- data/test/acts_as_authentic_test/restful_authentication_test.rb +18 -9
- data/test/acts_as_authentic_test/session_maintenance_test.rb +86 -22
- data/test/acts_as_authentic_test/single_access_test.rb +15 -15
- data/test/adapter_test.rb +21 -0
- data/test/authenticates_many_test.rb +26 -11
- data/test/config_test.rb +9 -9
- data/test/crypto_provider_test/aes256_test.rb +3 -3
- data/test/crypto_provider_test/bcrypt_test.rb +1 -1
- data/test/crypto_provider_test/scrypt_test.rb +2 -2
- data/test/crypto_provider_test/sha1_test.rb +4 -4
- data/test/crypto_provider_test/sha256_test.rb +2 -2
- data/test/crypto_provider_test/sha512_test.rb +3 -3
- data/test/crypto_provider_test/wordpress_test.rb +24 -0
- data/test/gemfiles/Gemfile.rails-4.2.x +2 -2
- data/test/gemfiles/Gemfile.rails-5.0.x +6 -0
- data/test/gemfiles/Gemfile.rails-5.1.x +6 -0
- data/test/gemfiles/Gemfile.rails-5.2.x +6 -0
- data/test/gemfiles/Gemfile.rails-master +6 -0
- data/test/i18n_test.rb +9 -9
- data/test/libs/affiliate.rb +2 -2
- data/test/libs/company.rb +4 -4
- data/test/libs/employee.rb +2 -2
- data/test/libs/employee_session.rb +1 -1
- data/test/libs/ldaper.rb +1 -1
- data/test/libs/project.rb +1 -1
- data/test/libs/user_session.rb +2 -2
- data/test/random_test.rb +9 -38
- data/test/session_test/activation_test.rb +7 -7
- data/test/session_test/active_record_trickery_test.rb +9 -6
- data/test/session_test/brute_force_protection_test.rb +26 -21
- data/test/session_test/callbacks_test.rb +10 -4
- data/test/session_test/cookies_test.rb +54 -20
- data/test/session_test/existence_test.rb +45 -23
- data/test/session_test/foundation_test.rb +17 -1
- data/test/session_test/http_auth_test.rb +11 -12
- data/test/session_test/id_test.rb +3 -3
- data/test/session_test/klass_test.rb +2 -2
- data/test/session_test/magic_columns_test.rb +15 -17
- data/test/session_test/magic_states_test.rb +17 -19
- data/test/session_test/params_test.rb +26 -20
- data/test/session_test/password_test.rb +11 -12
- data/test/session_test/perishability_test.rb +5 -5
- data/test/session_test/persistence_test.rb +4 -3
- data/test/session_test/scopes_test.rb +15 -9
- data/test/session_test/session_test.rb +7 -6
- data/test/session_test/timeout_test.rb +16 -14
- data/test/session_test/unauthorized_record_test.rb +3 -3
- data/test/session_test/validation_test.rb +5 -5
- data/test/test_helper.rb +115 -49
- metadata +107 -36
- data/README.rdoc +0 -232
- 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,15 +1,19 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session
|
3
|
-
# This module is responsible for authenticating the user via params, which ultimately
|
3
|
+
# This module is responsible for authenticating the user via params, which ultimately
|
4
|
+
# allows the user to log in using a URL like the following:
|
4
5
|
#
|
5
6
|
# https://www.domain.com?user_credentials=4LiXF7FiGUppIPubBPey
|
6
7
|
#
|
7
|
-
# Notice the token in the URL, this is a single access token. A single access token is
|
8
|
-
#
|
9
|
-
#
|
8
|
+
# Notice the token in the URL, this is a single access token. A single access token is
|
9
|
+
# used for single access only, it is not persisted. Meaning the user provides it,
|
10
|
+
# Authlogic grants them access, and that's it. If they want access again they need to
|
11
|
+
# provide the token again. Authlogic will *NEVER* try to persist the session after
|
12
|
+
# authenticating through this method.
|
10
13
|
#
|
11
|
-
# For added security, this token is *ONLY* allowed for RSS and ATOM requests. You can
|
12
|
-
#
|
14
|
+
# For added security, this token is *ONLY* allowed for RSS and ATOM requests. You can
|
15
|
+
# change this with the configuration. You can also define if it is allowed dynamically
|
16
|
+
# by defining a single_access_allowed? method in your controller. For example:
|
13
17
|
#
|
14
18
|
# class UsersController < ApplicationController
|
15
19
|
# private
|
@@ -17,8 +21,9 @@ module Authlogic
|
|
17
21
|
# action_name == "index"
|
18
22
|
# end
|
19
23
|
#
|
20
|
-
# Also, by default, this token is permanent. Meaning if the user changes their
|
21
|
-
# when it is explicitly
|
24
|
+
# Also, by default, this token is permanent. Meaning if the user changes their
|
25
|
+
# password, this token will remain the same. It will only change when it is explicitly
|
26
|
+
# reset.
|
22
27
|
#
|
23
28
|
# You can modify all of this behavior with the Config sub module.
|
24
29
|
module Params
|
@@ -30,15 +35,19 @@ module Authlogic
|
|
30
35
|
persist :persist_by_params
|
31
36
|
end
|
32
37
|
end
|
33
|
-
|
38
|
+
|
34
39
|
# Configuration for the params / single access feature.
|
35
40
|
module Config
|
36
|
-
# Works exactly like cookie_key, but for params. So a user can login via
|
41
|
+
# Works exactly like cookie_key, but for params. So a user can login via
|
42
|
+
# params just like a cookie or a session. Your URL would look like:
|
37
43
|
#
|
38
44
|
# http://www.domain.com?user_credentials=my_single_access_key
|
39
45
|
#
|
40
|
-
# You can change the "user_credentials" key above with this
|
41
|
-
#
|
46
|
+
# You can change the "user_credentials" key above with this
|
47
|
+
# configuration option. Keep in mind, just like cookie_key, if you
|
48
|
+
# supply an id the id will be appended to the front. Check out
|
49
|
+
# cookie_key for more details. Also checkout the "Single Access /
|
50
|
+
# Private Feeds Access" section in the README.
|
42
51
|
#
|
43
52
|
# * <tt>Default:</tt> cookie_key
|
44
53
|
# * <tt>Accepts:</tt> String
|
@@ -46,56 +55,76 @@ module Authlogic
|
|
46
55
|
rw_config(:params_key, value, cookie_key)
|
47
56
|
end
|
48
57
|
alias_method :params_key=, :params_key
|
49
|
-
|
50
|
-
# Authentication is allowed via a single access token, but maybe this is
|
51
|
-
# something you
|
58
|
+
|
59
|
+
# Authentication is allowed via a single access token, but maybe this is
|
60
|
+
# something you don't want for your application as a whole. Maybe this
|
61
|
+
# is something you only want for specific request types. Specify a list
|
62
|
+
# of allowed request types and single access authentication will only be
|
52
63
|
# allowed for the ones you specify.
|
53
64
|
#
|
54
65
|
# * <tt>Default:</tt> ["application/rss+xml", "application/atom+xml"]
|
55
|
-
# * <tt>Accepts:</tt> String of a request type, or :all or :any to
|
66
|
+
# * <tt>Accepts:</tt> String of a request type, or :all or :any to
|
67
|
+
# allow single access authentication for any and all request types
|
56
68
|
def single_access_allowed_request_types(value = nil)
|
57
|
-
rw_config(
|
69
|
+
rw_config(
|
70
|
+
:single_access_allowed_request_types,
|
71
|
+
value,
|
72
|
+
["application/rss+xml", "application/atom+xml"]
|
73
|
+
)
|
58
74
|
end
|
59
75
|
alias_method :single_access_allowed_request_types=, :single_access_allowed_request_types
|
60
76
|
end
|
61
|
-
|
62
|
-
# The methods available for an Authlogic::Session::Base object that make
|
77
|
+
|
78
|
+
# The methods available for an Authlogic::Session::Base object that make
|
79
|
+
# up the params / single access feature.
|
63
80
|
module InstanceMethods
|
64
81
|
private
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
else
|
79
|
-
[:all, :any].include?(single_access_allowed_request_types)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def params_key
|
84
|
-
build_key(self.class.params_key)
|
85
|
-
end
|
86
|
-
|
87
|
-
def single_access?
|
88
|
-
single_access == true
|
82
|
+
|
83
|
+
def persist_by_params
|
84
|
+
return false unless params_enabled?
|
85
|
+
self.unauthorized_record = search_for_record(
|
86
|
+
"find_by_single_access_token",
|
87
|
+
params_credentials
|
88
|
+
)
|
89
|
+
self.single_access = valid?
|
90
|
+
end
|
91
|
+
|
92
|
+
def params_enabled?
|
93
|
+
if !params_credentials || !klass.column_names.include?("single_access_token")
|
94
|
+
return false
|
89
95
|
end
|
90
|
-
|
91
|
-
|
92
|
-
self.class.single_access_allowed_request_types
|
96
|
+
if controller.responds_to_single_access_allowed?
|
97
|
+
return controller.single_access_allowed?
|
93
98
|
end
|
94
|
-
|
95
|
-
|
96
|
-
|
99
|
+
params_enabled_by_allowed_request_types?
|
100
|
+
end
|
101
|
+
|
102
|
+
def params_enabled_by_allowed_request_types?
|
103
|
+
case single_access_allowed_request_types
|
104
|
+
when Array
|
105
|
+
single_access_allowed_request_types.include?(controller.request_content_type) ||
|
106
|
+
single_access_allowed_request_types.include?(:all)
|
107
|
+
else
|
108
|
+
%i[all any].include?(single_access_allowed_request_types)
|
97
109
|
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def params_key
|
113
|
+
build_key(self.class.params_key)
|
114
|
+
end
|
115
|
+
|
116
|
+
def single_access?
|
117
|
+
single_access == true
|
118
|
+
end
|
119
|
+
|
120
|
+
def single_access_allowed_request_types
|
121
|
+
self.class.single_access_allowed_request_types
|
122
|
+
end
|
123
|
+
|
124
|
+
def params_credentials
|
125
|
+
controller.params[params_key]
|
126
|
+
end
|
98
127
|
end
|
99
128
|
end
|
100
129
|
end
|
101
|
-
end
|
130
|
+
end
|
@@ -6,25 +6,29 @@ module Authlogic
|
|
6
6
|
klass.class_eval do
|
7
7
|
extend Config
|
8
8
|
include InstanceMethods
|
9
|
-
validate :validate_by_password, :
|
10
|
-
|
9
|
+
validate :validate_by_password, if: :authenticating_with_password?
|
10
|
+
|
11
11
|
class << self
|
12
12
|
attr_accessor :configured_password_methods
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
# Password configuration
|
18
18
|
module Config
|
19
|
-
# Authlogic tries to validate the credentials passed to it. One part of
|
20
|
-
#
|
19
|
+
# Authlogic tries to validate the credentials passed to it. One part of
|
20
|
+
# validation is actually finding the user and making sure it exists.
|
21
|
+
# What method it uses the do this is up to you.
|
21
22
|
#
|
22
|
-
# Let's say you have a UserSession that is authenticating a User. By
|
23
|
-
#
|
24
|
-
#
|
23
|
+
# Let's say you have a UserSession that is authenticating a User. By
|
24
|
+
# default UserSession will call User.find_by_login(login). You can
|
25
|
+
# change what method UserSession calls by specifying it here. Then in
|
26
|
+
# your User model you can make that method do anything you want, giving
|
27
|
+
# you complete control of how users are found by the UserSession.
|
25
28
|
#
|
26
|
-
# Let's take an example: You want to allow users to login by username or
|
27
|
-
#
|
29
|
+
# Let's take an example: You want to allow users to login by username or
|
30
|
+
# email. Set this to the name of the class method that does this in the
|
31
|
+
# User model. Let's call it "find_by_username_or_email"
|
28
32
|
#
|
29
33
|
# class User < ActiveRecord::Base
|
30
34
|
# def self.find_by_username_or_email(login)
|
@@ -32,8 +36,10 @@ module Authlogic
|
|
32
36
|
# end
|
33
37
|
# end
|
34
38
|
#
|
35
|
-
# Now just specify the name of this method for this configuration option
|
36
|
-
#
|
39
|
+
# Now just specify the name of this method for this configuration option
|
40
|
+
# and you are all set. You can do anything you want here. Maybe you
|
41
|
+
# allow users to have multiple logins and you want to search a has_many
|
42
|
+
# relationship, etc. The sky is the limit.
|
37
43
|
#
|
38
44
|
# * <tt>Default:</tt> "find_by_smart_case_login_field"
|
39
45
|
# * <tt>Accepts:</tt> Symbol or String
|
@@ -41,10 +47,12 @@ module Authlogic
|
|
41
47
|
rw_config(:find_by_login_method, value, "find_by_smart_case_login_field")
|
42
48
|
end
|
43
49
|
alias_method :find_by_login_method=, :find_by_login_method
|
44
|
-
|
45
|
-
# The text used to identify credentials (username/password) combination
|
46
|
-
#
|
47
|
-
#
|
50
|
+
|
51
|
+
# The text used to identify credentials (username/password) combination
|
52
|
+
# when a bad login attempt occurs. When you show error messages for a
|
53
|
+
# bad login, it's considered good security practice to hide which field
|
54
|
+
# the user has entered incorrectly (the login field or the password
|
55
|
+
# field). For a full explanation, see
|
48
56
|
# http://www.gnucitizen.org/blog/username-enumeration-vulnerabilities/
|
49
57
|
#
|
50
58
|
# Example of use:
|
@@ -53,36 +61,42 @@ module Authlogic
|
|
53
61
|
# generalize_credentials_error_messages true
|
54
62
|
# end
|
55
63
|
#
|
56
|
-
# This would make the error message for bad logins and bad passwords
|
64
|
+
# This would make the error message for bad logins and bad passwords
|
65
|
+
# look identical:
|
57
66
|
#
|
58
67
|
# Login/Password combination is not valid
|
59
|
-
#
|
68
|
+
#
|
60
69
|
# Alternatively you may use a custom message:
|
61
|
-
#
|
70
|
+
#
|
62
71
|
# class UserSession < AuthLogic::Session::Base
|
63
72
|
# generalize_credentials_error_messages "Your login information is invalid"
|
64
73
|
# end
|
65
74
|
#
|
66
75
|
# This will instead show your custom error message when the UserSession is invalid.
|
67
76
|
#
|
68
|
-
# The downside to enabling this is that is can be too vague for a user
|
69
|
-
#
|
77
|
+
# The downside to enabling this is that is can be too vague for a user
|
78
|
+
# that has a hard time remembering their username and password
|
79
|
+
# combinations. It also disables the ability to to highlight the field
|
70
80
|
# with the error when you use form_for.
|
71
81
|
#
|
72
|
-
# If you are developing an app where security is an extreme priority
|
73
|
-
#
|
74
|
-
#
|
82
|
+
# If you are developing an app where security is an extreme priority
|
83
|
+
# (such as a financial application), then you should enable this.
|
84
|
+
# Otherwise, leaving this off is fine.
|
85
|
+
#
|
75
86
|
# * <tt>Default</tt> false
|
76
87
|
# * <tt>Accepts:</tt> Boolean
|
77
88
|
def generalize_credentials_error_messages(value = nil)
|
78
89
|
rw_config(:generalize_credentials_error_messages, value, false)
|
79
90
|
end
|
80
91
|
alias_method :generalize_credentials_error_messages=, :generalize_credentials_error_messages
|
81
|
-
|
82
|
-
# The name of the method you want Authlogic to create for storing the
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
92
|
+
|
93
|
+
# The name of the method you want Authlogic to create for storing the
|
94
|
+
# login / username. Keep in mind this is just for your
|
95
|
+
# Authlogic::Session, if you want it can be something completely
|
96
|
+
# different than the field in your model. So if you wanted people to
|
97
|
+
# login with a field called "login" and then find users by email this is
|
98
|
+
# completely doable. See the find_by_login_method configuration option
|
99
|
+
# for more details.
|
86
100
|
#
|
87
101
|
# * <tt>Default:</tt> klass.login_field || klass.email_field
|
88
102
|
# * <tt>Accepts:</tt> Symbol or String
|
@@ -90,8 +104,9 @@ module Authlogic
|
|
90
104
|
rw_config(:login_field, value, klass.login_field || klass.email_field)
|
91
105
|
end
|
92
106
|
alias_method :login_field=, :login_field
|
93
|
-
|
94
|
-
# Works exactly like login_field, but for the password instead. Returns
|
107
|
+
|
108
|
+
# Works exactly like login_field, but for the password instead. Returns
|
109
|
+
# :password if a login_field exists.
|
95
110
|
#
|
96
111
|
# * <tt>Default:</tt> :password
|
97
112
|
# * <tt>Accepts:</tt> Symbol or String
|
@@ -99,29 +114,32 @@ module Authlogic
|
|
99
114
|
rw_config(:password_field, value, login_field && :password)
|
100
115
|
end
|
101
116
|
alias_method :password_field=, :password_field
|
102
|
-
|
103
|
-
# The name of the method in your model used to verify the password. This
|
104
|
-
# be
|
117
|
+
|
118
|
+
# The name of the method in your model used to verify the password. This
|
119
|
+
# should be an instance method. It should also be prepared to accept a
|
120
|
+
# raw password and a crytped password.
|
105
121
|
#
|
106
|
-
# * <tt>Default:</tt> "valid_password?"
|
122
|
+
# * <tt>Default:</tt> "valid_password?" defined in acts_as_authentic/password.rb
|
107
123
|
# * <tt>Accepts:</tt> Symbol or String
|
108
124
|
def verify_password_method(value = nil)
|
109
125
|
rw_config(:verify_password_method, value, "valid_password?")
|
110
126
|
end
|
111
127
|
alias_method :verify_password_method=, :verify_password_method
|
112
128
|
end
|
113
|
-
|
129
|
+
|
114
130
|
# Password related instance methods
|
115
131
|
module InstanceMethods
|
116
132
|
def initialize(*args)
|
117
|
-
|
133
|
+
unless self.class.configured_password_methods
|
118
134
|
configure_password_methods
|
119
135
|
self.class.configured_password_methods = true
|
120
136
|
end
|
137
|
+
instance_variable_set("@#{password_field}", nil)
|
121
138
|
super
|
122
139
|
end
|
123
|
-
|
124
|
-
# Returns the login_field / password_field credentials combination in
|
140
|
+
|
141
|
+
# Returns the login_field / password_field credentials combination in
|
142
|
+
# hash form.
|
125
143
|
def credentials
|
126
144
|
if authenticating_with_password?
|
127
145
|
details = {}
|
@@ -132,107 +150,168 @@ module Authlogic
|
|
132
150
|
super
|
133
151
|
end
|
134
152
|
end
|
135
|
-
|
136
|
-
# Accepts the login_field / password_field credentials combination in
|
153
|
+
|
154
|
+
# Accepts the login_field / password_field credentials combination in
|
155
|
+
# hash form.
|
156
|
+
#
|
157
|
+
# You must pass an actual Hash, `ActionController::Parameters` is
|
158
|
+
# specifically not allowed.
|
159
|
+
#
|
160
|
+
# See `Authlogic::Session::Foundation#credentials=` for an overview of
|
161
|
+
# all method signatures.
|
137
162
|
def credentials=(value)
|
138
163
|
super
|
139
|
-
values =
|
164
|
+
values = Array.wrap(value)
|
140
165
|
if values.first.is_a?(Hash)
|
141
|
-
|
142
|
-
|
143
|
-
|
166
|
+
sliced = values
|
167
|
+
.first
|
168
|
+
.with_indifferent_access
|
169
|
+
.slice(login_field, password_field)
|
170
|
+
sliced.each do |field, val|
|
171
|
+
next if val.blank?
|
172
|
+
send("#{field}=", val)
|
144
173
|
end
|
145
174
|
end
|
146
175
|
end
|
147
|
-
|
176
|
+
|
148
177
|
def invalid_password?
|
149
178
|
invalid_password == true
|
150
179
|
end
|
151
|
-
|
180
|
+
|
152
181
|
private
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
self.class.class_eval <<-"end_eval", __FILE__, __LINE__
|
164
|
-
private
|
165
|
-
# The password should not be accessible publicly. This way forms using form_for don't fill the password with the
|
166
|
-
# attempted password. To prevent this we just create this method that is private.
|
167
|
-
def protected_#{password_field}
|
168
|
-
@#{password_field}
|
169
|
-
end
|
170
|
-
end_eval
|
171
|
-
end
|
182
|
+
|
183
|
+
def add_invalid_password_error
|
184
|
+
if generalize_credentials_error_messages?
|
185
|
+
add_general_credentials_error
|
186
|
+
else
|
187
|
+
errors.add(
|
188
|
+
password_field,
|
189
|
+
I18n.t("error_messages.password_invalid", default: "is not valid")
|
190
|
+
)
|
172
191
|
end
|
192
|
+
end
|
173
193
|
|
174
|
-
|
175
|
-
|
194
|
+
def add_login_not_found_error
|
195
|
+
if generalize_credentials_error_messages?
|
196
|
+
add_general_credentials_error
|
197
|
+
else
|
198
|
+
errors.add(
|
199
|
+
login_field,
|
200
|
+
I18n.t("error_messages.login_not_found", default: "is not valid")
|
201
|
+
)
|
176
202
|
end
|
177
|
-
|
178
|
-
def validate_by_password
|
179
|
-
self.invalid_password = false
|
180
|
-
|
181
|
-
# check for blank fields
|
182
|
-
errors.add(login_field, I18n.t('error_messages.login_blank', :default => "cannot be blank")) if send(login_field).blank?
|
183
|
-
errors.add(password_field, I18n.t('error_messages.password_blank', :default => "cannot be blank")) if send("protected_#{password_field}").blank?
|
184
|
-
return if errors.count > 0
|
185
|
-
|
186
|
-
# check for unknown login
|
187
|
-
self.attempted_record = search_for_record(find_by_login_method, send(login_field))
|
188
|
-
if attempted_record.blank?
|
189
|
-
generalize_credentials_error_messages? ?
|
190
|
-
add_general_credentials_error :
|
191
|
-
errors.add(login_field, I18n.t('error_messages.login_not_found', :default => "is not valid"))
|
192
|
-
return
|
193
|
-
end
|
203
|
+
end
|
194
204
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
205
|
+
def authenticating_with_password?
|
206
|
+
login_field && (!send(login_field).nil? || !send("protected_#{password_field}").nil?)
|
207
|
+
end
|
208
|
+
|
209
|
+
def configure_password_methods
|
210
|
+
define_login_field_methods
|
211
|
+
define_password_field_methods
|
212
|
+
end
|
213
|
+
|
214
|
+
def define_login_field_methods
|
215
|
+
return unless login_field
|
216
|
+
self.class.send(:attr_writer, login_field) unless respond_to?("#{login_field}=")
|
217
|
+
self.class.send(:attr_reader, login_field) unless respond_to?(login_field)
|
218
|
+
end
|
219
|
+
|
220
|
+
def define_password_field_methods
|
221
|
+
return unless password_field
|
222
|
+
self.class.send(:attr_writer, password_field) unless respond_to?("#{password_field}=")
|
223
|
+
self.class.send(:define_method, password_field) {} unless respond_to?(password_field)
|
224
|
+
|
225
|
+
# The password should not be accessible publicly. This way forms
|
226
|
+
# using form_for don't fill the password with the attempted
|
227
|
+
# password. To prevent this we just create this method that is
|
228
|
+
# private.
|
229
|
+
self.class.class_eval(
|
230
|
+
<<-EOS, __FILE__, __LINE__ + 1
|
231
|
+
private
|
232
|
+
def protected_#{password_field}
|
233
|
+
@#{password_field}
|
234
|
+
end
|
235
|
+
EOS
|
236
|
+
)
|
237
|
+
end
|
238
|
+
|
239
|
+
# In keeping with the metaphor of ActiveRecord, verification of the
|
240
|
+
# password is referred to as a "validation".
|
241
|
+
def validate_by_password
|
242
|
+
self.invalid_password = false
|
243
|
+
validate_by_password__blank_fields
|
244
|
+
return if errors.count > 0
|
245
|
+
self.attempted_record = search_for_record(find_by_login_method, send(login_field))
|
246
|
+
if attempted_record.blank?
|
247
|
+
add_login_not_found_error
|
248
|
+
return
|
249
|
+
end
|
250
|
+
validate_by_password__invalid_password
|
251
|
+
end
|
252
|
+
|
253
|
+
def validate_by_password__blank_fields
|
254
|
+
if send(login_field).blank?
|
255
|
+
errors.add(
|
256
|
+
login_field,
|
257
|
+
I18n.t("error_messages.login_blank", default: "cannot be blank")
|
258
|
+
)
|
203
259
|
end
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
260
|
+
if send("protected_#{password_field}").blank?
|
261
|
+
errors.add(
|
262
|
+
password_field,
|
263
|
+
I18n.t("error_messages.password_blank", default: "cannot be blank")
|
264
|
+
)
|
209
265
|
end
|
210
|
-
|
211
|
-
|
212
|
-
|
266
|
+
end
|
267
|
+
|
268
|
+
# Verify the password, usually using `valid_password?` in
|
269
|
+
# `acts_as_authentic/password.rb`. If it cannot be verified, we
|
270
|
+
# refer to it as "invalid".
|
271
|
+
def validate_by_password__invalid_password
|
272
|
+
unless attempted_record.send(
|
273
|
+
verify_password_method,
|
274
|
+
send("protected_#{password_field}")
|
275
|
+
)
|
276
|
+
self.invalid_password = true
|
277
|
+
add_invalid_password_error
|
213
278
|
end
|
214
|
-
|
215
|
-
|
216
|
-
|
279
|
+
end
|
280
|
+
|
281
|
+
attr_accessor :invalid_password
|
282
|
+
|
283
|
+
def find_by_login_method
|
284
|
+
self.class.find_by_login_method
|
285
|
+
end
|
286
|
+
|
287
|
+
def login_field
|
288
|
+
self.class.login_field
|
289
|
+
end
|
290
|
+
|
291
|
+
def add_general_credentials_error
|
292
|
+
error_message =
|
217
293
|
if self.class.generalize_credentials_error_messages.is_a? String
|
218
294
|
self.class.generalize_credentials_error_messages
|
219
295
|
else
|
220
296
|
"#{login_field.to_s.humanize}/Password combination is not valid"
|
221
297
|
end
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
298
|
+
errors.add(
|
299
|
+
:base,
|
300
|
+
I18n.t("error_messages.general_credentials_error", default: error_message)
|
301
|
+
)
|
302
|
+
end
|
303
|
+
|
304
|
+
def generalize_credentials_error_messages?
|
305
|
+
self.class.generalize_credentials_error_messages
|
306
|
+
end
|
307
|
+
|
308
|
+
def password_field
|
309
|
+
self.class.password_field
|
310
|
+
end
|
311
|
+
|
312
|
+
def verify_password_method
|
313
|
+
self.class.verify_password_method
|
314
|
+
end
|
236
315
|
end
|
237
316
|
end
|
238
317
|
end
|