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.
Files changed (140) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE.md +13 -0
  3. data/.github/triage.md +87 -0
  4. data/.gitignore +4 -0
  5. data/.rubocop.yml +127 -0
  6. data/.rubocop_todo.yml +65 -0
  7. data/.travis.yml +18 -10
  8. data/CHANGELOG.md +156 -6
  9. data/CONTRIBUTING.md +71 -3
  10. data/Gemfile +2 -2
  11. data/README.md +386 -0
  12. data/Rakefile +13 -7
  13. data/UPGRADING.md +22 -0
  14. data/authlogic.gemspec +33 -22
  15. data/lib/authlogic.rb +60 -52
  16. data/lib/authlogic/acts_as_authentic/base.rb +40 -26
  17. data/lib/authlogic/acts_as_authentic/email.rb +96 -32
  18. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +36 -12
  19. data/lib/authlogic/acts_as_authentic/login.rb +114 -49
  20. data/lib/authlogic/acts_as_authentic/magic_columns.rb +17 -6
  21. data/lib/authlogic/acts_as_authentic/password.rb +296 -139
  22. data/lib/authlogic/acts_as_authentic/perishable_token.rb +34 -20
  23. data/lib/authlogic/acts_as_authentic/persistence_token.rb +20 -24
  24. data/lib/authlogic/acts_as_authentic/queries/find_with_case.rb +67 -0
  25. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +68 -23
  26. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +128 -85
  27. data/lib/authlogic/acts_as_authentic/single_access_token.rb +41 -25
  28. data/lib/authlogic/acts_as_authentic/validations_scope.rb +8 -8
  29. data/lib/authlogic/authenticates_many/association.rb +22 -14
  30. data/lib/authlogic/authenticates_many/base.rb +35 -16
  31. data/lib/authlogic/config.rb +10 -10
  32. data/lib/authlogic/controller_adapters/abstract_adapter.rb +40 -12
  33. data/lib/authlogic/controller_adapters/rack_adapter.rb +15 -8
  34. data/lib/authlogic/controller_adapters/rails_adapter.rb +42 -22
  35. data/lib/authlogic/controller_adapters/sinatra_adapter.rb +3 -3
  36. data/lib/authlogic/crypto_providers.rb +91 -0
  37. data/lib/authlogic/crypto_providers/aes256.rb +42 -14
  38. data/lib/authlogic/crypto_providers/bcrypt.rb +35 -20
  39. data/lib/authlogic/crypto_providers/md5.rb +11 -9
  40. data/lib/authlogic/crypto_providers/scrypt.rb +26 -13
  41. data/lib/authlogic/crypto_providers/sha1.rb +14 -8
  42. data/lib/authlogic/crypto_providers/sha256.rb +16 -12
  43. data/lib/authlogic/crypto_providers/sha512.rb +8 -24
  44. data/lib/authlogic/crypto_providers/wordpress.rb +44 -15
  45. data/lib/authlogic/i18n.rb +33 -20
  46. data/lib/authlogic/i18n/translator.rb +1 -1
  47. data/lib/authlogic/random.rb +12 -29
  48. data/lib/authlogic/regex.rb +59 -27
  49. data/lib/authlogic/session/activation.rb +36 -23
  50. data/lib/authlogic/session/active_record_trickery.rb +13 -10
  51. data/lib/authlogic/session/base.rb +20 -8
  52. data/lib/authlogic/session/brute_force_protection.rb +87 -56
  53. data/lib/authlogic/session/callbacks.rb +99 -49
  54. data/lib/authlogic/session/cookies.rb +128 -59
  55. data/lib/authlogic/session/existence.rb +29 -19
  56. data/lib/authlogic/session/foundation.rb +70 -16
  57. data/lib/authlogic/session/http_auth.rb +39 -31
  58. data/lib/authlogic/session/id.rb +27 -15
  59. data/lib/authlogic/session/klass.rb +17 -13
  60. data/lib/authlogic/session/magic_columns.rb +78 -59
  61. data/lib/authlogic/session/magic_states.rb +50 -27
  62. data/lib/authlogic/session/params.rb +79 -50
  63. data/lib/authlogic/session/password.rb +197 -118
  64. data/lib/authlogic/session/perishable_token.rb +12 -6
  65. data/lib/authlogic/session/persistence.rb +20 -14
  66. data/lib/authlogic/session/priority_record.rb +20 -16
  67. data/lib/authlogic/session/scopes.rb +63 -33
  68. data/lib/authlogic/session/session.rb +40 -25
  69. data/lib/authlogic/session/timeout.rb +51 -34
  70. data/lib/authlogic/session/unauthorized_record.rb +24 -18
  71. data/lib/authlogic/session/validation.rb +32 -21
  72. data/lib/authlogic/test_case.rb +123 -35
  73. data/lib/authlogic/test_case/mock_controller.rb +14 -13
  74. data/lib/authlogic/test_case/mock_cookie_jar.rb +14 -5
  75. data/lib/authlogic/test_case/mock_logger.rb +1 -1
  76. data/lib/authlogic/test_case/mock_request.rb +9 -4
  77. data/lib/authlogic/test_case/rails_request_adapter.rb +8 -7
  78. data/lib/authlogic/version.rb +21 -0
  79. data/test/acts_as_authentic_test/base_test.rb +1 -1
  80. data/test/acts_as_authentic_test/email_test.rb +80 -63
  81. data/test/acts_as_authentic_test/logged_in_status_test.rb +14 -8
  82. data/test/acts_as_authentic_test/login_test.rb +91 -49
  83. data/test/acts_as_authentic_test/magic_columns_test.rb +13 -13
  84. data/test/acts_as_authentic_test/password_test.rb +82 -60
  85. data/test/acts_as_authentic_test/perishable_token_test.rb +31 -25
  86. data/test/acts_as_authentic_test/persistence_token_test.rb +9 -5
  87. data/test/acts_as_authentic_test/restful_authentication_test.rb +18 -9
  88. data/test/acts_as_authentic_test/session_maintenance_test.rb +86 -22
  89. data/test/acts_as_authentic_test/single_access_test.rb +15 -15
  90. data/test/adapter_test.rb +21 -0
  91. data/test/authenticates_many_test.rb +26 -11
  92. data/test/config_test.rb +9 -9
  93. data/test/crypto_provider_test/aes256_test.rb +3 -3
  94. data/test/crypto_provider_test/bcrypt_test.rb +1 -1
  95. data/test/crypto_provider_test/scrypt_test.rb +2 -2
  96. data/test/crypto_provider_test/sha1_test.rb +4 -4
  97. data/test/crypto_provider_test/sha256_test.rb +2 -2
  98. data/test/crypto_provider_test/sha512_test.rb +3 -3
  99. data/test/crypto_provider_test/wordpress_test.rb +24 -0
  100. data/test/gemfiles/Gemfile.rails-4.2.x +2 -2
  101. data/test/gemfiles/Gemfile.rails-5.0.x +6 -0
  102. data/test/gemfiles/Gemfile.rails-5.1.x +6 -0
  103. data/test/gemfiles/Gemfile.rails-5.2.x +6 -0
  104. data/test/gemfiles/Gemfile.rails-master +6 -0
  105. data/test/i18n_test.rb +9 -9
  106. data/test/libs/affiliate.rb +2 -2
  107. data/test/libs/company.rb +4 -4
  108. data/test/libs/employee.rb +2 -2
  109. data/test/libs/employee_session.rb +1 -1
  110. data/test/libs/ldaper.rb +1 -1
  111. data/test/libs/project.rb +1 -1
  112. data/test/libs/user_session.rb +2 -2
  113. data/test/random_test.rb +9 -38
  114. data/test/session_test/activation_test.rb +7 -7
  115. data/test/session_test/active_record_trickery_test.rb +9 -6
  116. data/test/session_test/brute_force_protection_test.rb +26 -21
  117. data/test/session_test/callbacks_test.rb +10 -4
  118. data/test/session_test/cookies_test.rb +54 -20
  119. data/test/session_test/existence_test.rb +45 -23
  120. data/test/session_test/foundation_test.rb +17 -1
  121. data/test/session_test/http_auth_test.rb +11 -12
  122. data/test/session_test/id_test.rb +3 -3
  123. data/test/session_test/klass_test.rb +2 -2
  124. data/test/session_test/magic_columns_test.rb +15 -17
  125. data/test/session_test/magic_states_test.rb +17 -19
  126. data/test/session_test/params_test.rb +26 -20
  127. data/test/session_test/password_test.rb +11 -12
  128. data/test/session_test/perishability_test.rb +5 -5
  129. data/test/session_test/persistence_test.rb +4 -3
  130. data/test/session_test/scopes_test.rb +15 -9
  131. data/test/session_test/session_test.rb +7 -6
  132. data/test/session_test/timeout_test.rb +16 -14
  133. data/test/session_test/unauthorized_record_test.rb +3 -3
  134. data/test/session_test/validation_test.rb +5 -5
  135. data/test/test_helper.rb +115 -49
  136. metadata +107 -36
  137. data/README.rdoc +0 -232
  138. data/test/gemfiles/Gemfile.rails-3.2.x +0 -7
  139. data/test/gemfiles/Gemfile.rails-4.0.x +0 -7
  140. 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 allows the user to log in using a URL like the following:
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 used for single access only, it is not persisted. Meaning the user
8
- # provides it, Authlogic grants them access, and that's it. If they want access again they need to provide the token again. Authlogic will
9
- # *NEVER* try to persist the session after authenticating through this method.
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 change this with the configuration. You can also define if
12
- # it is allowed dynamically by defining a single_access_allowed? method in your controller. For example:
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 password, this token will remain the same. It will only change
21
- # when it is explicitly reset.
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 params just like a cookie or a session. Your URL would look like:
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 configuration option. Keep in mind, just like cookie_key, if you supply an id
41
- # the id will be appended to the front. Check out cookie_key for more details. Also checkout the "Single Access / Private Feeds Access" section in the README.
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 something you don't want for your application as a whole. Maybe this is
51
- # something you only want for specific request types. Specify a list of allowed request types and single access authentication will only be
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 allow single access authentication for any and all request types
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(:single_access_allowed_request_types, value, ["application/rss+xml", "application/atom+xml"])
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 up the params / single access feature.
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
- def persist_by_params
66
- return false if !params_enabled?
67
- self.unauthorized_record = search_for_record("find_by_single_access_token", params_credentials)
68
- self.single_access = valid?
69
- end
70
-
71
- def params_enabled?
72
- return false if !params_credentials || !klass.column_names.include?("single_access_token")
73
- return controller.single_access_allowed? if controller.responds_to_single_access_allowed?
74
-
75
- case single_access_allowed_request_types
76
- when Array
77
- single_access_allowed_request_types.include?(controller.request_content_type) || single_access_allowed_request_types.include?(:all)
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
- def single_access_allowed_request_types
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
- def params_credentials
96
- controller.params[params_key]
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, :if => :authenticating_with_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 validation is actually finding the user and
20
- # making sure it exists. What method it uses the do this is up to you.
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 default UserSession will call User.find_by_login(login).
23
- # You can change what method UserSession calls by specifying it here. Then in your User model you can make that method do
24
- # anything you want, giving you complete control of how users are found by the UserSession.
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 email. Set this to the name of the class method
27
- # that does this in the User model. Let's call it "find_by_username_or_email"
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 and you are all set. You can do anything you
36
- # want here. Maybe you allow users to have multiple logins and you want to search a has_many relationship, etc. The sky is the limit.
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 when a bad login attempt occurs.
46
- # When you show error messages for a bad login, it's considered good security practice to hide which field
47
- # the user has entered incorrectly (the login field or the password field). For a full explanation, see
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 look identical:
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 that has a hard time remembering
69
- # their username and password combinations. It also disables the ability to to highlight the field
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 (such as a financial application),
73
- # then you should enable this. Otherwise, leaving this off is fine.
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 login / username. Keep in mind this is just for your
83
- # Authlogic::Session, if you want it can be something completely different than the field in your model. So if you wanted people to
84
- # login with a field called "login" and then find users by email this is compeltely doable. See the find_by_login_method configuration
85
- # option for more details.
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 :password if a login_field exists.
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 should be an instance method. It should also
104
- # be prepared to accept a raw password and a crytped password.
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
- if !self.class.configured_password_methods
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 hash form.
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 hash form.
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 = value.is_a?(Array) ? value : [value]
164
+ values = Array.wrap(value)
140
165
  if values.first.is_a?(Hash)
141
- values.first.with_indifferent_access.slice(login_field, password_field).each do |field, value|
142
- next if value.blank?
143
- send("#{field}=", value)
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
- def configure_password_methods
154
- if login_field
155
- self.class.send(:attr_writer, login_field) if !respond_to?("#{login_field}=")
156
- self.class.send(:attr_reader, login_field) if !respond_to?(login_field)
157
- end
158
-
159
- if password_field
160
- self.class.send(:attr_writer, password_field) if !respond_to?("#{password_field}=")
161
- self.class.send(:define_method, password_field) {} if !respond_to?(password_field)
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
- def authenticating_with_password?
175
- login_field && (!send(login_field).nil? || !send("protected_#{password_field}").nil?)
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
- # check for invalid password
196
- if !attempted_record.send(verify_password_method, send("protected_#{password_field}"))
197
- self.invalid_password = true
198
- generalize_credentials_error_messages? ?
199
- add_general_credentials_error :
200
- errors.add(password_field, I18n.t('error_messages.password_invalid', :default => "is not valid"))
201
- return
202
- end
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
- attr_accessor :invalid_password
206
-
207
- def find_by_login_method
208
- self.class.find_by_login_method
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
- def login_field
212
- self.class.login_field
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
- def add_general_credentials_error
216
- error_message =
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
- errors.add(:base, I18n.t('error_messages.general_credentials_error', :default => error_message))
223
- end
224
-
225
- def generalize_credentials_error_messages?
226
- self.class.generalize_credentials_error_messages
227
- end
228
-
229
- def password_field
230
- self.class.password_field
231
- end
232
-
233
- def verify_password_method
234
- self.class.verify_password_method
235
- end
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