authlogic 2.0.0 → 2.1.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/.gitignore +9 -0
- data/CHANGELOG.rdoc +107 -2
- data/{MIT-LICENSE → LICENSE} +1 -1
- data/README.rdoc +136 -159
- data/Rakefile +47 -18
- data/VERSION.yml +4 -0
- data/authlogic.gemspec +205 -0
- data/init.rb +1 -1
- data/lib/authlogic/acts_as_authentic/base.rb +33 -12
- data/lib/authlogic/acts_as_authentic/email.rb +47 -14
- data/lib/authlogic/acts_as_authentic/logged_in_status.rb +20 -14
- data/lib/authlogic/acts_as_authentic/login.rb +84 -8
- data/lib/authlogic/acts_as_authentic/password.rb +216 -87
- data/lib/authlogic/acts_as_authentic/perishable_token.rb +9 -4
- data/lib/authlogic/acts_as_authentic/persistence_token.rb +4 -2
- data/lib/authlogic/acts_as_authentic/restful_authentication.rb +5 -4
- data/lib/authlogic/acts_as_authentic/session_maintenance.rb +17 -5
- data/lib/authlogic/acts_as_authentic/single_access_token.rb +10 -3
- data/lib/authlogic/acts_as_authentic/validations_scope.rb +2 -2
- data/lib/authlogic/controller_adapters/abstract_adapter.rb +13 -1
- data/lib/authlogic/controller_adapters/rails_adapter.rb +1 -1
- data/lib/authlogic/crypto_providers/aes256.rb +2 -2
- data/lib/authlogic/crypto_providers/bcrypt.rb +3 -1
- data/lib/authlogic/crypto_providers/sha1.rb +2 -2
- data/lib/authlogic/i18n.rb +10 -1
- data/lib/authlogic/regex.rb +25 -0
- data/lib/authlogic/session/activation.rb +2 -0
- data/lib/authlogic/session/active_record_trickery.rb +19 -3
- data/lib/authlogic/session/brute_force_protection.rb +26 -11
- data/lib/authlogic/session/callbacks.rb +16 -6
- data/lib/authlogic/session/cookies.rb +15 -11
- data/lib/authlogic/session/existence.rb +4 -2
- data/lib/authlogic/session/foundation.rb +1 -1
- data/lib/authlogic/session/http_auth.rb +46 -11
- data/lib/authlogic/session/magic_columns.rb +25 -6
- data/lib/authlogic/session/magic_states.rb +4 -4
- data/lib/authlogic/session/params.rb +14 -9
- data/lib/authlogic/session/password.rb +86 -24
- data/lib/authlogic/session/priority_record.rb +1 -1
- data/lib/authlogic/session/session.rb +2 -2
- data/lib/authlogic/session/timeout.rb +1 -1
- data/lib/authlogic/session/validation.rb +9 -5
- data/lib/authlogic/test_case/mock_controller.rb +45 -0
- data/lib/authlogic/test_case/mock_cookie_jar.rb +14 -0
- data/lib/authlogic/test_case/mock_logger.rb +10 -0
- data/lib/authlogic/test_case/mock_request.rb +19 -0
- data/lib/authlogic/test_case/rails_request_adapter.rb +30 -0
- data/lib/authlogic/test_case.rb +114 -0
- data/lib/authlogic.rb +1 -1
- data/rails/init.rb +1 -0
- data/shoulda_macros/authlogic.rb +2 -1
- data/test/acts_as_authentic_test/base_test.rb +6 -0
- data/test/acts_as_authentic_test/email_test.rb +25 -7
- data/test/acts_as_authentic_test/login_test.rb +37 -7
- data/test/acts_as_authentic_test/magic_columns_test.rb +4 -4
- data/test/acts_as_authentic_test/password_test.rb +64 -40
- data/test/acts_as_authentic_test/perishable_token_test.rb +36 -2
- data/test/acts_as_authentic_test/restful_authentication_test.rb +40 -0
- data/test/acts_as_authentic_test/session_maintenance_test.rb +34 -18
- data/test/acts_as_authentic_test/single_access_test.rb +6 -1
- data/test/libs/affiliate.rb +7 -0
- data/test/libs/ldaper.rb +3 -0
- data/test/random_test.rb +2 -2
- data/test/session_test/activation_test.rb +1 -1
- data/test/session_test/active_record_trickery_test.rb +2 -1
- data/test/session_test/brute_force_protection_test.rb +34 -9
- data/test/session_test/cookies_test.rb +3 -3
- data/test/session_test/http_auth_test.rb +20 -8
- data/test/session_test/magic_columns_test.rb +7 -4
- data/test/session_test/magic_states_test.rb +3 -3
- data/test/session_test/params_test.rb +4 -4
- data/test/session_test/password_test.rb +8 -0
- data/test/session_test/session_test.rb +9 -9
- data/test/session_test/timeout_test.rb +10 -1
- data/test/test_helper.rb +46 -24
- metadata +38 -27
- data/Manifest.txt +0 -111
- data/lib/authlogic/testing/test_unit_helpers.rb +0 -39
- data/lib/authlogic/version.rb +0 -56
- data/test/libs/mock_controller.rb +0 -35
- data/test/libs/mock_cookie_jar.rb +0 -10
- data/test/libs/mock_request.rb +0 -5
|
@@ -18,7 +18,7 @@ module Authlogic
|
|
|
18
18
|
# * <tt>Default:</tt> :crypted_password, :encrypted_password, :password_hash, or :pw_hash
|
|
19
19
|
# * <tt>Accepts:</tt> Symbol
|
|
20
20
|
def crypted_password_field(value = nil)
|
|
21
|
-
|
|
21
|
+
rw_config(:crypted_password_field, value, first_column_to_exist(nil, :crypted_password, :encrypted_password, :password_hash, :pw_hash))
|
|
22
22
|
end
|
|
23
23
|
alias_method :crypted_password_field=, :crypted_password_field
|
|
24
24
|
|
|
@@ -27,44 +27,129 @@ module Authlogic
|
|
|
27
27
|
# * <tt>Default:</tt> :password_salt, :pw_salt, :salt, nil if none exist
|
|
28
28
|
# * <tt>Accepts:</tt> Symbol
|
|
29
29
|
def password_salt_field(value = nil)
|
|
30
|
-
|
|
30
|
+
rw_config(:password_salt_field, value, first_column_to_exist(nil, :password_salt, :pw_salt, :salt))
|
|
31
31
|
end
|
|
32
32
|
alias_method :password_salt_field=, :password_salt_field
|
|
33
33
|
|
|
34
|
+
# Whether or not to require a password confirmation. If you don't want your users to confirm their password
|
|
35
|
+
# just set this to false.
|
|
36
|
+
#
|
|
37
|
+
# * <tt>Default:</tt> true
|
|
38
|
+
# * <tt>Accepts:</tt> Boolean
|
|
39
|
+
def require_password_confirmation(value = nil)
|
|
40
|
+
rw_config(:require_password_confirmation, value, true)
|
|
41
|
+
end
|
|
42
|
+
alias_method :require_password_confirmation=, :require_password_confirmation
|
|
43
|
+
|
|
44
|
+
# By default passwords are required when a record is new or the crypted_password is blank, but if both of these things
|
|
45
|
+
# are met a password is not required. In this case, blank passwords are ignored.
|
|
46
|
+
#
|
|
47
|
+
# Think about a profile page, where the user can edit all of their information, including changing their password.
|
|
48
|
+
# If they do not want to change their password they just leave the fields blank. This will try to set the password to
|
|
49
|
+
# a blank value, in which case is incorrect behavior. As such, Authlogic ignores this. But let's say you have a completely
|
|
50
|
+
# separate page for resetting passwords, you might not want to ignore blank passwords. If this is the case for you, then
|
|
51
|
+
# just set this value to false.
|
|
52
|
+
#
|
|
53
|
+
# * <tt>Default:</tt> true
|
|
54
|
+
# * <tt>Accepts:</tt> Boolean
|
|
55
|
+
def ignore_blank_passwords(value = nil)
|
|
56
|
+
rw_config(:ignore_blank_passwords, value, true)
|
|
57
|
+
end
|
|
58
|
+
alias_method :ignore_blank_passwords=, :ignore_blank_passwords
|
|
59
|
+
|
|
60
|
+
# When calling valid_password?("some pass") do you want to check that password against what's in that object or whats in
|
|
61
|
+
# the datbase. Take this example:
|
|
62
|
+
#
|
|
63
|
+
# u = User.first
|
|
64
|
+
# u.password = "new pass"
|
|
65
|
+
# u.valid_password?("old pass")
|
|
66
|
+
#
|
|
67
|
+
# Should the last line above return true or false? The record hasn't been saved yet, so most would assume yes.
|
|
68
|
+
# Other would assume no. So I let you decide by giving you this option.
|
|
69
|
+
#
|
|
70
|
+
# * <tt>Default:</tt> true
|
|
71
|
+
# * <tt>Accepts:</tt> Boolean
|
|
72
|
+
def check_passwords_against_database(value = nil)
|
|
73
|
+
rw_config(:check_passwords_against_database, value, true)
|
|
74
|
+
end
|
|
75
|
+
alias_method :check_passwords_against_database=, :check_passwords_against_database
|
|
76
|
+
|
|
34
77
|
# Whether or not to validate the password field.
|
|
35
78
|
#
|
|
36
79
|
# * <tt>Default:</tt> true
|
|
37
80
|
# * <tt>Accepts:</tt> Boolean
|
|
38
81
|
def validate_password_field(value = nil)
|
|
39
|
-
|
|
82
|
+
rw_config(:validate_password_field, value, true)
|
|
40
83
|
end
|
|
41
84
|
alias_method :validate_password_field=, :validate_password_field
|
|
42
85
|
|
|
86
|
+
# A hash of options for the validates_length_of call for the password field. Allows you to change this however you want.
|
|
87
|
+
#
|
|
88
|
+
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
|
89
|
+
# merge options into it. Checkout the convenience function merge_validates_length_of_password_field_options to merge
|
|
90
|
+
# options.</b>
|
|
91
|
+
#
|
|
92
|
+
# * <tt>Default:</tt> {:minimum => 4, :if => :require_password?}
|
|
93
|
+
# * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
|
|
94
|
+
def validates_length_of_password_field_options(value = nil)
|
|
95
|
+
rw_config(:validates_length_of_password_field_options, value, {:minimum => 4, :if => :require_password?})
|
|
96
|
+
end
|
|
97
|
+
alias_method :validates_length_of_password_field_options=, :validates_length_of_password_field_options
|
|
98
|
+
|
|
99
|
+
# A convenience function to merge options into the validates_length_of_login_field_options. So intead of:
|
|
100
|
+
#
|
|
101
|
+
# self.validates_length_of_password_field_options = validates_length_of_password_field_options.merge(:my_option => my_value)
|
|
102
|
+
#
|
|
103
|
+
# You can do this:
|
|
104
|
+
#
|
|
105
|
+
# merge_validates_length_of_password_field_options :my_option => my_value
|
|
106
|
+
def merge_validates_length_of_password_field_options(options = {})
|
|
107
|
+
self.validates_length_of_password_field_options = validates_length_of_password_field_options.merge(options)
|
|
108
|
+
end
|
|
109
|
+
|
|
43
110
|
# A hash of options for the validates_confirmation_of call for the password field. Allows you to change this however you want.
|
|
44
111
|
#
|
|
45
|
-
#
|
|
112
|
+
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
|
113
|
+
# merge options into it. Checkout the convenience function merge_validates_length_of_password_field_options to merge
|
|
114
|
+
# options.</b>
|
|
115
|
+
#
|
|
116
|
+
# * <tt>Default:</tt> {:if => :require_password?}
|
|
46
117
|
# * <tt>Accepts:</tt> Hash of options accepted by validates_confirmation_of
|
|
47
118
|
def validates_confirmation_of_password_field_options(value = nil)
|
|
48
|
-
|
|
119
|
+
rw_config(:validates_confirmation_of_password_field_options, value, {:if => :require_password?})
|
|
49
120
|
end
|
|
50
121
|
alias_method :validates_confirmation_of_password_field_options=, :validates_confirmation_of_password_field_options
|
|
51
122
|
|
|
123
|
+
# See merge_validates_length_of_password_field_options. The same thing, except for validates_confirmation_of_password_field_options
|
|
124
|
+
def merge_validates_confirmation_of_password_field_options(options = {})
|
|
125
|
+
self.validates_confirmation_of_password_field_options = validates_confirmation_of_password_field_options.merge(options)
|
|
126
|
+
end
|
|
127
|
+
|
|
52
128
|
# A hash of options for the validates_length_of call for the password_confirmation field. Allows you to change this however you want.
|
|
53
129
|
#
|
|
54
|
-
#
|
|
130
|
+
# <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
|
|
131
|
+
# merge options into it. Checkout the convenience function merge_validates_length_of_password_field_options to merge
|
|
132
|
+
# options.</b>
|
|
133
|
+
#
|
|
134
|
+
# * <tt>Default:</tt> validates_length_of_password_field_options
|
|
55
135
|
# * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
|
|
56
136
|
def validates_length_of_password_confirmation_field_options(value = nil)
|
|
57
|
-
|
|
137
|
+
rw_config(:validates_length_of_password_confirmation_field_options, value, validates_length_of_password_field_options)
|
|
58
138
|
end
|
|
59
139
|
alias_method :validates_length_of_password_confirmation_field_options=, :validates_length_of_password_confirmation_field_options
|
|
60
140
|
|
|
141
|
+
# See merge_validates_length_of_password_field_options. The same thing, except for validates_length_of_password_confirmation_field_options
|
|
142
|
+
def merge_validates_length_of_password_confirmation_field_options(options = {})
|
|
143
|
+
self.validates_length_of_password_confirmation_field_options = validates_length_of_password_confirmation_field_options.merge(options)
|
|
144
|
+
end
|
|
145
|
+
|
|
61
146
|
# The class you want to use to encrypt and verify your encrypted passwords. See the Authlogic::CryptoProviders module for more info
|
|
62
147
|
# on the available methods and how to create your own.
|
|
63
148
|
#
|
|
64
149
|
# * <tt>Default:</tt> CryptoProviders::Sha512
|
|
65
150
|
# * <tt>Accepts:</tt> Class
|
|
66
151
|
def crypto_provider(value = nil)
|
|
67
|
-
|
|
152
|
+
rw_config(:crypto_provider, value, CryptoProviders::Sha512)
|
|
68
153
|
end
|
|
69
154
|
alias_method :crypto_provider=, :crypto_provider
|
|
70
155
|
|
|
@@ -80,7 +165,7 @@ module Authlogic
|
|
|
80
165
|
# * <tt>Default:</tt> nil
|
|
81
166
|
# * <tt>Accepts:</tt> Class or Array
|
|
82
167
|
def transition_from_crypto_providers(value = nil)
|
|
83
|
-
|
|
168
|
+
rw_config(:transition_from_crypto_providers, (!value.nil? && [value].flatten.compact) || value, [])
|
|
84
169
|
end
|
|
85
170
|
alias_method :transition_from_crypto_providers=, :transition_from_crypto_providers
|
|
86
171
|
end
|
|
@@ -93,6 +178,7 @@ module Authlogic
|
|
|
93
178
|
]
|
|
94
179
|
|
|
95
180
|
def self.included(klass)
|
|
181
|
+
return if klass.crypted_password_field.nil?
|
|
96
182
|
klass.define_callbacks *METHODS
|
|
97
183
|
end
|
|
98
184
|
|
|
@@ -109,106 +195,149 @@ module Authlogic
|
|
|
109
195
|
# The methods related to the password field.
|
|
110
196
|
module Methods
|
|
111
197
|
def self.included(klass)
|
|
198
|
+
return if klass.crypted_password_field.nil?
|
|
199
|
+
|
|
112
200
|
klass.class_eval do
|
|
201
|
+
include InstanceMethods
|
|
202
|
+
|
|
113
203
|
if validate_password_field
|
|
114
|
-
|
|
115
|
-
|
|
204
|
+
validates_length_of :password, validates_length_of_password_field_options
|
|
205
|
+
|
|
206
|
+
if require_password_confirmation
|
|
207
|
+
validates_confirmation_of :password, validates_confirmation_of_password_field_options
|
|
208
|
+
validates_length_of :password_confirmation, validates_length_of_password_confirmation_field_options
|
|
209
|
+
end
|
|
116
210
|
end
|
|
211
|
+
|
|
212
|
+
after_save :reset_password_changed
|
|
117
213
|
end
|
|
118
214
|
end
|
|
119
215
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
216
|
+
module InstanceMethods
|
|
217
|
+
# The password
|
|
218
|
+
def password
|
|
219
|
+
@password
|
|
220
|
+
end
|
|
124
221
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
222
|
+
# This is a virtual method. Once a password is passed to it, it will create new password salt as well as encrypt
|
|
223
|
+
# the password.
|
|
224
|
+
def password=(pass)
|
|
225
|
+
return if ignore_blank_passwords? && pass.blank?
|
|
226
|
+
before_password_set
|
|
227
|
+
@password = pass
|
|
228
|
+
send("#{password_salt_field}=", Authlogic::Random.friendly_token) if password_salt_field
|
|
229
|
+
send("#{crypted_password_field}=", crypto_provider.encrypt(*encrypt_arguments(@password, false, act_like_restful_authentication? ? :restful_authentication : nil)))
|
|
230
|
+
@password_changed = true
|
|
231
|
+
after_password_set
|
|
232
|
+
end
|
|
135
233
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
234
|
+
# Accepts a raw password to determine if it is the correct password or not. Notice the second argument. That defaults to the value of
|
|
235
|
+
# check_passwords_against_database. See that method for mor information, but basically it just tells Authlogic to check the password
|
|
236
|
+
# against the value in the database or the value in the object.
|
|
237
|
+
def valid_password?(attempted_password, check_against_database = check_passwords_against_database?)
|
|
238
|
+
crypted = check_against_database && send("#{crypted_password_field}_changed?") ? send("#{crypted_password_field}_was") : send(crypted_password_field)
|
|
239
|
+
return false if attempted_password.blank? || crypted.blank?
|
|
240
|
+
before_password_verification
|
|
141
241
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
:restful_authentication : nil
|
|
242
|
+
crypto_providers.each_with_index do |encryptor, index|
|
|
243
|
+
# The arguments_type of for the transitioning from restful_authentication
|
|
244
|
+
arguments_type = (act_like_restful_authentication? && index == 0) ||
|
|
245
|
+
(transition_from_restful_authentication? && index > 0 && encryptor == Authlogic::CryptoProviders::Sha1) ?
|
|
246
|
+
:restful_authentication : nil
|
|
148
247
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if index > 0 || (encryptor.respond_to?(:cost_matches?) && !encryptor.cost_matches?(send(crypted_password_field)))
|
|
154
|
-
self.password = attempted_password
|
|
155
|
-
save(false)
|
|
248
|
+
if encryptor.matches?(crypted, *encrypt_arguments(attempted_password, check_against_database, arguments_type))
|
|
249
|
+
transition_password(attempted_password) if transition_password?(index, encryptor, crypted, check_against_database)
|
|
250
|
+
after_password_verification
|
|
251
|
+
return true
|
|
156
252
|
end
|
|
157
|
-
|
|
158
|
-
after_password_verification
|
|
159
|
-
|
|
160
|
-
return true
|
|
161
253
|
end
|
|
162
|
-
end
|
|
163
254
|
|
|
164
|
-
|
|
165
|
-
|
|
255
|
+
false
|
|
256
|
+
end
|
|
166
257
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
258
|
+
# Resets the password to a random friendly token.
|
|
259
|
+
def reset_password
|
|
260
|
+
friendly_token = Authlogic::Random.friendly_token
|
|
261
|
+
self.password = friendly_token
|
|
262
|
+
self.password_confirmation = friendly_token
|
|
263
|
+
end
|
|
264
|
+
alias_method :randomize_password, :reset_password
|
|
174
265
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
266
|
+
# Resets the password to a random friendly token and then saves the record.
|
|
267
|
+
def reset_password!
|
|
268
|
+
reset_password
|
|
269
|
+
save_without_session_maintenance(false)
|
|
270
|
+
end
|
|
271
|
+
alias_method :randomize_password!, :reset_password!
|
|
181
272
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
273
|
+
private
|
|
274
|
+
def check_passwords_against_database?
|
|
275
|
+
self.class.check_passwords_against_database == true
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def crypto_providers
|
|
279
|
+
[crypto_provider] + transition_from_crypto_providers
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def encrypt_arguments(raw_password, check_against_database, arguments_type = nil)
|
|
283
|
+
salt = nil
|
|
284
|
+
salt = (check_against_database && send("#{password_salt_field}_changed?") ? send("#{password_salt_field}_was") : send(password_salt_field)) if password_salt_field
|
|
285
|
+
|
|
286
|
+
case arguments_type
|
|
287
|
+
when :restful_authentication
|
|
288
|
+
[REST_AUTH_SITE_KEY, salt, raw_password, REST_AUTH_SITE_KEY].compact
|
|
289
|
+
else
|
|
290
|
+
[raw_password, salt].compact
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Determines if we need to tranisiton the password.
|
|
295
|
+
# If the index > 0 then we are using an "transition from" crypto provider.
|
|
296
|
+
# If the encryptor has a cost and the cost it outdated.
|
|
297
|
+
# If we aren't using database values
|
|
298
|
+
# If we are using database values, only if the password hasnt change so we don't overwrite any changes
|
|
299
|
+
def transition_password?(index, encryptor, crypted, check_against_database)
|
|
300
|
+
(index > 0 || (encryptor.respond_to?(:cost_matches?) && !encryptor.cost_matches?(send(crypted_password_field)))) &&
|
|
301
|
+
(!check_against_database || !send("#{crypted_password_field}_changed?"))
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def transition_password(attempted_password)
|
|
305
|
+
self.password = attempted_password
|
|
306
|
+
save(false)
|
|
190
307
|
end
|
|
191
|
-
end
|
|
192
308
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
309
|
+
def require_password?
|
|
310
|
+
new_record? || password_changed? || send(crypted_password_field).blank?
|
|
311
|
+
end
|
|
196
312
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
313
|
+
def ignore_blank_passwords?
|
|
314
|
+
self.class.ignore_blank_passwords == true
|
|
315
|
+
end
|
|
200
316
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
317
|
+
def password_changed?
|
|
318
|
+
@password_changed == true
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def reset_password_changed
|
|
322
|
+
@password_changed = nil
|
|
323
|
+
end
|
|
204
324
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
325
|
+
def crypted_password_field
|
|
326
|
+
self.class.crypted_password_field
|
|
327
|
+
end
|
|
208
328
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
329
|
+
def password_salt_field
|
|
330
|
+
self.class.password_salt_field
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def crypto_provider
|
|
334
|
+
self.class.crypto_provider
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def transition_from_crypto_providers
|
|
338
|
+
self.class.transition_from_crypto_providers
|
|
339
|
+
end
|
|
340
|
+
end
|
|
212
341
|
end
|
|
213
342
|
end
|
|
214
343
|
end
|
|
@@ -20,7 +20,7 @@ module Authlogic
|
|
|
20
20
|
# * <tt>Default:</tt> 10.minutes
|
|
21
21
|
# * <tt>Accepts:</tt> Fixnum
|
|
22
22
|
def perishable_token_valid_for(value = nil)
|
|
23
|
-
|
|
23
|
+
rw_config(:perishable_token_valid_for, (!value.nil? && value.to_i) || value, 10.minutes.to_i)
|
|
24
24
|
end
|
|
25
25
|
alias_method :perishable_token_valid_for=, :perishable_token_valid_for
|
|
26
26
|
|
|
@@ -31,7 +31,7 @@ module Authlogic
|
|
|
31
31
|
# * <tt>Default:</tt> false
|
|
32
32
|
# * <tt>Accepts:</tt> Boolean
|
|
33
33
|
def disable_perishable_token_maintenance(value = nil)
|
|
34
|
-
|
|
34
|
+
rw_config(:disable_perishable_token_maintenance, value, false)
|
|
35
35
|
end
|
|
36
36
|
alias_method :disable_perishable_token_maintenance=, :disable_perishable_token_maintenance
|
|
37
37
|
end
|
|
@@ -60,7 +60,7 @@ module Authlogic
|
|
|
60
60
|
# If you want to use a different timeout value, just pass it as the second parameter:
|
|
61
61
|
#
|
|
62
62
|
# User.find_using_perishable_token(token, 1.hour)
|
|
63
|
-
def find_using_perishable_token(token, age = perishable_token_valid_for)
|
|
63
|
+
def find_using_perishable_token(token, age = self.perishable_token_valid_for)
|
|
64
64
|
return if token.blank?
|
|
65
65
|
age = age.to_i
|
|
66
66
|
|
|
@@ -74,6 +74,11 @@ module Authlogic
|
|
|
74
74
|
|
|
75
75
|
find(:first, :conditions => [conditions_sql, *conditions_subs])
|
|
76
76
|
end
|
|
77
|
+
|
|
78
|
+
# This method will raise ActiveRecord::NotFound if no record is found.
|
|
79
|
+
def find_using_perishable_token!(token, age = perishable_token_valid_for)
|
|
80
|
+
find_using_perishable_token(token, age) || raise(ActiveRecord::RecordNotFound)
|
|
81
|
+
end
|
|
77
82
|
end
|
|
78
83
|
|
|
79
84
|
# Instance level methods for the perishable token.
|
|
@@ -97,4 +102,4 @@ module Authlogic
|
|
|
97
102
|
end
|
|
98
103
|
end
|
|
99
104
|
end
|
|
100
|
-
end
|
|
105
|
+
end
|
|
@@ -16,8 +16,10 @@ module Authlogic
|
|
|
16
16
|
extend ClassMethods
|
|
17
17
|
include InstanceMethods
|
|
18
18
|
|
|
19
|
-
after_password_set :
|
|
20
|
-
|
|
19
|
+
if respond_to?(:after_password_set) && respond_to?(:after_password_verification)
|
|
20
|
+
after_password_set :reset_persistence_token
|
|
21
|
+
after_password_verification :reset_persistence_token!, :if => :reset_persistence_token?
|
|
22
|
+
end
|
|
21
23
|
|
|
22
24
|
validates_presence_of :persistence_token
|
|
23
25
|
validates_uniqueness_of :persistence_token, :if => :persistence_token_changed?
|
|
@@ -18,7 +18,7 @@ module Authlogic
|
|
|
18
18
|
# * <tt>Default:</tt> false
|
|
19
19
|
# * <tt>Accepts:</tt> Boolean
|
|
20
20
|
def act_like_restful_authentication(value = nil)
|
|
21
|
-
r =
|
|
21
|
+
r = rw_config(:act_like_restful_authentication, value, false)
|
|
22
22
|
set_restful_authentication_config if value
|
|
23
23
|
r
|
|
24
24
|
end
|
|
@@ -26,9 +26,10 @@ module Authlogic
|
|
|
26
26
|
|
|
27
27
|
# This works just like act_like_restful_authentication except that it will start transitioning your users to the algorithm you
|
|
28
28
|
# specify with the crypto provider option. The next time they log in it will resave their password with the new algorithm
|
|
29
|
-
# and any new record will use the new algorithm as well.
|
|
29
|
+
# and any new record will use the new algorithm as well. Make sure to update your users table if you are using the default
|
|
30
|
+
# migration since it will set crypted_password and salt columns to a maximum width of 40 characters which is not enough.
|
|
30
31
|
def transition_from_restful_authentication(value = nil)
|
|
31
|
-
r =
|
|
32
|
+
r = rw_config(:transition_from_restful_authentication, value, false)
|
|
32
33
|
set_restful_authentication_config if value
|
|
33
34
|
r
|
|
34
35
|
end
|
|
@@ -39,7 +40,7 @@ module Authlogic
|
|
|
39
40
|
crypto_provider_key = act_like_restful_authentication ? :crypto_provider : :transition_from_crypto_providers
|
|
40
41
|
self.send("#{crypto_provider_key}=", CryptoProviders::Sha1)
|
|
41
42
|
if !defined?(::REST_AUTH_SITE_KEY) || ::REST_AUTH_SITE_KEY.nil?
|
|
42
|
-
class_eval("::REST_AUTH_SITE_KEY =
|
|
43
|
+
class_eval("::REST_AUTH_SITE_KEY = ''") if !defined?(::REST_AUTH_SITE_KEY)
|
|
43
44
|
CryptoProviders::Sha1.stretches = 1
|
|
44
45
|
end
|
|
45
46
|
end
|
|
@@ -5,7 +5,7 @@ module Authlogic
|
|
|
5
5
|
#
|
|
6
6
|
# Just to clear up any confusion, Authlogic stores both the record id and the persistence token in the session.
|
|
7
7
|
# Why? So stale sessions can not be persisted. It stores the id so it can quickly find the record, and the
|
|
8
|
-
# persistence token to ensure no sessions are stale. So if the persistence token changes, the user
|
|
8
|
+
# persistence token to ensure no sessions are stale. So if the persistence token changes, the user must log
|
|
9
9
|
# back in.
|
|
10
10
|
#
|
|
11
11
|
# Well, the persistence token changes with the password. What happens if the user changes his own password?
|
|
@@ -26,6 +26,17 @@ module Authlogic
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
module Config
|
|
29
|
+
# This is more of a convenience method. In order to turn off automatic maintenance of sessions just
|
|
30
|
+
# set this to false, or you can also set the session_ids method to a blank array. Both accomplish
|
|
31
|
+
# the same thing. This method is a little clearer in it's intentions though.
|
|
32
|
+
#
|
|
33
|
+
# * <tt>Default:</tt> true
|
|
34
|
+
# * <tt>Accepts:</tt> Boolean
|
|
35
|
+
def maintain_sessions(value = nil)
|
|
36
|
+
rw_config(:maintain_sessions, value, true)
|
|
37
|
+
end
|
|
38
|
+
alias_method :maintain_sessions=, :maintain_sessions
|
|
39
|
+
|
|
29
40
|
# As you may know, authlogic sessions can be separate by id (See Authlogic::Session::Base#id). You can
|
|
30
41
|
# specify here what session ids you want auto maintained. By default it is the main session, which has
|
|
31
42
|
# an id of nil.
|
|
@@ -33,7 +44,7 @@ module Authlogic
|
|
|
33
44
|
# * <tt>Default:</tt> [nil]
|
|
34
45
|
# * <tt>Accepts:</tt> Array
|
|
35
46
|
def session_ids(value = nil)
|
|
36
|
-
|
|
47
|
+
rw_config(:session_ids, value, [nil])
|
|
37
48
|
end
|
|
38
49
|
alias_method :session_ids=, :session_ids
|
|
39
50
|
|
|
@@ -42,7 +53,8 @@ module Authlogic
|
|
|
42
53
|
# * <tt>Default:</tt> "#{klass.name}Session".constantize
|
|
43
54
|
# * <tt>Accepts:</tt> Class
|
|
44
55
|
def session_class(value = nil)
|
|
45
|
-
|
|
56
|
+
const = "#{base_class.name}Session".constantize rescue nil
|
|
57
|
+
rw_config(:session_class, value, const)
|
|
46
58
|
end
|
|
47
59
|
alias_method :session_class=, :session_class
|
|
48
60
|
end
|
|
@@ -73,7 +85,7 @@ module Authlogic
|
|
|
73
85
|
end
|
|
74
86
|
|
|
75
87
|
def update_sessions?
|
|
76
|
-
!skip_session_maintenance && session_class.activated? && !session_ids.blank? && persistence_token_changed?
|
|
88
|
+
!skip_session_maintenance && session_class && session_class.activated? && self.class.maintain_sessions == true && !session_ids.blank? && persistence_token_changed?
|
|
77
89
|
end
|
|
78
90
|
|
|
79
91
|
def get_session_information
|
|
@@ -98,7 +110,7 @@ module Authlogic
|
|
|
98
110
|
# We only want to automatically login into the first session, since this is the main session. The other sessions are sessions
|
|
99
111
|
# that need to be created after logging into the main session.
|
|
100
112
|
session_id = session_ids.first
|
|
101
|
-
session_class.create
|
|
113
|
+
session_class.create(*[self, self, session_id].compact)
|
|
102
114
|
|
|
103
115
|
return true
|
|
104
116
|
end
|
|
@@ -12,8 +12,15 @@ module Authlogic
|
|
|
12
12
|
|
|
13
13
|
# All configuration for the single_access token aspect of acts_as_authentic.
|
|
14
14
|
module Config
|
|
15
|
+
# The single access token is used for authentication via URLs, such as a private feed. That being said,
|
|
16
|
+
# if the user changes their password, that token probably shouldn't change. If it did, the user would have
|
|
17
|
+
# to update all of their URLs. So be default this is option is disabled, if you need it, feel free to turn
|
|
18
|
+
# it on.
|
|
19
|
+
#
|
|
20
|
+
# * <tt>Default:</tt> false
|
|
21
|
+
# * <tt>Accepts:</tt> Boolean
|
|
15
22
|
def change_single_access_token_with_password(value = nil)
|
|
16
|
-
|
|
23
|
+
rw_config(:change_single_access_token_with_password, value, false)
|
|
17
24
|
end
|
|
18
25
|
alias_method :change_single_access_token_with_password=, :change_single_access_token_with_password
|
|
19
26
|
end
|
|
@@ -22,12 +29,12 @@ module Authlogic
|
|
|
22
29
|
module Methods
|
|
23
30
|
def self.included(klass)
|
|
24
31
|
return if !klass.column_names.include?("single_access_token")
|
|
25
|
-
|
|
32
|
+
|
|
26
33
|
klass.class_eval do
|
|
27
34
|
include InstanceMethods
|
|
28
35
|
validates_uniqueness_of :single_access_token, :if => :single_access_token_changed?
|
|
29
36
|
before_validation :reset_single_access_token, :if => :reset_single_access_token?
|
|
30
|
-
after_password_set
|
|
37
|
+
after_password_set(:reset_single_access_token, :if => :change_single_access_token_with_password?) if respond_to?(:after_password_set)
|
|
31
38
|
end
|
|
32
39
|
end
|
|
33
40
|
|
|
@@ -17,13 +17,13 @@ module Authlogic
|
|
|
17
17
|
# company:
|
|
18
18
|
#
|
|
19
19
|
# acts_as_authentic do |c|
|
|
20
|
-
# c.
|
|
20
|
+
# c.validations_scope = :company_id
|
|
21
21
|
# end
|
|
22
22
|
#
|
|
23
23
|
# * <tt>Default:</tt> nil
|
|
24
24
|
# * <tt>Accepts:</tt> Symbol or Array of symbols
|
|
25
25
|
def validations_scope(value = nil)
|
|
26
|
-
|
|
26
|
+
rw_config(:validations_scope, value)
|
|
27
27
|
end
|
|
28
28
|
alias_method :validations_scope=, :validations_scope
|
|
29
29
|
end
|
|
@@ -42,8 +42,20 @@ module Authlogic
|
|
|
42
42
|
controller.session
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
def responds_to_single_access_allowed?
|
|
46
|
+
controller.respond_to?(:single_access_allowed?, true)
|
|
47
|
+
end
|
|
48
|
+
|
|
45
49
|
def single_access_allowed?
|
|
46
|
-
controller.
|
|
50
|
+
controller.send(:single_access_allowed?)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def responds_to_last_request_update_allowed?
|
|
54
|
+
controller.respond_to?(:last_request_update_allowed?, true)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def last_request_update_allowed?
|
|
58
|
+
controller.send(:last_request_update_allowed?)
|
|
47
59
|
end
|
|
48
60
|
|
|
49
61
|
private
|
|
@@ -13,7 +13,7 @@ module Authlogic
|
|
|
13
13
|
|
|
14
14
|
def cookie_domain
|
|
15
15
|
@cookie_domain_key ||= (Rails::VERSION::MAJOR >= 2 && Rails::VERSION::MINOR >= 3) ? :domain : :session_domain
|
|
16
|
-
|
|
16
|
+
ActionController::Base.session_options[@cookie_domain_key]
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def request_content_type
|
|
@@ -5,7 +5,7 @@ module Authlogic
|
|
|
5
5
|
# This encryption method is reversible if you have the supplied key. So in order to use this encryption method you must supply it with a key first.
|
|
6
6
|
# In an initializer, or before your application initializes, you should do the following:
|
|
7
7
|
#
|
|
8
|
-
# Authlogic::CryptoProviders::AES256.key = "my really long and unique key,
|
|
8
|
+
# Authlogic::CryptoProviders::AES256.key = "my really long and unique key, preferrably a bunch of random characters"
|
|
9
9
|
#
|
|
10
10
|
# My final comment is that this is a strong encryption method, but its main weakness is that its reversible. If you do not need to reverse the hash
|
|
11
11
|
# then you should consider Sha512 or BCrypt instead.
|
|
@@ -34,7 +34,7 @@ module Authlogic
|
|
|
34
34
|
|
|
35
35
|
private
|
|
36
36
|
def aes
|
|
37
|
-
raise ArgumentError.new("You provide a key like #{name}.key = my_key before using the #{name}") if @key.blank?
|
|
37
|
+
raise ArgumentError.new("You must provide a key like #{name}.key = my_key before using the #{name}") if @key.blank?
|
|
38
38
|
@aes ||= OpenSSL::Cipher::Cipher.new("AES-256-ECB")
|
|
39
39
|
end
|
|
40
40
|
end
|