authlogic 3.5.0 → 3.8.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.
- data/.github/ISSUE_TEMPLATE.md +13 -0
- data/.rubocop_todo.yml +1 -37
- data/.travis.yml +15 -6
- data/CHANGELOG.md +2 -130
- data/CONTRIBUTING.md +13 -2
- data/README.md +2 -3
- data/authlogic.gemspec +4 -5
- data/lib/authlogic/acts_as_authentic/base.rb +4 -2
- data/lib/authlogic/acts_as_authentic/email.rb +8 -3
- data/lib/authlogic/acts_as_authentic/logged_in_status.rb +21 -3
- data/lib/authlogic/acts_as_authentic/login.rb +44 -25
- data/lib/authlogic/acts_as_authentic/password.rb +28 -12
- data/lib/authlogic/acts_as_authentic/perishable_token.rb +21 -12
- data/lib/authlogic/acts_as_authentic/restful_authentication.rb +16 -9
- data/lib/authlogic/acts_as_authentic/session_maintenance.rb +5 -3
- data/lib/authlogic/authenticates_many/association.rb +11 -4
- data/lib/authlogic/authenticates_many/base.rb +5 -4
- data/lib/authlogic/controller_adapters/rack_adapter.rb +6 -2
- data/lib/authlogic/controller_adapters/rails_adapter.rb +11 -8
- data/lib/authlogic/crypto_providers/aes256.rb +21 -2
- data/lib/authlogic/crypto_providers/bcrypt.rb +4 -1
- data/lib/authlogic/crypto_providers/sha512.rb +15 -10
- data/lib/authlogic/regex.rb +7 -6
- data/lib/authlogic/session/activation.rb +19 -10
- data/lib/authlogic/session/cookies.rb +3 -1
- data/lib/authlogic/session/id.rb +13 -7
- data/lib/authlogic/session/magic_columns.rb +19 -10
- data/lib/authlogic/session/magic_states.rb +7 -1
- data/lib/authlogic/session/password.rb +82 -35
- data/lib/authlogic/session/perishable_token.rb +7 -3
- data/lib/authlogic/session/validation.rb +13 -11
- data/lib/authlogic/test_case.rb +52 -32
- data/lib/authlogic.rb +6 -0
- data/test/acts_as_authentic_test/email_test.rb +33 -27
- data/test/acts_as_authentic_test/logged_in_status_test.rb +2 -2
- data/test/acts_as_authentic_test/login_test.rb +50 -37
- data/test/acts_as_authentic_test/magic_columns_test.rb +8 -8
- data/test/acts_as_authentic_test/password_test.rb +14 -14
- data/test/acts_as_authentic_test/perishable_token_test.rb +5 -5
- data/test/acts_as_authentic_test/persistence_token_test.rb +4 -4
- data/test/acts_as_authentic_test/restful_authentication_test.rb +6 -6
- data/test/acts_as_authentic_test/session_maintenance_test.rb +15 -10
- data/test/acts_as_authentic_test/single_access_test.rb +6 -6
- data/test/authenticates_many_test.rb +21 -6
- data/test/gemfiles/Gemfile.rails-5.1.x +6 -0
- data/test/gemfiles/Gemfile.rails-5.2.x +6 -0
- data/test/libs/company.rb +1 -1
- data/test/session_test/activation_test.rb +1 -1
- data/test/session_test/active_record_trickery_test.rb +3 -3
- data/test/session_test/brute_force_protection_test.rb +19 -14
- data/test/session_test/cookies_test.rb +21 -12
- data/test/session_test/existence_test.rb +15 -10
- data/test/session_test/http_auth_test.rb +2 -2
- data/test/session_test/magic_columns_test.rb +7 -4
- data/test/session_test/magic_states_test.rb +7 -9
- data/test/session_test/params_test.rb +6 -6
- data/test/session_test/password_test.rb +2 -2
- data/test/session_test/perishability_test.rb +1 -1
- data/test/session_test/persistence_test.rb +2 -2
- data/test/session_test/timeout_test.rb +7 -5
- data/test/session_test/validation_test.rb +1 -1
- data/test/test_helper.rb +37 -6
- metadata +57 -36
- checksums.yaml +0 -7
@@ -16,16 +16,19 @@ module Authlogic
|
|
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
|
-
# Set this to the name of the class method that does this in the
|
28
|
-
# 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"
|
29
32
|
#
|
30
33
|
# class User < ActiveRecord::Base
|
31
34
|
# def self.find_by_username_or_email(login)
|
@@ -33,10 +36,10 @@ module Authlogic
|
|
33
36
|
# end
|
34
37
|
# end
|
35
38
|
#
|
36
|
-
# Now just specify the name of this method for this configuration option
|
37
|
-
# are all set. You can do anything you want here. Maybe you
|
38
|
-
# multiple logins and you want to search a has_many
|
39
|
-
# 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.
|
40
43
|
#
|
41
44
|
# * <tt>Default:</tt> "find_by_smart_case_login_field"
|
42
45
|
# * <tt>Accepts:</tt> Symbol or String
|
@@ -45,10 +48,11 @@ module Authlogic
|
|
45
48
|
end
|
46
49
|
alias_method :find_by_login_method=, :find_by_login_method
|
47
50
|
|
48
|
-
# The text used to identify credentials (username/password) combination
|
49
|
-
# login attempt occurs. When you show error messages for a
|
50
|
-
# considered good security practice to hide which field
|
51
|
-
# incorrectly (the login field or the password
|
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
|
52
56
|
# http://www.gnucitizen.org/blog/username-enumeration-vulnerabilities/
|
53
57
|
#
|
54
58
|
# Example of use:
|
@@ -57,7 +61,8 @@ module Authlogic
|
|
57
61
|
# generalize_credentials_error_messages true
|
58
62
|
# end
|
59
63
|
#
|
60
|
-
# 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:
|
61
66
|
#
|
62
67
|
# Login/Password combination is not valid
|
63
68
|
#
|
@@ -69,12 +74,14 @@ module Authlogic
|
|
69
74
|
#
|
70
75
|
# This will instead show your custom error message when the UserSession is invalid.
|
71
76
|
#
|
72
|
-
# The downside to enabling this is that is can be too vague for a user
|
73
|
-
#
|
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
|
74
80
|
# with the error when you use form_for.
|
75
81
|
#
|
76
|
-
# If you are developing an app where security is an extreme priority
|
77
|
-
#
|
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.
|
78
85
|
#
|
79
86
|
# * <tt>Default</tt> false
|
80
87
|
# * <tt>Accepts:</tt> Boolean
|
@@ -83,12 +90,13 @@ module Authlogic
|
|
83
90
|
end
|
84
91
|
alias_method :generalize_credentials_error_messages=, :generalize_credentials_error_messages
|
85
92
|
|
86
|
-
# The name of the method you want Authlogic to create for storing the
|
87
|
-
# username. Keep in mind this is just for your
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
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.
|
92
100
|
#
|
93
101
|
# * <tt>Default:</tt> klass.login_field || klass.email_field
|
94
102
|
# * <tt>Accepts:</tt> Symbol or String
|
@@ -97,7 +105,8 @@ module Authlogic
|
|
97
105
|
end
|
98
106
|
alias_method :login_field=, :login_field
|
99
107
|
|
100
|
-
# Works exactly like login_field, but for the password instead. Returns
|
108
|
+
# Works exactly like login_field, but for the password instead. Returns
|
109
|
+
# :password if a login_field exists.
|
101
110
|
#
|
102
111
|
# * <tt>Default:</tt> :password
|
103
112
|
# * <tt>Accepts:</tt> Symbol or String
|
@@ -106,8 +115,9 @@ module Authlogic
|
|
106
115
|
end
|
107
116
|
alias_method :password_field=, :password_field
|
108
117
|
|
109
|
-
# The name of the method in your model used to verify the password. This
|
110
|
-
# be
|
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.
|
111
121
|
#
|
112
122
|
# * <tt>Default:</tt> "valid_password?"
|
113
123
|
# * <tt>Accepts:</tt> Symbol or String
|
@@ -117,8 +127,40 @@ module Authlogic
|
|
117
127
|
alias_method :verify_password_method=, :verify_password_method
|
118
128
|
end
|
119
129
|
|
120
|
-
# Password
|
130
|
+
# Password-related instance methods
|
121
131
|
module InstanceMethods
|
132
|
+
E_AC_PARAMETERS = <<-STR.strip_heredoc.freeze
|
133
|
+
You have passed an ActionController::Parameters to Authlogic 3. That's
|
134
|
+
OK for now, but in Authlogic 4, it will raise an error. Please
|
135
|
+
replace:
|
136
|
+
|
137
|
+
UserSession.new(user_session_params)
|
138
|
+
UserSession.create(user_session_params)
|
139
|
+
|
140
|
+
with
|
141
|
+
|
142
|
+
UserSession.new(user_session_params.to_h)
|
143
|
+
UserSession.create(user_session_params.to_h)
|
144
|
+
|
145
|
+
And don't forget to `permit`!
|
146
|
+
|
147
|
+
During the transition of rails to Strong Parameters, it has been
|
148
|
+
common for Authlogic users to forget to `permit` their params. They
|
149
|
+
would pass their params into Authlogic, we'd call `to_h`, and they'd
|
150
|
+
be surprised when authentication failed.
|
151
|
+
|
152
|
+
In 2018, people are still making this mistake. We'd like to help them
|
153
|
+
and make authlogic a little simpler at the same time, so in Authlogic
|
154
|
+
3.7.0, we deprecated the use of ActionController::Parameters.
|
155
|
+
|
156
|
+
We discussed this issue thoroughly between late 2016 and early
|
157
|
+
2018. Notable discussions include:
|
158
|
+
|
159
|
+
- https://github.com/binarylogic/authlogic/issues/512
|
160
|
+
- https://github.com/binarylogic/authlogic/pull/558
|
161
|
+
- https://github.com/binarylogic/authlogic/pull/577
|
162
|
+
STR
|
163
|
+
|
122
164
|
def initialize(*args)
|
123
165
|
if !self.class.configured_password_methods
|
124
166
|
configure_password_methods
|
@@ -127,7 +169,8 @@ module Authlogic
|
|
127
169
|
super
|
128
170
|
end
|
129
171
|
|
130
|
-
# Returns the login_field / password_field credentials combination in
|
172
|
+
# Returns the login_field / password_field credentials combination in
|
173
|
+
# hash form.
|
131
174
|
def credentials
|
132
175
|
if authenticating_with_password?
|
133
176
|
details = {}
|
@@ -139,7 +182,8 @@ module Authlogic
|
|
139
182
|
end
|
140
183
|
end
|
141
184
|
|
142
|
-
# Accepts the login_field / password_field credentials combination in
|
185
|
+
# Accepts the login_field / password_field credentials combination in
|
186
|
+
# hash form.
|
143
187
|
def credentials=(value)
|
144
188
|
super
|
145
189
|
values = parse_param_val(value) # add strong parameters check
|
@@ -168,10 +212,12 @@ module Authlogic
|
|
168
212
|
self.class.send(:attr_writer, password_field) if !respond_to?("#{password_field}=")
|
169
213
|
self.class.send(:define_method, password_field) {} if !respond_to?(password_field)
|
170
214
|
|
215
|
+
# The password should not be accessible publicly. This way forms
|
216
|
+
# using form_for don't fill the password with the attempted
|
217
|
+
# password. To prevent this we just create this method that is
|
218
|
+
# private.
|
171
219
|
self.class.class_eval <<-"end_eval", __FILE__, __LINE__
|
172
220
|
private
|
173
|
-
# The password should not be accessible publicly. This way forms using form_for don't fill the password with the
|
174
|
-
# attempted password. To prevent this we just create this method that is private.
|
175
221
|
def protected_#{password_field}
|
176
222
|
@#{password_field}
|
177
223
|
end
|
@@ -250,6 +296,7 @@ module Authlogic
|
|
250
296
|
# This method converts the ActionController::Parameters to a Hash
|
251
297
|
def parse_param_val(value)
|
252
298
|
if value.first.class.name == "ActionController::Parameters"
|
299
|
+
ActiveSupport::Deprecation.warn(E_AC_PARAMETERS)
|
253
300
|
[value.first.to_h]
|
254
301
|
else
|
255
302
|
value.is_a?(Array) ? value : [value]
|
@@ -1,7 +1,9 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session
|
3
|
-
# Maintains the perishable token, which is helpful for confirming records or
|
4
|
-
#
|
3
|
+
# Maintains the perishable token, which is helpful for confirming records or
|
4
|
+
# authorizing records to reset their password. All that this module does is
|
5
|
+
# reset it after a session have been saved, just keep it changing. The more
|
6
|
+
# it changes, the tighter the security.
|
5
7
|
#
|
6
8
|
# See Authlogic::ActsAsAuthentic::PerishableToken for more information.
|
7
9
|
module PerishableToken
|
@@ -12,7 +14,9 @@ module Authlogic
|
|
12
14
|
private
|
13
15
|
|
14
16
|
def reset_perishable_token!
|
15
|
-
|
17
|
+
if record.respond_to?(:reset_perishable_token) && !record.disable_perishable_token_maintenance?
|
18
|
+
record.reset_perishable_token
|
19
|
+
end
|
16
20
|
end
|
17
21
|
end
|
18
22
|
end
|
@@ -2,7 +2,8 @@ module Authlogic
|
|
2
2
|
module Session
|
3
3
|
# Responsible for session validation
|
4
4
|
module Validation
|
5
|
-
# The errors in Authlogic work JUST LIKE ActiveRecord. In fact, it uses
|
5
|
+
# The errors in Authlogic work JUST LIKE ActiveRecord. In fact, it uses
|
6
|
+
# the exact same ActiveRecord errors class. Use it the same way:
|
6
7
|
#
|
7
8
|
# class UserSession
|
8
9
|
# validate :check_if_awesome
|
@@ -22,9 +23,10 @@ module Authlogic
|
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
25
|
-
# You should use this as a place holder for any records that you find
|
26
|
-
#
|
27
|
-
# the
|
26
|
+
# You should use this as a place holder for any records that you find
|
27
|
+
# during validation. The main reason for this is to allow other modules to
|
28
|
+
# use it if needed. Take the failed_login_count feature, it needs this in
|
29
|
+
# order to increase the failed login count.
|
28
30
|
def attempted_record
|
29
31
|
@attempted_record
|
30
32
|
end
|
@@ -34,8 +36,8 @@ module Authlogic
|
|
34
36
|
@attempted_record = value
|
35
37
|
end
|
36
38
|
|
37
|
-
# The errors in Authlogic work JUST LIKE ActiveRecord. In fact, it uses
|
38
|
-
# Use it the same way:
|
39
|
+
# The errors in Authlogic work JUST LIKE ActiveRecord. In fact, it uses
|
40
|
+
# the exact same ActiveRecord errors class. Use it the same way:
|
39
41
|
#
|
40
42
|
# === Example
|
41
43
|
#
|
@@ -52,9 +54,9 @@ module Authlogic
|
|
52
54
|
@errors ||= Errors.new(self)
|
53
55
|
end
|
54
56
|
|
55
|
-
# Determines if the information you provided for authentication is valid
|
56
|
-
# a problem with the information provided errors will
|
57
|
-
# method will return false.
|
57
|
+
# Determines if the information you provided for authentication is valid
|
58
|
+
# or not. If there is a problem with the information provided errors will
|
59
|
+
# be added to the errors object and this method will return false.
|
58
60
|
def valid?
|
59
61
|
errors.clear
|
60
62
|
self.attempted_record = nil
|
@@ -64,13 +66,13 @@ module Authlogic
|
|
64
66
|
validate
|
65
67
|
ensure_authentication_attempted
|
66
68
|
|
67
|
-
if errors.
|
69
|
+
if errors.empty?
|
68
70
|
new_session? ? after_validation_on_create : after_validation_on_update
|
69
71
|
after_validation
|
70
72
|
end
|
71
73
|
|
72
74
|
save_record(attempted_record)
|
73
|
-
errors.
|
75
|
+
errors.empty?
|
74
76
|
end
|
75
77
|
|
76
78
|
private
|
data/lib/authlogic/test_case.rb
CHANGED
@@ -5,8 +5,9 @@ require File.dirname(__FILE__) + "/test_case/mock_logger"
|
|
5
5
|
require File.dirname(__FILE__) + "/test_case/mock_request"
|
6
6
|
|
7
7
|
module Authlogic
|
8
|
-
# This module is a collection of methods and classes that help you easily test
|
9
|
-
# I use these same tools to test the internals of
|
8
|
+
# This module is a collection of methods and classes that help you easily test
|
9
|
+
# Authlogic. In fact, I use these same tools to test the internals of
|
10
|
+
# Authlogic.
|
10
11
|
#
|
11
12
|
# === The quick and dirty
|
12
13
|
#
|
@@ -18,26 +19,33 @@ module Authlogic
|
|
18
19
|
#
|
19
20
|
# === Setting up
|
20
21
|
#
|
21
|
-
# Authlogic comes with some simple testing tools. To get these, you need to
|
22
|
-
# you are doing this in a rails app,
|
22
|
+
# Authlogic comes with some simple testing tools. To get these, you need to
|
23
|
+
# first require Authlogic's TestCase. If you are doing this in a rails app,
|
24
|
+
# you would require this file at the top of your test_helper.rb file:
|
23
25
|
#
|
24
26
|
# require "authlogic/test_case"
|
25
27
|
#
|
26
|
-
# If you are using Test::Unit::TestCase, the standard testing library that
|
27
|
-
#
|
28
|
+
# If you are using Test::Unit::TestCase, the standard testing library that
|
29
|
+
# comes with ruby, then you can skip this next part. If you are not, you need
|
30
|
+
# to include the Authlogic::TestCase into your testing suite as follows:
|
28
31
|
#
|
29
32
|
# include Authlogic::TestCase
|
30
33
|
#
|
31
|
-
# Now that everything is ready to go, let's move onto actually testing. Here
|
34
|
+
# Now that everything is ready to go, let's move onto actually testing. Here
|
35
|
+
# is the basic idea behind testing:
|
32
36
|
#
|
33
|
-
# Authlogic requires a "connection" to your controller to activate it. In the
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
+
# Authlogic requires a "connection" to your controller to activate it. In the
|
38
|
+
# same manner that ActiveRecord requires a connection to your database. It
|
39
|
+
# can't do anything until it gets connected. That being said, Authlogic will
|
40
|
+
# raise an Authlogic::Session::Activation::NotActivatedError any time you try
|
41
|
+
# to instantiate an object without a "connection". So before you do anything
|
42
|
+
# with Authlogic, you need to activate / connect Authlogic. Let's walk through
|
43
|
+
# how to do this in tests:
|
37
44
|
#
|
38
45
|
# === Fixtures / Factories
|
39
46
|
#
|
40
|
-
# Creating users via fixtures / factories is easy. Here's an example of a
|
47
|
+
# Creating users via fixtures / factories is easy. Here's an example of a
|
48
|
+
# fixture:
|
41
49
|
#
|
42
50
|
# ben:
|
43
51
|
# email: whatever@whatever.com
|
@@ -47,43 +55,52 @@ module Authlogic
|
|
47
55
|
# single_access_token: <%= Authlogic::Random.friendly_token %>
|
48
56
|
# perishable_token: <%= Authlogic::Random.friendly_token %>
|
49
57
|
#
|
50
|
-
# Notice the crypted_password value. Just supplement that with whatever crypto
|
58
|
+
# Notice the crypted_password value. Just supplement that with whatever crypto
|
59
|
+
# provider you are using, if you are not using the default.
|
51
60
|
#
|
52
61
|
# === Functional tests
|
53
62
|
#
|
54
|
-
# Activating Authlogic isn't a problem here, because making a request will
|
55
|
-
#
|
63
|
+
# Activating Authlogic isn't a problem here, because making a request will
|
64
|
+
# activate Authlogic for you. The problem is logging users in so they can
|
65
|
+
# access restricted areas. Solving this is simple, just do this:
|
56
66
|
#
|
57
67
|
# setup :activate_authlogic
|
58
68
|
#
|
59
|
-
# For those of you unfamiliar with TestUnit, the setup method basically just
|
60
|
-
# It is essentially "setting up"
|
69
|
+
# For those of you unfamiliar with TestUnit, the setup method basically just
|
70
|
+
# executes a method before any test is ran. It is essentially "setting up"
|
71
|
+
# your tests.
|
61
72
|
#
|
62
73
|
# Once you have done this, just log users in like usual:
|
63
74
|
#
|
64
75
|
# UserSession.create(users(:whomever))
|
65
76
|
# # access my restricted area here
|
66
77
|
#
|
67
|
-
# Do this before you make your request and it will act as if that user is
|
78
|
+
# Do this before you make your request and it will act as if that user is
|
79
|
+
# logged in.
|
68
80
|
#
|
69
81
|
# === Integration tests
|
70
82
|
#
|
71
|
-
# Again, just like functional tests, you don't have to do anything. As soon as
|
72
|
-
#
|
83
|
+
# Again, just like functional tests, you don't have to do anything. As soon as
|
84
|
+
# you make a request, Authlogic will be connected. If you want to activate
|
85
|
+
# Authlogic before making a request follow the same steps described in the
|
73
86
|
# "functional tests" section above. It works in the same manner.
|
74
87
|
#
|
75
88
|
# === Unit tests
|
76
89
|
#
|
77
|
-
# The only time you need to do any trickiness here is if you want to test
|
78
|
-
#
|
90
|
+
# The only time you need to do any trickiness here is if you want to test
|
91
|
+
# Authlogic models. Maybe you added some custom code or methods in your
|
92
|
+
# Authlogic models. Maybe you are writing a plugin or a library that extends
|
93
|
+
# Authlogic.
|
79
94
|
#
|
80
|
-
# That being said, in this environment there is no controller. So you need to
|
81
|
-
# that looks like a controller, acts like a
|
82
|
-
#
|
83
|
-
#
|
95
|
+
# That being said, in this environment there is no controller. So you need to
|
96
|
+
# use a "mock" controller. Something that looks like a controller, acts like a
|
97
|
+
# controller, but isn't a "real" controller. You are essentially connecting
|
98
|
+
# Authlogic to your "mock" controller, then you can test off of the mock
|
99
|
+
# controller to make sure everything is functioning properly.
|
84
100
|
#
|
85
|
-
# I use a mock controller to test Authlogic myself. It's part of the Authlogic
|
86
|
-
#
|
101
|
+
# I use a mock controller to test Authlogic myself. It's part of the Authlogic
|
102
|
+
# library that you can easily use. It's as simple as functional and
|
103
|
+
# integration tests. Just do the following:
|
87
104
|
#
|
88
105
|
# setup :activate_authlogic
|
89
106
|
#
|
@@ -94,9 +111,11 @@ module Authlogic
|
|
94
111
|
# assert UserSession.create(ben)
|
95
112
|
# assert_equal controller.session["user_credentials"], ben.persistence_token
|
96
113
|
#
|
97
|
-
# See how I am checking that Authlogic is interacting with the controller
|
114
|
+
# See how I am checking that Authlogic is interacting with the controller
|
115
|
+
# properly? That's the idea here.
|
98
116
|
module TestCase
|
99
|
-
# Activates authlogic so that you can use it in your tests. You should call
|
117
|
+
# Activates authlogic so that you can use it in your tests. You should call
|
118
|
+
# this method in your test's setup. Ex:
|
100
119
|
#
|
101
120
|
# setup :activate_authlogic
|
102
121
|
def activate_authlogic
|
@@ -109,8 +128,9 @@ module Authlogic
|
|
109
128
|
Authlogic::Session::Base.controller = (@request && Authlogic::TestCase::RailsRequestAdapter.new(@request)) || controller
|
110
129
|
end
|
111
130
|
|
112
|
-
# The Authlogic::TestCase::MockController object passed to Authlogic to
|
113
|
-
# See the module description
|
131
|
+
# The Authlogic::TestCase::MockController object passed to Authlogic to
|
132
|
+
# activate it. You can access this in your test. See the module description
|
133
|
+
# for an example.
|
114
134
|
def controller
|
115
135
|
@controller ||= Authlogic::TestCase::MockController.new
|
116
136
|
end
|
data/lib/authlogic.rb
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# Authlogic uses ActiveSupport's core extensions like `strip_heredoc`, which
|
2
|
+
# ActiveRecord does not `require`. It's possible that we could save a few
|
3
|
+
# milliseconds by loading only the specific core extensions we need, but
|
4
|
+
# `all.rb` is simpler. We can revisit this decision if it becomes a problem.
|
5
|
+
require "active_support/all"
|
6
|
+
|
1
7
|
require "active_record"
|
2
8
|
|
3
9
|
path = File.dirname(__FILE__) + "/authlogic/"
|
@@ -9,6 +9,7 @@ module ActsAsAuthenticTest
|
|
9
9
|
"dakota.dux+1@gmail.com",
|
10
10
|
"dakota.d'ux@gmail.com",
|
11
11
|
"a&b@c.com",
|
12
|
+
"someuser@somedomain.travelersinsurance"
|
12
13
|
]
|
13
14
|
|
14
15
|
BAD_ASCII_EMAILS = [
|
@@ -17,6 +18,7 @@ module ActsAsAuthenticTest
|
|
17
18
|
"question?mark@gmail.com",
|
18
19
|
"backslash@g\\mail.com",
|
19
20
|
"<script>alert(123);</script>\nnobody@example.com",
|
21
|
+
"someuser@somedomain.isreallytoolongandimeanreallytoolong"
|
20
22
|
]
|
21
23
|
|
22
24
|
# http://en.wikipedia.org/wiki/ISO/IEC_8859-1#Codepage_layout
|
@@ -58,7 +60,7 @@ module ActsAsAuthenticTest
|
|
58
60
|
"我>.香港", # greater than
|
59
61
|
"我?本@屋企.香港", # question mark
|
60
62
|
"чебурша@ьн\\ами.рф", # backslash
|
61
|
-
"user@domain.com%0A<script>alert('hello')</script>"
|
63
|
+
"user@domain.com%0A<script>alert('hello')</script>"
|
62
64
|
]
|
63
65
|
|
64
66
|
def test_email_field_config
|
@@ -76,7 +78,7 @@ module ActsAsAuthenticTest
|
|
76
78
|
assert Employee.validate_email_field
|
77
79
|
|
78
80
|
User.validate_email_field = false
|
79
|
-
|
81
|
+
refute User.validate_email_field
|
80
82
|
User.validate_email_field true
|
81
83
|
assert User.validate_email_field
|
82
84
|
end
|
@@ -94,25 +96,25 @@ module ActsAsAuthenticTest
|
|
94
96
|
def test_validates_format_of_email_field_options_config
|
95
97
|
default = {
|
96
98
|
:with => Authlogic::Regex.email,
|
97
|
-
:message =>
|
99
|
+
:message => proc do
|
98
100
|
I18n.t(
|
99
101
|
'error_messages.email_invalid',
|
100
102
|
:default => "should look like an email address."
|
101
103
|
)
|
102
104
|
end
|
103
105
|
}
|
104
|
-
|
106
|
+
default_message = default.delete(:message).call
|
105
107
|
|
106
108
|
options = User.validates_format_of_email_field_options
|
107
109
|
message = options.delete(:message)
|
108
|
-
assert message.
|
109
|
-
assert_equal
|
110
|
+
assert message.is_a?(Proc)
|
111
|
+
assert_equal default_message, message.call
|
110
112
|
assert_equal default, options
|
111
113
|
|
112
114
|
options = Employee.validates_format_of_email_field_options
|
113
115
|
message = options.delete(:message)
|
114
|
-
assert message.
|
115
|
-
assert_equal
|
116
|
+
assert message.is_a?(Proc)
|
117
|
+
assert_equal default_message, message.call
|
116
118
|
assert_equal default, options
|
117
119
|
|
118
120
|
User.validates_format_of_email_field_options = { :yes => "no" }
|
@@ -155,7 +157,11 @@ module ActsAsAuthenticTest
|
|
155
157
|
end
|
156
158
|
|
157
159
|
def test_validates_uniqueness_of_email_field_options_config
|
158
|
-
default = {
|
160
|
+
default = {
|
161
|
+
:case_sensitive => false,
|
162
|
+
:scope => Employee.validations_scope,
|
163
|
+
:if => "#{Employee.email_field}_changed?".to_sym
|
164
|
+
}
|
159
165
|
assert_equal default, Employee.validates_uniqueness_of_email_field_options
|
160
166
|
|
161
167
|
Employee.validates_uniqueness_of_email_field_options = { :yes => "no" }
|
@@ -167,43 +173,43 @@ module ActsAsAuthenticTest
|
|
167
173
|
def test_validates_length_of_email_field
|
168
174
|
u = User.new
|
169
175
|
u.email = "a@a.a"
|
170
|
-
|
171
|
-
|
176
|
+
refute u.valid?
|
177
|
+
refute u.errors[:email].empty?
|
172
178
|
|
173
179
|
u.email = "a@a.com"
|
174
|
-
|
175
|
-
assert u.errors[:email].
|
180
|
+
refute u.valid?
|
181
|
+
assert u.errors[:email].empty?
|
176
182
|
end
|
177
183
|
|
178
184
|
def test_validates_format_of_email_field
|
179
185
|
u = User.new
|
180
186
|
u.email = "aaaaaaaaaaaaa"
|
181
187
|
u.valid?
|
182
|
-
|
188
|
+
refute u.errors[:email].empty?
|
183
189
|
|
184
190
|
u.email = "a@a.com"
|
185
191
|
u.valid?
|
186
|
-
assert u.errors[:email].
|
192
|
+
assert u.errors[:email].empty?
|
187
193
|
|
188
194
|
u.email = "damien+test1...etc..@mydomain.com"
|
189
195
|
u.valid?
|
190
|
-
assert u.errors[:email].
|
196
|
+
assert u.errors[:email].empty?
|
191
197
|
|
192
198
|
u.email = "dakota.dux+1@gmail.com"
|
193
199
|
u.valid?
|
194
|
-
assert u.errors[:email].
|
200
|
+
assert u.errors[:email].empty?
|
195
201
|
|
196
202
|
u.email = "dakota.d'ux@gmail.com"
|
197
203
|
u.valid?
|
198
|
-
assert u.errors[:email].
|
204
|
+
assert u.errors[:email].empty?
|
199
205
|
|
200
206
|
u.email = "<script>alert(123);</script>\nnobody@example.com"
|
201
|
-
|
202
|
-
|
207
|
+
refute u.valid?
|
208
|
+
refute u.errors[:email].empty?
|
203
209
|
|
204
210
|
u.email = "a&b@c.com"
|
205
211
|
u.valid?
|
206
|
-
assert u.errors[:email].
|
212
|
+
assert u.errors[:email].empty?
|
207
213
|
end
|
208
214
|
|
209
215
|
def test_validates_format_of_nonascii_email_field
|
@@ -219,16 +225,16 @@ module ActsAsAuthenticTest
|
|
219
225
|
def test_validates_uniqueness_of_email_field
|
220
226
|
u = User.new
|
221
227
|
u.email = "bjohnson@binarylogic.com"
|
222
|
-
|
223
|
-
|
228
|
+
refute u.valid?
|
229
|
+
refute u.errors[:email].empty?
|
224
230
|
|
225
231
|
u.email = "BJOHNSON@binarylogic.com"
|
226
|
-
|
227
|
-
|
232
|
+
refute u.valid?
|
233
|
+
refute u.errors[:email].empty?
|
228
234
|
|
229
235
|
u.email = "a@a.com"
|
230
|
-
|
231
|
-
assert u.errors[:email].
|
236
|
+
refute u.valid?
|
237
|
+
assert u.errors[:email].empty?
|
232
238
|
end
|
233
239
|
end
|
234
240
|
end
|
@@ -52,11 +52,11 @@ module ActsAsAuthenticTest
|
|
52
52
|
|
53
53
|
def test_logged_in_logged_out
|
54
54
|
u = User.first
|
55
|
-
|
55
|
+
refute u.logged_in?
|
56
56
|
assert u.logged_out?
|
57
57
|
u.last_request_at = Time.now
|
58
58
|
assert u.logged_in?
|
59
|
-
|
59
|
+
refute u.logged_out?
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|