authlogic 3.4.6 → 4.2.0

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