authlogic 3.4.6 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +33 -0
- data/.rubocop_todo.yml +427 -0
- data/.travis.yml +24 -3
- data/CHANGELOG.md +9 -2
- data/CONTRIBUTING.md +40 -1
- data/Gemfile +1 -1
- data/README.md +295 -0
- data/Rakefile +10 -2
- data/authlogic.gemspec +6 -5
- data/lib/authlogic.rb +2 -2
- data/lib/authlogic/acts_as_authentic/base.rb +2 -2
- data/lib/authlogic/acts_as_authentic/email.rb +59 -14
- data/lib/authlogic/acts_as_authentic/logged_in_status.rb +4 -3
- data/lib/authlogic/acts_as_authentic/login.rb +62 -12
- data/lib/authlogic/acts_as_authentic/magic_columns.rb +17 -6
- data/lib/authlogic/acts_as_authentic/password.rb +107 -53
- data/lib/authlogic/acts_as_authentic/persistence_token.rb +10 -9
- data/lib/authlogic/acts_as_authentic/restful_authentication.rb +2 -0
- data/lib/authlogic/acts_as_authentic/session_maintenance.rb +48 -35
- data/lib/authlogic/acts_as_authentic/single_access_token.rb +19 -15
- data/lib/authlogic/acts_as_authentic/validations_scope.rb +2 -2
- data/lib/authlogic/authenticates_many/association.rb +6 -5
- data/lib/authlogic/authenticates_many/base.rb +22 -12
- data/lib/authlogic/config.rb +2 -1
- data/lib/authlogic/controller_adapters/abstract_adapter.rb +2 -1
- data/lib/authlogic/controller_adapters/rack_adapter.rb +3 -4
- data/lib/authlogic/controller_adapters/rails_adapter.rb +26 -14
- data/lib/authlogic/controller_adapters/sinatra_adapter.rb +1 -1
- data/lib/authlogic/crypto_providers/aes256.rb +16 -12
- data/lib/authlogic/crypto_providers/bcrypt.rb +10 -4
- data/lib/authlogic/crypto_providers/md5.rb +7 -7
- data/lib/authlogic/crypto_providers/scrypt.rb +10 -2
- data/lib/authlogic/crypto_providers/sha1.rb +3 -3
- data/lib/authlogic/crypto_providers/sha256.rb +3 -3
- data/lib/authlogic/crypto_providers/sha512.rb +4 -4
- data/lib/authlogic/crypto_providers/wordpress.rb +13 -13
- data/lib/authlogic/i18n.rb +22 -16
- data/lib/authlogic/i18n/translator.rb +1 -1
- data/lib/authlogic/random.rb +13 -12
- data/lib/authlogic/regex.rb +3 -3
- data/lib/authlogic/session/activation.rb +7 -6
- data/lib/authlogic/session/active_record_trickery.rb +1 -2
- data/lib/authlogic/session/base.rb +7 -6
- data/lib/authlogic/session/brute_force_protection.rb +58 -34
- data/lib/authlogic/session/callbacks.rb +16 -12
- data/lib/authlogic/session/cookies.rb +29 -14
- data/lib/authlogic/session/existence.rb +10 -10
- data/lib/authlogic/session/foundation.rb +11 -7
- data/lib/authlogic/session/http_auth.rb +6 -5
- data/lib/authlogic/session/id.rb +5 -4
- data/lib/authlogic/session/klass.rb +2 -1
- data/lib/authlogic/session/magic_columns.rb +21 -14
- data/lib/authlogic/session/magic_states.rb +25 -14
- data/lib/authlogic/session/params.rb +41 -26
- data/lib/authlogic/session/password.rb +62 -40
- data/lib/authlogic/session/perishable_token.rb +3 -2
- data/lib/authlogic/session/persistence.rb +3 -3
- data/lib/authlogic/session/priority_record.rb +5 -4
- data/lib/authlogic/session/scopes.rb +20 -9
- data/lib/authlogic/session/session.rb +9 -4
- data/lib/authlogic/session/timeout.rb +40 -23
- data/lib/authlogic/session/unauthorized_record.rb +6 -5
- data/lib/authlogic/session/validation.rb +18 -9
- data/lib/authlogic/test_case.rb +2 -2
- data/lib/authlogic/test_case/mock_controller.rb +9 -9
- data/lib/authlogic/test_case/mock_cookie_jar.rb +2 -2
- data/lib/authlogic/test_case/mock_logger.rb +1 -1
- data/lib/authlogic/test_case/mock_request.rb +2 -1
- data/lib/authlogic/test_case/rails_request_adapter.rb +5 -5
- data/test/acts_as_authentic_test/email_test.rb +29 -17
- data/test/acts_as_authentic_test/logged_in_status_test.rb +9 -3
- data/test/acts_as_authentic_test/login_test.rb +47 -13
- data/test/acts_as_authentic_test/magic_columns_test.rb +4 -4
- data/test/acts_as_authentic_test/password_test.rb +31 -21
- data/test/acts_as_authentic_test/perishable_token_test.rb +15 -15
- data/test/acts_as_authentic_test/session_maintenance_test.rb +20 -13
- data/test/acts_as_authentic_test/single_access_test.rb +8 -8
- data/test/authenticates_many_test.rb +4 -4
- data/test/crypto_provider_test/aes256_test.rb +2 -2
- data/test/crypto_provider_test/scrypt_test.rb +1 -1
- data/test/crypto_provider_test/sha1_test.rb +3 -3
- data/test/crypto_provider_test/sha256_test.rb +1 -1
- data/test/crypto_provider_test/sha512_test.rb +2 -2
- data/test/gemfiles/Gemfile.rails-3.2.x +2 -2
- data/test/gemfiles/Gemfile.rails-5.0.x +6 -0
- data/test/i18n_test.rb +5 -5
- data/test/libs/affiliate.rb +2 -2
- data/test/libs/company.rb +1 -1
- data/test/libs/employee.rb +2 -2
- data/test/libs/employee_session.rb +1 -1
- data/test/libs/ldaper.rb +1 -1
- data/test/libs/project.rb +1 -1
- data/test/random_test.rb +5 -4
- data/test/session_test/activation_test.rb +5 -5
- data/test/session_test/active_record_trickery_test.rb +7 -5
- data/test/session_test/cookies_test.rb +8 -6
- data/test/session_test/existence_test.rb +19 -13
- data/test/session_test/http_auth_test.rb +0 -3
- data/test/session_test/id_test.rb +2 -2
- data/test/session_test/klass_test.rb +1 -1
- data/test/session_test/magic_columns_test.rb +0 -3
- data/test/session_test/magic_states_test.rb +11 -11
- data/test/session_test/params_test.rb +10 -10
- data/test/session_test/password_test.rb +4 -5
- data/test/session_test/perishability_test.rb +3 -3
- data/test/session_test/scopes_test.rb +8 -8
- data/test/session_test/session_test.rb +5 -4
- data/test/session_test/timeout_test.rb +8 -8
- data/test/session_test/unauthorized_record_test.rb +2 -2
- data/test/session_test/validation_test.rb +3 -3
- data/test/test_helper.rb +9 -5
- metadata +54 -24
- data/README.rdoc +0 -232
@@ -7,13 +7,13 @@ module Authlogic
|
|
7
7
|
extend Config
|
8
8
|
include InstanceMethods
|
9
9
|
validate :validate_by_password, :if => :authenticating_with_password?
|
10
|
-
|
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
19
|
# Authlogic tries to validate the credentials passed to it. One part of validation is actually finding the user and
|
@@ -23,8 +23,9 @@ module Authlogic
|
|
23
23
|
# You can change what method UserSession calls by specifying it here. Then in your User model you can make that method do
|
24
24
|
# anything you want, giving you complete control of how users are found by the UserSession.
|
25
25
|
#
|
26
|
-
# Let's take an example: You want to allow users to login by username or email.
|
27
|
-
# that does this in the User model. Let's
|
26
|
+
# Let's take an example: You want to allow users to login by username or email.
|
27
|
+
# Set this to the name of the class method that does this in the User model. Let's
|
28
|
+
# call it "find_by_username_or_email"
|
28
29
|
#
|
29
30
|
# class User < ActiveRecord::Base
|
30
31
|
# def self.find_by_username_or_email(login)
|
@@ -32,8 +33,10 @@ module Authlogic
|
|
32
33
|
# end
|
33
34
|
# end
|
34
35
|
#
|
35
|
-
# Now just specify the name of this method for this configuration option and you
|
36
|
-
#
|
36
|
+
# Now just specify the name of this method for this configuration option and you
|
37
|
+
# are all set. You can do anything you want here. Maybe you allow users to have
|
38
|
+
# multiple logins and you want to search a has_many relationship, etc. The sky is
|
39
|
+
# the limit.
|
37
40
|
#
|
38
41
|
# * <tt>Default:</tt> "find_by_smart_case_login_field"
|
39
42
|
# * <tt>Accepts:</tt> Symbol or String
|
@@ -41,10 +44,11 @@ module Authlogic
|
|
41
44
|
rw_config(:find_by_login_method, value, "find_by_smart_case_login_field")
|
42
45
|
end
|
43
46
|
alias_method :find_by_login_method=, :find_by_login_method
|
44
|
-
|
45
|
-
# The text used to identify credentials (username/password) combination when a bad
|
46
|
-
# When you show error messages for a bad login, it's
|
47
|
-
#
|
47
|
+
|
48
|
+
# The text used to identify credentials (username/password) combination when a bad
|
49
|
+
# login attempt occurs. When you show error messages for a bad login, it's
|
50
|
+
# considered good security practice to hide which field the user has entered
|
51
|
+
# incorrectly (the login field or the password field). For a full explanation, see
|
48
52
|
# http://www.gnucitizen.org/blog/username-enumeration-vulnerabilities/
|
49
53
|
#
|
50
54
|
# Example of use:
|
@@ -56,9 +60,9 @@ module Authlogic
|
|
56
60
|
# This would make the error message for bad logins and bad passwords look identical:
|
57
61
|
#
|
58
62
|
# Login/Password combination is not valid
|
59
|
-
#
|
63
|
+
#
|
60
64
|
# Alternatively you may use a custom message:
|
61
|
-
#
|
65
|
+
#
|
62
66
|
# class UserSession < AuthLogic::Session::Base
|
63
67
|
# generalize_credentials_error_messages "Your login information is invalid"
|
64
68
|
# end
|
@@ -71,18 +75,20 @@ module Authlogic
|
|
71
75
|
#
|
72
76
|
# If you are developing an app where security is an extreme priority (such as a financial application),
|
73
77
|
# then you should enable this. Otherwise, leaving this off is fine.
|
74
|
-
#
|
78
|
+
#
|
75
79
|
# * <tt>Default</tt> false
|
76
80
|
# * <tt>Accepts:</tt> Boolean
|
77
81
|
def generalize_credentials_error_messages(value = nil)
|
78
82
|
rw_config(:generalize_credentials_error_messages, value, false)
|
79
83
|
end
|
80
84
|
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 /
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
85
|
+
|
86
|
+
# The name of the method you want Authlogic to create for storing the login /
|
87
|
+
# username. Keep in mind this is just for your Authlogic::Session, if you want it
|
88
|
+
# can be something completely different than the field in your model. So if you
|
89
|
+
# wanted people to login with a field called "login" and then find users by email
|
90
|
+
# this is completely doable. See the find_by_login_method configuration option for
|
91
|
+
# more details.
|
86
92
|
#
|
87
93
|
# * <tt>Default:</tt> klass.login_field || klass.email_field
|
88
94
|
# * <tt>Accepts:</tt> Symbol or String
|
@@ -90,7 +96,7 @@ module Authlogic
|
|
90
96
|
rw_config(:login_field, value, klass.login_field || klass.email_field)
|
91
97
|
end
|
92
98
|
alias_method :login_field=, :login_field
|
93
|
-
|
99
|
+
|
94
100
|
# Works exactly like login_field, but for the password instead. Returns :password if a login_field exists.
|
95
101
|
#
|
96
102
|
# * <tt>Default:</tt> :password
|
@@ -99,7 +105,7 @@ module Authlogic
|
|
99
105
|
rw_config(:password_field, value, login_field && :password)
|
100
106
|
end
|
101
107
|
alias_method :password_field=, :password_field
|
102
|
-
|
108
|
+
|
103
109
|
# The name of the method in your model used to verify the password. This should be an instance method. It should also
|
104
110
|
# be prepared to accept a raw password and a crytped password.
|
105
111
|
#
|
@@ -110,7 +116,7 @@ module Authlogic
|
|
110
116
|
end
|
111
117
|
alias_method :verify_password_method=, :verify_password_method
|
112
118
|
end
|
113
|
-
|
119
|
+
|
114
120
|
# Password related instance methods
|
115
121
|
module InstanceMethods
|
116
122
|
def initialize(*args)
|
@@ -120,7 +126,7 @@ module Authlogic
|
|
120
126
|
end
|
121
127
|
super
|
122
128
|
end
|
123
|
-
|
129
|
+
|
124
130
|
# Returns the login_field / password_field credentials combination in hash form.
|
125
131
|
def credentials
|
126
132
|
if authenticating_with_password?
|
@@ -132,11 +138,12 @@ module Authlogic
|
|
132
138
|
super
|
133
139
|
end
|
134
140
|
end
|
135
|
-
|
141
|
+
|
136
142
|
# Accepts the login_field / password_field credentials combination in hash form.
|
137
143
|
def credentials=(value)
|
138
144
|
super
|
139
|
-
values = value
|
145
|
+
values = parse_param_val(value) # add strong parameters check
|
146
|
+
|
140
147
|
if values.first.is_a?(Hash)
|
141
148
|
values.first.with_indifferent_access.slice(login_field, password_field).each do |field, value|
|
142
149
|
next if value.blank?
|
@@ -144,18 +151,19 @@ module Authlogic
|
|
144
151
|
end
|
145
152
|
end
|
146
153
|
end
|
147
|
-
|
154
|
+
|
148
155
|
def invalid_password?
|
149
156
|
invalid_password == true
|
150
157
|
end
|
151
|
-
|
158
|
+
|
152
159
|
private
|
160
|
+
|
153
161
|
def configure_password_methods
|
154
162
|
if login_field
|
155
163
|
self.class.send(:attr_writer, login_field) if !respond_to?("#{login_field}=")
|
156
164
|
self.class.send(:attr_reader, login_field) if !respond_to?(login_field)
|
157
165
|
end
|
158
|
-
|
166
|
+
|
159
167
|
if password_field
|
160
168
|
self.class.send(:attr_writer, password_field) if !respond_to?("#{password_field}=")
|
161
169
|
self.class.send(:define_method, password_field) {} if !respond_to?(password_field)
|
@@ -174,16 +182,19 @@ module Authlogic
|
|
174
182
|
def authenticating_with_password?
|
175
183
|
login_field && (!send(login_field).nil? || !send("protected_#{password_field}").nil?)
|
176
184
|
end
|
177
|
-
|
185
|
+
|
178
186
|
def validate_by_password
|
179
187
|
self.invalid_password = false
|
180
|
-
|
188
|
+
|
181
189
|
# check for blank fields
|
182
|
-
|
183
|
-
|
190
|
+
if send(login_field).blank?
|
191
|
+
errors.add(login_field, I18n.t('error_messages.login_blank', :default => "cannot be blank"))
|
192
|
+
end
|
193
|
+
if send("protected_#{password_field}").blank?
|
194
|
+
errors.add(password_field, I18n.t('error_messages.password_blank', :default => "cannot be blank"))
|
195
|
+
end
|
184
196
|
return if errors.count > 0
|
185
197
|
|
186
|
-
# check for unknown login
|
187
198
|
self.attempted_record = search_for_record(find_by_login_method, send(login_field))
|
188
199
|
if attempted_record.blank?
|
189
200
|
generalize_credentials_error_messages? ?
|
@@ -201,19 +212,19 @@ module Authlogic
|
|
201
212
|
return
|
202
213
|
end
|
203
214
|
end
|
204
|
-
|
215
|
+
|
205
216
|
attr_accessor :invalid_password
|
206
|
-
|
217
|
+
|
207
218
|
def find_by_login_method
|
208
219
|
self.class.find_by_login_method
|
209
220
|
end
|
210
|
-
|
221
|
+
|
211
222
|
def login_field
|
212
223
|
self.class.login_field
|
213
224
|
end
|
214
|
-
|
225
|
+
|
215
226
|
def add_general_credentials_error
|
216
|
-
error_message =
|
227
|
+
error_message =
|
217
228
|
if self.class.generalize_credentials_error_messages.is_a? String
|
218
229
|
self.class.generalize_credentials_error_messages
|
219
230
|
else
|
@@ -221,18 +232,29 @@ module Authlogic
|
|
221
232
|
end
|
222
233
|
errors.add(:base, I18n.t('error_messages.general_credentials_error', :default => error_message))
|
223
234
|
end
|
224
|
-
|
235
|
+
|
225
236
|
def generalize_credentials_error_messages?
|
226
237
|
self.class.generalize_credentials_error_messages
|
227
238
|
end
|
228
|
-
|
239
|
+
|
229
240
|
def password_field
|
230
241
|
self.class.password_field
|
231
242
|
end
|
232
|
-
|
243
|
+
|
233
244
|
def verify_password_method
|
234
245
|
self.class.verify_password_method
|
235
246
|
end
|
247
|
+
|
248
|
+
# In Rails 5 the ActionController::Parameters no longer inherits from HashWithIndifferentAccess.
|
249
|
+
# See: http://guides.rubyonrails.org/upgrading_ruby_on_rails.html#actioncontroller-parameters-no-longer-inherits-from-hashwithindifferentaccess
|
250
|
+
# This method converts the ActionController::Parameters to a Hash
|
251
|
+
def parse_param_val(value)
|
252
|
+
if value.first.class.name == "ActionController::Parameters"
|
253
|
+
[value.first.to_h]
|
254
|
+
else
|
255
|
+
value.is_a?(Array) ? value : [value]
|
256
|
+
end
|
257
|
+
end
|
236
258
|
end
|
237
259
|
end
|
238
260
|
end
|
@@ -8,11 +8,12 @@ module Authlogic
|
|
8
8
|
def self.included(klass)
|
9
9
|
klass.after_save :reset_perishable_token!
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
private
|
13
|
+
|
13
14
|
def reset_perishable_token!
|
14
15
|
record.reset_perishable_token if record.respond_to?(:reset_perishable_token) && !record.disable_perishable_token_maintenance?
|
15
16
|
end
|
16
17
|
end
|
17
18
|
end
|
18
|
-
end
|
19
|
+
end
|
@@ -8,7 +8,7 @@ module Authlogic
|
|
8
8
|
include InstanceMethods
|
9
9
|
end
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
module ClassMethods
|
13
13
|
# This is how you persist a session. This finds the record for the current session using
|
14
14
|
# a variety of methods. It basically tries to "log in" the user without the user having
|
@@ -34,7 +34,7 @@ module Authlogic
|
|
34
34
|
#
|
35
35
|
# See the id method for more information on ids.
|
36
36
|
def find(id = nil, priority_record = nil)
|
37
|
-
session = new({:priority_record => priority_record}, id)
|
37
|
+
session = new({ :priority_record => priority_record }, id)
|
38
38
|
session.priority_record = priority_record
|
39
39
|
if session.persisting?
|
40
40
|
session
|
@@ -43,7 +43,7 @@ module Authlogic
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
module InstanceMethods
|
48
48
|
# Let's you know if the session is being persisted or not, meaning the user does not have to explicitly log in
|
49
49
|
# in order to be logged in. If the session has no associated record, it will try to find a record and persist
|
@@ -9,7 +9,7 @@ module Authlogic
|
|
9
9
|
attr_accessor :priority_record
|
10
10
|
end
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
# Setting priority record if it is passed. The only way it can be passed is through an array:
|
14
14
|
#
|
15
15
|
# session.credentials = [real_user_object, priority_user_object]
|
@@ -18,17 +18,18 @@ module Authlogic
|
|
18
18
|
values = value.is_a?(Array) ? value : [value]
|
19
19
|
self.priority_record = values[1] if values[1].class < ::ActiveRecord::Base
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
private
|
23
|
+
|
23
24
|
def attempted_record=(value)
|
24
25
|
value = priority_record if value == priority_record
|
25
26
|
super
|
26
27
|
end
|
27
|
-
|
28
|
+
|
28
29
|
def save_record(alternate_record = nil)
|
29
30
|
r = alternate_record || record
|
30
31
|
super if r != priority_record
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|
34
|
-
end
|
35
|
+
end
|
@@ -2,10 +2,13 @@ require 'request_store'
|
|
2
2
|
|
3
3
|
module Authlogic
|
4
4
|
module Session
|
5
|
-
# Authentication can be scoped, and it's easy, you just need to define how you want to
|
5
|
+
# Authentication can be scoped, and it's easy, you just need to define how you want to
|
6
|
+
# scope everything. This should help you:
|
6
7
|
#
|
7
|
-
# 1. Want to scope by a parent object? Ex: An account has many users.
|
8
|
-
#
|
8
|
+
# 1. Want to scope by a parent object? Ex: An account has many users.
|
9
|
+
# Checkout Authlogic::AuthenticatesMany
|
10
|
+
# 2. Want to scope the validations in your model? Ex: 2 users can have the same login
|
11
|
+
# under different accounts. See Authlogic::ActsAsAuthentic::Scope
|
9
12
|
module Scopes # :nodoc:
|
10
13
|
def self.included(klass)
|
11
14
|
klass.class_eval do
|
@@ -22,11 +25,15 @@ module Authlogic
|
|
22
25
|
RequestStore.store[:authlogic_scope]
|
23
26
|
end
|
24
27
|
|
25
|
-
# What with_scopes focuses on is scoping the query when finding the object and the
|
26
|
-
#
|
28
|
+
# What with_scopes focuses on is scoping the query when finding the object and the
|
29
|
+
# name of the cookie / session. It works very similar to
|
30
|
+
# ActiveRecord::Base#with_scopes. It accepts a hash with any of the following
|
31
|
+
# options:
|
27
32
|
#
|
28
|
-
# * <tt>find_options:</tt> any options you can pass into ActiveRecord::Base.find.
|
29
|
-
#
|
33
|
+
# * <tt>find_options:</tt> any options you can pass into ActiveRecord::Base.find.
|
34
|
+
# This is used when trying to find the record.
|
35
|
+
# * <tt>id:</tt> The id of the session, this gets merged with the real id. For
|
36
|
+
# information ids see the id method.
|
30
37
|
#
|
31
38
|
# Here is how you use it:
|
32
39
|
#
|
@@ -34,7 +41,8 @@ module Authlogic
|
|
34
41
|
# UserSession.find
|
35
42
|
# end
|
36
43
|
#
|
37
|
-
#
|
44
|
+
# Essentially what the above does is scope the searching of the object with the
|
45
|
+
# sql you provided. So instead of:
|
38
46
|
#
|
39
47
|
# User.where("login = 'ben'").first
|
40
48
|
#
|
@@ -42,7 +50,8 @@ module Authlogic
|
|
42
50
|
#
|
43
51
|
# User.where("login = 'ben' and account_id = 2").first
|
44
52
|
#
|
45
|
-
# You will also notice the :id option. This works just like the id method. It
|
53
|
+
# You will also notice the :id option. This works just like the id method. It
|
54
|
+
# scopes your cookies. So the name of your cookie will be:
|
46
55
|
#
|
47
56
|
# account_2_user_credentials
|
48
57
|
#
|
@@ -69,6 +78,7 @@ module Authlogic
|
|
69
78
|
end
|
70
79
|
|
71
80
|
private
|
81
|
+
|
72
82
|
def scope=(value)
|
73
83
|
RequestStore.store[:authlogic_scope] = value
|
74
84
|
end
|
@@ -87,6 +97,7 @@ module Authlogic
|
|
87
97
|
end
|
88
98
|
|
89
99
|
private
|
100
|
+
|
90
101
|
# Used for things like cookie_key, session_key, etc.
|
91
102
|
def build_key(last_part)
|
92
103
|
[scope[:id], super].compact.join("_")
|
@@ -28,12 +28,14 @@ module Authlogic
|
|
28
28
|
# Instance methods for the session feature.
|
29
29
|
module InstanceMethods
|
30
30
|
private
|
31
|
+
|
31
32
|
# Tries to validate the session from information in the session
|
32
33
|
def persist_by_session
|
33
34
|
persistence_token, record_id = session_credentials
|
34
35
|
if !persistence_token.nil?
|
35
|
-
# Allow finding by persistence token, because when records are created the
|
36
|
-
#
|
36
|
+
# Allow finding by persistence token, because when records are created the
|
37
|
+
# session is maintained in a before_save, when there is no id. This is done
|
38
|
+
# for performance reasons and to save on queries.
|
37
39
|
record = record_id.nil? ?
|
38
40
|
search_for_record("find_by_persistence_token", persistence_token.to_s) :
|
39
41
|
search_for_record("find_by_#{klass.primary_key}", record_id.to_s)
|
@@ -45,7 +47,10 @@ module Authlogic
|
|
45
47
|
end
|
46
48
|
|
47
49
|
def session_credentials
|
48
|
-
[
|
50
|
+
[
|
51
|
+
controller.session[session_key],
|
52
|
+
controller.session["#{session_key}_#{klass.primary_key}"]
|
53
|
+
].collect { |i| i.nil? ? i : i.to_s }.compact
|
49
54
|
end
|
50
55
|
|
51
56
|
def session_key
|
@@ -59,4 +64,4 @@ module Authlogic
|
|
59
64
|
end
|
60
65
|
end
|
61
66
|
end
|
62
|
-
end
|
67
|
+
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session
|
3
|
-
# Think about financial websites, if you are inactive for a certain period
|
4
|
-
# log back in on your next request. You can do
|
3
|
+
# Think about financial websites, if you are inactive for a certain period
|
4
|
+
# of time you will be asked to log back in on your next request. You can do
|
5
|
+
# this with Authlogic easily, there are 2 parts to this:
|
5
6
|
#
|
6
7
|
# 1. Define the timeout threshold:
|
7
8
|
#
|
@@ -15,9 +16,10 @@ module Authlogic
|
|
15
16
|
# logout_on_timeout true # default if false
|
16
17
|
# end
|
17
18
|
#
|
18
|
-
# This will require a user to log back in if they are inactive for more than
|
19
|
-
# this feature to be used you must have a
|
20
|
-
# you are
|
19
|
+
# This will require a user to log back in if they are inactive for more than
|
20
|
+
# 10 minutes. In order for this feature to be used you must have a
|
21
|
+
# last_request_at datetime column in your table for whatever model you are
|
22
|
+
# authenticating with.
|
21
23
|
module Timeout
|
22
24
|
def self.included(klass)
|
23
25
|
klass.class_eval do
|
@@ -28,22 +30,33 @@ module Authlogic
|
|
28
30
|
attr_accessor :stale_record
|
29
31
|
end
|
30
32
|
end
|
31
|
-
|
33
|
+
|
32
34
|
# Configuration for the timeout feature.
|
33
35
|
module Config
|
34
|
-
# With acts_as_authentic you get a :logged_in_timeout configuration
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
36
|
+
# With acts_as_authentic you get a :logged_in_timeout configuration
|
37
|
+
# option. If this is set, after this amount of time has passed the user
|
38
|
+
# will be marked as logged out. Obviously, since web based apps are on a
|
39
|
+
# per request basis, we have to define a time limit threshold that
|
40
|
+
# determines when we consider a user to be "logged out". Meaning, if
|
41
|
+
# they login and then leave the website, when do mark them as logged
|
42
|
+
# out? I recommend just using this as a fun feature on your website or
|
43
|
+
# reports, giving you a ballpark number of users logged in and active.
|
44
|
+
# This is not meant to be a dead accurate representation of a users
|
45
|
+
# logged in state, since there is really no real way to do this with web
|
46
|
+
# based apps. Think about a user that logs in and doesn't log out. There
|
47
|
+
# is no action that tells you that the user isn't technically still
|
48
|
+
# logged in and active.
|
41
49
|
#
|
42
|
-
# That being said, you can use that feature to require a new login if
|
43
|
-
#
|
50
|
+
# That being said, you can use that feature to require a new login if
|
51
|
+
# their session times out. Similar to how financial sites work. Just set
|
52
|
+
# this option to true and if your record returns true for stale? then
|
53
|
+
# they will be required to log back in.
|
44
54
|
#
|
45
|
-
# Lastly, UserSession.find will still return a object is the session is
|
46
|
-
#
|
55
|
+
# Lastly, UserSession.find will still return a object is the session is
|
56
|
+
# stale, but you will not get a record. This allows you to determine if
|
57
|
+
# the user needs to log back in because their session went stale, or
|
58
|
+
# because they just aren't logged in. Just call
|
59
|
+
# current_user_session.stale? as your flag.
|
47
60
|
#
|
48
61
|
# * <tt>Default:</tt> false
|
49
62
|
# * <tt>Accepts:</tt> Boolean
|
@@ -52,11 +65,14 @@ module Authlogic
|
|
52
65
|
end
|
53
66
|
alias_method :logout_on_timeout=, :logout_on_timeout
|
54
67
|
end
|
55
|
-
|
68
|
+
|
56
69
|
# Instance methods for the timeout feature.
|
57
70
|
module InstanceMethods
|
58
|
-
# Tells you if the record is stale or not. Meaning the record has timed
|
59
|
-
#
|
71
|
+
# Tells you if the record is stale or not. Meaning the record has timed
|
72
|
+
# out. This will only return true if you set logout_on_timeout to true
|
73
|
+
# in your configuration. Basically how a bank website works. If you
|
74
|
+
# aren't active over a certain period of time your session becomes stale
|
75
|
+
# and requires you to log back in.
|
60
76
|
def stale?
|
61
77
|
if remember_me?
|
62
78
|
remember_me_expired?
|
@@ -64,19 +80,20 @@ module Authlogic
|
|
64
80
|
!stale_record.nil? || (logout_on_timeout? && record && record.logged_out?)
|
65
81
|
end
|
66
82
|
end
|
67
|
-
|
83
|
+
|
68
84
|
private
|
85
|
+
|
69
86
|
def reset_stale_state
|
70
87
|
self.stale_record = nil
|
71
88
|
end
|
72
|
-
|
89
|
+
|
73
90
|
def enforce_timeout
|
74
91
|
if stale?
|
75
92
|
self.stale_record = record
|
76
93
|
self.record = nil
|
77
94
|
end
|
78
95
|
end
|
79
|
-
|
96
|
+
|
80
97
|
def logout_on_timeout?
|
81
98
|
self.class.logout_on_timeout == true
|
82
99
|
end
|