authlogic 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of authlogic might be problematic. Click here for more details.
- data/CHANGELOG.rdoc +8 -1
- data/Manifest +4 -0
- data/README.rdoc +50 -24
- data/authlogic.gemspec +5 -5
- data/lib/authlogic.rb +3 -0
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb +34 -10
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb +8 -3
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb +2 -2
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/password_reset.rb +73 -0
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb +27 -27
- data/lib/authlogic/session/base.rb +41 -38
- data/lib/authlogic/session/config.rb +125 -32
- data/lib/authlogic/session/password_reset.rb +17 -0
- data/lib/authlogic/session/scopes.rb +2 -6
- data/lib/authlogic/version.rb +2 -2
- data/test/fixtures/users.yml +3 -0
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb +6 -1
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb +16 -2
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/password_reset_test.rb +40 -0
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/session_maintenance_test.rb +1 -1
- data/test/session_tests/base_test.rb +9 -8
- data/test/session_tests/config_test.rb +84 -12
- data/test/session_tests/password_reset_test.rb +15 -0
- data/test/session_tests/scopes_test.rb +5 -4
- data/test/test_helper.rb +12 -6
- metadata +10 -2
data/CHANGELOG.rdoc
CHANGED
@@ -1,6 +1,13 @@
|
|
1
|
-
== 1.
|
1
|
+
== 1.2.0 released 2008-11-16
|
2
2
|
|
3
3
|
* Added check for database set up in acts_as_authentic to prevent errors during migrations.
|
4
|
+
* Forced logged_in and logged_out named scopes to use seconds.
|
5
|
+
* Hardened valid_password? method to only allow raw passwords.
|
6
|
+
* controllers and scopes are no longer stored in class variables but in the Thread.current hash so their instances die out with the thread, which frees up memory.
|
7
|
+
* Removed single_access_token_field and remember_token_field from Sesson::Config, they are not needed there.
|
8
|
+
* Added password_reset_token to assist in resetting passwords.
|
9
|
+
* Added email_field, email_field_regex, email_field_regex_failed_message configuration options to acts_as_authentic. So that you can validate emails as well as a login, instead of the either-or approach.
|
10
|
+
* Added configuration for all validation messages for the session so that you can modify them and provide I18n support.
|
4
11
|
|
5
12
|
== 1.1.1 released 2008-11-13
|
6
13
|
|
data/Manifest
CHANGED
@@ -8,6 +8,7 @@ lib/authlogic/crypto_providers/sha512.rb
|
|
8
8
|
lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb
|
9
9
|
lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb
|
10
10
|
lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb
|
11
|
+
lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/password_reset.rb
|
11
12
|
lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb
|
12
13
|
lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb
|
13
14
|
lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb
|
@@ -21,6 +22,7 @@ lib/authlogic/session/config.rb
|
|
21
22
|
lib/authlogic/session/cookies.rb
|
22
23
|
lib/authlogic/session/errors.rb
|
23
24
|
lib/authlogic/session/params.rb
|
25
|
+
lib/authlogic/session/password_reset.rb
|
24
26
|
lib/authlogic/session/scopes.rb
|
25
27
|
lib/authlogic/session/session.rb
|
26
28
|
lib/authlogic/version.rb
|
@@ -42,6 +44,7 @@ test/libs/ordered_hash.rb
|
|
42
44
|
test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb
|
43
45
|
test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb
|
44
46
|
test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/logged_in_test.rb
|
47
|
+
test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/password_reset_test.rb
|
45
48
|
test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/persistence_test.rb
|
46
49
|
test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/session_maintenance_test.rb
|
47
50
|
test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/single_access_test.rb
|
@@ -52,6 +55,7 @@ test/session_tests/base_test.rb
|
|
52
55
|
test/session_tests/config_test.rb
|
53
56
|
test/session_tests/cookies_test.rb
|
54
57
|
test/session_tests/params_test.rb
|
58
|
+
test/session_tests/password_reset_test.rb
|
55
59
|
test/session_tests/scopes_test.rb
|
56
60
|
test/session_tests/session_test.rb
|
57
61
|
test/test_helper.rb
|
data/README.rdoc
CHANGED
@@ -53,7 +53,7 @@ Or how about persisting the session...
|
|
53
53
|
class ApplicationController
|
54
54
|
helper_method :current_user_session, :current_user
|
55
55
|
|
56
|
-
|
56
|
+
private
|
57
57
|
def current_user_session
|
58
58
|
return @current_user_session if defined?(@current_user_session)
|
59
59
|
@current_user_session = UserSession.find
|
@@ -71,6 +71,7 @@ Authlogic makes this a reality. This is just the tip of the ice berg. Keep readi
|
|
71
71
|
|
72
72
|
* <b>Documentation:</b> http://authlogic.rubyforge.org
|
73
73
|
* <b>Authlogic setup tutorial:</b> http://www.binarylogic.com/2008/11/3/tutorial-authlogic-basic-setup
|
74
|
+
* <b>Authlogic reset passwords tutorial:</b> http://www.binarylogic.com/2008/11/16/tutorial-reset-passwords-with-authlogic
|
74
75
|
* <b>Live example of the setup tutorial above (with source):</b> http://authlogic_example.binarylogic.com
|
75
76
|
* <b>Bugs / feature suggestions:</b> http://binarylogic.lighthouseapp.com/projects/18752-authlogic
|
76
77
|
|
@@ -105,11 +106,13 @@ Create your user_session.rb file:
|
|
105
106
|
|
106
107
|
The user model needs to have the following columns. The names of these columns can be changed with configuration. Better yet, Authlogic tries to guess these names by checking for the existence of common names. See Authlogic::Session::Config::ClassMethods for more details, but chances are you won't have to specify any configuration for your field names, even if they aren't the same names as below.
|
107
108
|
|
108
|
-
t.string :login,
|
109
|
-
t.string :crypted_password,
|
110
|
-
t.string :password_salt,
|
111
|
-
t.string :remember_token,
|
112
|
-
t.
|
109
|
+
t.string :login, :null => false
|
110
|
+
t.string :crypted_password, :null => false
|
111
|
+
t.string :password_salt, :null => false # not needed if you are encrypting your pw instead of using a hash algorithm.
|
112
|
+
t.string :remember_token, :null => false
|
113
|
+
t.string :single_access_token, :null => false # optional, see the single access section below.
|
114
|
+
t.string :password_reset_token, :null => false # optional, see the password reset section below.
|
115
|
+
t.integer :login_count # optional, this is a "magic" column, see the magic columns section below
|
113
116
|
|
114
117
|
=== Set up your model
|
115
118
|
|
@@ -119,7 +122,7 @@ Make sure you have a model that you will be authenticating with. For this exampl
|
|
119
122
|
acts_as_authentic # for options see documentation: Authlogic::ORMAdapters::ActiveRecordAdapter::ActsAsAuthentic::Config
|
120
123
|
end
|
121
124
|
|
122
|
-
Done! Now go use it just like you would with any other ActiveRecord model. Either glance at the code at the beginning of this
|
125
|
+
Done! Now go use it just like you would with any other ActiveRecord model. Either glance at the code at the beginning of this README or check out the tutorials (see above in "helpful links") for a more detailed walk through.
|
123
126
|
|
124
127
|
== Magic Columns
|
125
128
|
|
@@ -148,19 +151,23 @@ Need Authlogic to check your own "state"? No problem, check out the hooks sectio
|
|
148
151
|
|
149
152
|
== Hooks / Callbacks
|
150
153
|
|
151
|
-
Just like ActiveRecord you can create your own hooks / callbacks so that you can do whatever you want when certain actions are performed.
|
154
|
+
Just like ActiveRecord you can create your own hooks / callbacks so that you can do whatever you want when certain actions are performed. Such as before_save, after_save, etc.
|
152
155
|
|
153
156
|
before_create
|
154
157
|
after_create
|
155
158
|
before_destroy
|
156
159
|
after_destroy
|
160
|
+
before_find
|
161
|
+
after_find
|
157
162
|
before_save
|
158
163
|
after_save
|
159
164
|
before_update
|
160
165
|
after_update
|
161
166
|
before_validation
|
162
167
|
after_validation
|
163
|
-
|
168
|
+
|
169
|
+
See Authlogic::Session::Callbacks for more information
|
170
|
+
|
164
171
|
== Multiple Sessions / Session Identifiers
|
165
172
|
|
166
173
|
You're asking: "why would I want multiple sessions?". Take this example:
|
@@ -171,7 +178,7 @@ You have an app where users login and then need to re-login to view / change the
|
|
171
178
|
@user_session = UserSession.new
|
172
179
|
@user_session.id
|
173
180
|
# => nil
|
174
|
-
|
181
|
+
|
175
182
|
# secure user session
|
176
183
|
@secure_user_session = UserSession.new(:secure)
|
177
184
|
@secure_user_session.id
|
@@ -182,25 +189,39 @@ This will keep everything separate. The :secure session will store its info in a
|
|
182
189
|
@user_session = UserSession.find
|
183
190
|
@secure_user_session = UserSession.find(:secure)
|
184
191
|
|
185
|
-
For more information on ids checkout Authlogic::Session::Base#
|
192
|
+
For more information on ids checkout Authlogic::Session::Base#id
|
193
|
+
|
194
|
+
== Resetting passwords
|
195
|
+
|
196
|
+
You may have noticed in the helpful links section is a tutorial on resetting password with Authlogic. I'm not going to repeat myself here, but I will touch on the basics, if you want more information please see the tutorial.
|
197
|
+
|
198
|
+
Just add the following field to your database:
|
199
|
+
|
200
|
+
t.string :password_reset_token, :null => false
|
201
|
+
|
202
|
+
Authlogic will notice this field and take care of maintaining it for you. You should use the value of this field to verify your user before they reset their password. There is a finder method you can use to find users with this token, I highly recommend using this method, as it adds in extra security checks to verify the user. See Authlogic::ORMAdapters::ActiveRecordAdapter::ActsAsAuthentic::PasswordReset for more information.
|
186
203
|
|
187
204
|
== Single Access / Private Feeds Access
|
188
205
|
|
189
|
-
Need to provide a single / one time access to an account where the session does NOT get persisted? Take a private feed for example, if everyone followed standards basic http auth should work just fine, but since we live in a world where following standards is a
|
206
|
+
Need to provide a single / one time access to an account where the session does NOT get persisted? Take a private feed for example, if everyone followed standards, basic http auth should work just fine, but since we live in a world where following standards is not a standard (\*cough\* Microsoft \*cough\*), the feed url needs to have some sort of "credentials" to log the user in and get their user specific feed items. This is easy, Authlogic has a nifty little feature for doing just this. All that you need to do is add the following field in your table:
|
207
|
+
|
208
|
+
t.string :single_access_token, :null => false
|
209
|
+
# or call it feeds_token, feed_token, or whatever you want with configuration
|
190
210
|
|
191
|
-
|
211
|
+
Authlogic will notice you have this and adjust accordingly. By default single_access_tokens can only be used to login for rss and atom request types.
|
192
212
|
|
193
|
-
|
213
|
+
To tailor how this works, you have the following configuration options:
|
194
214
|
|
195
|
-
|
196
|
-
2. <tt>single_access_allowed_request_types:</tt> Single access needs to be handled with care, after all, it gives the user access to their account. But maybe you don't want to allow this for your entire application. Maybe you only want to allow this for certain request types, such as application/rss+xml or application/atom+xml. By default single access is only allowed for these requests types.
|
197
|
-
3. <tt>single_access_token_field:</tt> This works just like remember_token_field. It basically allows you to name the column that the single_access_token is stored in.
|
198
|
-
4. change_single_access_token_with_password
|
215
|
+
Session configuration (Authlogic::Session::Config)
|
199
216
|
|
200
|
-
|
217
|
+
1. params_key
|
218
|
+
2. single_access_allowed_request_types
|
219
|
+
3. single_access_token_field
|
201
220
|
|
202
|
-
|
203
|
-
|
221
|
+
Model configuration (Authlogic::ORMAdapters::ActiveRecordAdapter::ActsAsAuthentic::Config)
|
222
|
+
|
223
|
+
1. single_access_token_field:
|
224
|
+
2. change_single_access_token_with_password
|
204
225
|
|
205
226
|
Please use this with care and make sure you warn your users that the URL you provide them is to remain private. Even if Billy 13 year old gets this URL and tries to log in, the only way he can login is through a GET or POST parameter with an rss or atom request. Billy can't create a cookie with this token and Billy wont have access to anything else on the site, unless you change the above configuration.
|
206
227
|
|
@@ -253,7 +274,7 @@ What's neat about cookies is that if you use sub domains they automatically scop
|
|
253
274
|
|
254
275
|
But what if you *don't* want to separate your cookies by subdomains? You can accomplish this by doing:
|
255
276
|
|
256
|
-
ActionController::Base.session_options[:session_domain] =
|
277
|
+
ActionController::Base.session_options[:session_domain] = '.mydomain.com'
|
257
278
|
|
258
279
|
If for some reason the above doesn't work for you, do some simple Google searches. There are a million blog posts on this.
|
259
280
|
|
@@ -300,8 +321,9 @@ Here is basically how this is done....
|
|
300
321
|
|
301
322
|
private
|
302
323
|
def maintain_sessions!
|
303
|
-
# If we aren't logged in
|
304
|
-
# If we
|
324
|
+
# If we aren't logged in and a user is create log them in as that user
|
325
|
+
# If we aren't logged in and a user's password changes, log them in as that user
|
326
|
+
# If we are logged in and they change their password, update the session so they remain logged in
|
305
327
|
end
|
306
328
|
end
|
307
329
|
|
@@ -339,6 +361,10 @@ Using a library that hundreds of other people use has it advantages. Probably on
|
|
339
361
|
|
340
362
|
Lastly, there is a pattern here, why clutter up all of your applications with the same code over and over?
|
341
363
|
|
364
|
+
=== Why test the same code over and over?
|
365
|
+
|
366
|
+
I've noticed my apps get cluttered with authentication tests, and they are the same exact tests! This irritates me. When you have identical tests across your apps thats a red flag that code can be extracted into a library. What's great about Authlogic is that I tested it for you. You don't write tests that test the internals of ActiveRecord do you? The same applies for Authlogic. Only test code that you've written. Essentially testing authentication is similar to testing any another RESTful controller. This makes your tests focused and easier to understand.
|
367
|
+
|
342
368
|
=== Limited to a single authentication
|
343
369
|
|
344
370
|
I recently had an app where you could log in as a user and also log in as an employee. I won't go into the specifics of the app, but it made the most sense to do it this way. So I had two sessions in one app. None of the current solutions I found easily supported this. They all assumed a single session. One session was messy enough, adding another just put me over the edge and eventually forced me to write Authlogic. Authlogic can support 100 different sessions easily and in a clean format. Just like an app can support 100 different models and 100 different records of each model.
|
data/authlogic.gemspec
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = %q{authlogic}
|
3
|
-
s.version = "1.
|
3
|
+
s.version = "1.2.0"
|
4
4
|
|
5
5
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
6
6
|
s.authors = ["Ben Johnson of Binary Logic"]
|
7
|
-
s.date = %q{2008-11-
|
7
|
+
s.date = %q{2008-11-16}
|
8
8
|
s.description = %q{A clean, simple, and unobtrusive ruby authentication solution.}
|
9
9
|
s.email = %q{bjohnson@binarylogic.com}
|
10
|
-
s.extra_rdoc_files = ["CHANGELOG.rdoc", "lib/authlogic/controller_adapters/abstract_adapter.rb", "lib/authlogic/controller_adapters/merb_adapter.rb", "lib/authlogic/controller_adapters/rails_adapter.rb", "lib/authlogic/crypto_providers/sha1.rb", "lib/authlogic/crypto_providers/sha512.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb", "lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb", "lib/authlogic/session/active_record_trickery.rb", "lib/authlogic/session/authenticates_many_association.rb", "lib/authlogic/session/base.rb", "lib/authlogic/session/callbacks.rb", "lib/authlogic/session/config.rb", "lib/authlogic/session/cookies.rb", "lib/authlogic/session/errors.rb", "lib/authlogic/session/params.rb", "lib/authlogic/session/scopes.rb", "lib/authlogic/session/session.rb", "lib/authlogic/version.rb", "lib/authlogic.rb", "README.rdoc"]
|
11
|
-
s.files = ["CHANGELOG.rdoc", "init.rb", "lib/authlogic/controller_adapters/abstract_adapter.rb", "lib/authlogic/controller_adapters/merb_adapter.rb", "lib/authlogic/controller_adapters/rails_adapter.rb", "lib/authlogic/crypto_providers/sha1.rb", "lib/authlogic/crypto_providers/sha512.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb", "lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb", "lib/authlogic/session/active_record_trickery.rb", "lib/authlogic/session/authenticates_many_association.rb", "lib/authlogic/session/base.rb", "lib/authlogic/session/callbacks.rb", "lib/authlogic/session/config.rb", "lib/authlogic/session/cookies.rb", "lib/authlogic/session/errors.rb", "lib/authlogic/session/params.rb", "lib/authlogic/session/scopes.rb", "lib/authlogic/session/session.rb", "lib/authlogic/version.rb", "lib/authlogic.rb", "Manifest", "MIT-LICENSE", "Rakefile", "README.rdoc", "shoulda_macros/authlogic.rb", "test/fixtures/companies.yml", "test/fixtures/employees.yml", "test/fixtures/projects.yml", "test/fixtures/users.yml", "test/libs/aes128_crypto_provider.rb", "test/libs/mock_controller.rb", "test/libs/mock_cookie_jar.rb", "test/libs/mock_request.rb", "test/libs/ordered_hash.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/logged_in_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/persistence_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/session_maintenance_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/single_access_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/authenticates_many_test.rb", "test/session_tests/active_record_trickery_test.rb", "test/session_tests/authenticates_many_association_test.rb", "test/session_tests/base_test.rb", "test/session_tests/config_test.rb", "test/session_tests/cookies_test.rb", "test/session_tests/params_test.rb", "test/session_tests/scopes_test.rb", "test/session_tests/session_test.rb", "test/test_helper.rb", "authlogic.gemspec"]
|
10
|
+
s.extra_rdoc_files = ["CHANGELOG.rdoc", "lib/authlogic/controller_adapters/abstract_adapter.rb", "lib/authlogic/controller_adapters/merb_adapter.rb", "lib/authlogic/controller_adapters/rails_adapter.rb", "lib/authlogic/crypto_providers/sha1.rb", "lib/authlogic/crypto_providers/sha512.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/password_reset.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb", "lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb", "lib/authlogic/session/active_record_trickery.rb", "lib/authlogic/session/authenticates_many_association.rb", "lib/authlogic/session/base.rb", "lib/authlogic/session/callbacks.rb", "lib/authlogic/session/config.rb", "lib/authlogic/session/cookies.rb", "lib/authlogic/session/errors.rb", "lib/authlogic/session/params.rb", "lib/authlogic/session/password_reset.rb", "lib/authlogic/session/scopes.rb", "lib/authlogic/session/session.rb", "lib/authlogic/version.rb", "lib/authlogic.rb", "README.rdoc"]
|
11
|
+
s.files = ["CHANGELOG.rdoc", "init.rb", "lib/authlogic/controller_adapters/abstract_adapter.rb", "lib/authlogic/controller_adapters/merb_adapter.rb", "lib/authlogic/controller_adapters/rails_adapter.rb", "lib/authlogic/crypto_providers/sha1.rb", "lib/authlogic/crypto_providers/sha512.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/password_reset.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb", "lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb", "lib/authlogic/session/active_record_trickery.rb", "lib/authlogic/session/authenticates_many_association.rb", "lib/authlogic/session/base.rb", "lib/authlogic/session/callbacks.rb", "lib/authlogic/session/config.rb", "lib/authlogic/session/cookies.rb", "lib/authlogic/session/errors.rb", "lib/authlogic/session/params.rb", "lib/authlogic/session/password_reset.rb", "lib/authlogic/session/scopes.rb", "lib/authlogic/session/session.rb", "lib/authlogic/version.rb", "lib/authlogic.rb", "Manifest", "MIT-LICENSE", "Rakefile", "README.rdoc", "shoulda_macros/authlogic.rb", "test/fixtures/companies.yml", "test/fixtures/employees.yml", "test/fixtures/projects.yml", "test/fixtures/users.yml", "test/libs/aes128_crypto_provider.rb", "test/libs/mock_controller.rb", "test/libs/mock_cookie_jar.rb", "test/libs/mock_request.rb", "test/libs/ordered_hash.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/logged_in_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/password_reset_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/persistence_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/session_maintenance_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/single_access_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/authenticates_many_test.rb", "test/session_tests/active_record_trickery_test.rb", "test/session_tests/authenticates_many_association_test.rb", "test/session_tests/base_test.rb", "test/session_tests/config_test.rb", "test/session_tests/cookies_test.rb", "test/session_tests/params_test.rb", "test/session_tests/password_reset_test.rb", "test/session_tests/scopes_test.rb", "test/session_tests/session_test.rb", "test/test_helper.rb", "authlogic.gemspec"]
|
12
12
|
s.has_rdoc = true
|
13
13
|
s.homepage = %q{http://github.com/binarylogic/authlogic}
|
14
14
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Authlogic", "--main", "README.rdoc"]
|
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.rubyforge_project = %q{authlogic}
|
17
17
|
s.rubygems_version = %q{1.2.0}
|
18
18
|
s.summary = %q{A clean, simple, and unobtrusive ruby authentication solution.}
|
19
|
-
s.test_files = ["test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/logged_in_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/persistence_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/session_maintenance_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/single_access_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/authenticates_many_test.rb", "test/session_tests/active_record_trickery_test.rb", "test/session_tests/authenticates_many_association_test.rb", "test/session_tests/base_test.rb", "test/session_tests/config_test.rb", "test/session_tests/cookies_test.rb", "test/session_tests/params_test.rb", "test/session_tests/scopes_test.rb", "test/session_tests/session_test.rb", "test/test_helper.rb"]
|
19
|
+
s.test_files = ["test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/credentials_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/logged_in_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/password_reset_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/persistence_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/session_maintenance_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/single_access_test.rb", "test/orm_adapters_tests/active_record_adapter_tests/authenticates_many_test.rb", "test/session_tests/active_record_trickery_test.rb", "test/session_tests/authenticates_many_association_test.rb", "test/session_tests/base_test.rb", "test/session_tests/config_test.rb", "test/session_tests/cookies_test.rb", "test/session_tests/params_test.rb", "test/session_tests/password_reset_test.rb", "test/session_tests/scopes_test.rb", "test/session_tests/session_test.rb", "test/test_helper.rb"]
|
20
20
|
|
21
21
|
if s.respond_to? :specification_version then
|
22
22
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
data/lib/authlogic.rb
CHANGED
@@ -13,6 +13,7 @@ if defined?(ActiveRecord)
|
|
13
13
|
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic"
|
14
14
|
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials"
|
15
15
|
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in"
|
16
|
+
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/password_reset"
|
16
17
|
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence"
|
17
18
|
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance"
|
18
19
|
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access"
|
@@ -27,6 +28,7 @@ require File.dirname(__FILE__) + "/authlogic/session/config"
|
|
27
28
|
require File.dirname(__FILE__) + "/authlogic/session/cookies"
|
28
29
|
require File.dirname(__FILE__) + "/authlogic/session/errors"
|
29
30
|
require File.dirname(__FILE__) + "/authlogic/session/params"
|
31
|
+
require File.dirname(__FILE__) + "/authlogic/session/password_reset"
|
30
32
|
require File.dirname(__FILE__) + "/authlogic/session/session"
|
31
33
|
require File.dirname(__FILE__) + "/authlogic/session/scopes"
|
32
34
|
require File.dirname(__FILE__) + "/authlogic/session/base"
|
@@ -38,6 +40,7 @@ module Authlogic
|
|
38
40
|
include Callbacks
|
39
41
|
include Cookies
|
40
42
|
include Params
|
43
|
+
include PasswordReset
|
41
44
|
include Session
|
42
45
|
include Scopes
|
43
46
|
end
|
@@ -34,20 +34,27 @@ module Authlogic
|
|
34
34
|
#
|
35
35
|
# * <tt>login_field_regex_failed_message</tt> - the message to use when the validates_format_of for the login field fails. This depends on if you are
|
36
36
|
# performing :email or :login regex.
|
37
|
+
#
|
38
|
+
# * <tt>email_field</tt> - default: :email, depending on if it is present, if :email is not present defaults to nil
|
39
|
+
# The name of the field used to store the email address. Only specify this if you arent using this as your :login_field.
|
40
|
+
#
|
41
|
+
# * <tt>email_field_regex</tt> - default: type email regex
|
42
|
+
# This is used in validates_format_of for the :email_field.
|
43
|
+
#
|
44
|
+
# * <tt>email_field_regex_failed_message</tt> - the message to use when the validates_format_of for the email field fails.
|
37
45
|
#
|
38
46
|
# * <tt>change_single_access_token_with_password</tt> - default: false,
|
39
47
|
# When a user changes their password do you want the single access token to change as well? That's what this configuration option is all about.
|
40
48
|
#
|
41
|
-
# * <tt>single_access_token_field</tt> - default: :single_access_token, :feed_token, or :feeds_token, depending on which column is present,
|
49
|
+
# * <tt>single_access_token_field</tt> - default: :single_access_token, :feed_token, or :feeds_token, depending on which column is present, if none are present defaults to nil
|
42
50
|
# This is the name of the field to login with single access, mainly used for private feed access. Only specify if the name of the field is different
|
43
51
|
# then the defaults. See the "Single Access" section in the README for more details on how single access works.
|
44
52
|
#
|
45
53
|
# * <tt>password_field</tt> - default: :password,
|
46
54
|
# This is the name of the field to set the password, *NOT* the field the encrypted password is stored. Defaults the what the configuration
|
47
55
|
#
|
48
|
-
# * <tt>crypted_password_field</tt> - default: depends on which columns are present,
|
49
|
-
# The name of the database field where your encrypted password is stored.
|
50
|
-
# you need to specify it with this option: crypted_password, encrypted_password, password_hash, pw_hash
|
56
|
+
# * <tt>crypted_password_field</tt> - default: :crypted_password, :encrypted_password, :password_hash, :pw_hash, depends on which columns are present, if none are present defaults to nil
|
57
|
+
# The name of the database field where your encrypted password is stored.
|
51
58
|
#
|
52
59
|
# * <tt>password_blank_message</tt> - default: "can not be blank",
|
53
60
|
# The error message used when the password is left blank.
|
@@ -57,6 +64,15 @@ module Authlogic
|
|
57
64
|
#
|
58
65
|
# * <tt>password_salt_field</tt> - default: :password_salt, :pw_salt, or :salt, depending on which column is present, defaults to :password_salt if none are present,
|
59
66
|
# This is the name of the field in your database that stores your password salt.
|
67
|
+
#
|
68
|
+
# * <tt>password_reset_token_field</tt> - default: :password_reset_token, :pw_reset_token, :reset_password_token, or :reset_pw_token, depending on which column is present, if none are present defaults to nil
|
69
|
+
# This is the name of the field in your database that stores your password reset token. The token you should use to verify your users before you allow a password reset. Authlogic takes care
|
70
|
+
# of maintaining this for you and making sure it changes when needed.
|
71
|
+
#
|
72
|
+
# * <tt>password_reset_token_valid_for</tt> - default: 10.minutes,
|
73
|
+
# Authlogic gives you a sepcial method for finding records by the password reset token (see Authlogic::ORMAdapters::ActiveRecordAdapter::ActcsAsAuthentic::PasswordReset). In this method
|
74
|
+
# it checks for the age of the token. If the token is old than whatever you specify here, a user will NOT be returned. This way the tokens are perishable, thus making this system much
|
75
|
+
# more secure.
|
60
76
|
#
|
61
77
|
# * <tt>remember_token_field</tt> - default: :remember_token, :remember_key, :cookie_tokien, or :cookie_key, depending on which column is present, defaults to :remember_token if none are present,
|
62
78
|
# This is the name of the field your remember_token is stored. The remember token is a unique token that is stored in the users cookie and
|
@@ -93,14 +109,19 @@ module Authlogic
|
|
93
109
|
options[:crypto_provider] ||= CryptoProviders::Sha512
|
94
110
|
options[:login_field] ||= first_column_to_exist(:login, :username, :email)
|
95
111
|
options[:login_field_type] ||= options[:login_field] == :email ? :email : :login
|
96
|
-
|
112
|
+
options[:email_field] = first_column_to_exist(nil, :email) unless options.key?(:email_field)
|
113
|
+
options[:email_field] = nil if options[:email_field] == options[:login_field]
|
114
|
+
|
115
|
+
email_name_regex = '[\w\.%\+\-]+'
|
116
|
+
domain_head_regex = '(?:[A-Z0-9\-]+\.)+'
|
117
|
+
domain_tld_regex = '(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)'
|
118
|
+
options[:email_field_regex] ||= /\A#{email_name_regex}@#{domain_head_regex}#{domain_tld_regex}\z/i
|
119
|
+
options[:email_field_regex_failed_message] ||= "should look like an email address."
|
120
|
+
|
97
121
|
case options[:login_field_type]
|
98
122
|
when :email
|
99
|
-
|
100
|
-
|
101
|
-
domain_tld_regex = '(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)'
|
102
|
-
options[:login_field_regex] ||= /\A#{email_name_regex}@#{domain_head_regex}#{domain_tld_regex}\z/i
|
103
|
-
options[:login_field_regex_failed_message] ||= "should look like an email address."
|
123
|
+
options[:login_field_regex] ||= options[:email_field_regex]
|
124
|
+
options[:login_field_regex_failed_message] ||= options[:email_field_regex_failed_message]
|
104
125
|
else
|
105
126
|
options[:login_field_regex] ||= /\A\w[\w\.\-_@ ]+\z/
|
106
127
|
options[:login_field_regex_failed_message] ||= "use only letters, numbers, spaces, and .-_@ please."
|
@@ -113,6 +134,9 @@ module Authlogic
|
|
113
134
|
options[:password_salt_field] ||= first_column_to_exist(:password_salt, :pw_salt, :salt)
|
114
135
|
options[:remember_token_field] ||= first_column_to_exist(:remember_token, :remember_key, :cookie_token, :cookiey_key)
|
115
136
|
options[:single_access_token_field] ||= first_column_to_exist(nil, :single_access_token, :feed_token, :feeds_token)
|
137
|
+
options[:password_reset_token_field] ||= first_column_to_exist(nil, :password_reset_token, :pw_reset_token, :reset_password_token, :reset_pw_token)
|
138
|
+
options[:password_reset_token_valid_for] ||= 10.minutes
|
139
|
+
options[:password_reset_token_valid_for] = options[:password_reset_token_valid_for].to_i
|
116
140
|
options[:logged_in_timeout] ||= 10.minutes
|
117
141
|
options[:logged_in_timeout] = options[:logged_in_timeout].to_i
|
118
142
|
options[:session_ids] ||= [nil]
|
@@ -13,7 +13,7 @@ module Authlogic
|
|
13
13
|
# === Instance Methods
|
14
14
|
#
|
15
15
|
# * <tt>{options[:password_field]}=(value)</tt> - encrypts a raw password and sets it to your crypted_password_field. Also sets the password_salt to a random token.
|
16
|
-
# * <tt>valid_{options[:password_field]}?(password_to_check)</tt> - checks is the password is valid. The password passed
|
16
|
+
# * <tt>valid_{options[:password_field]}?(password_to_check)</tt> - checks is the password is valid. The password passed must be the raw password, not encrypted.
|
17
17
|
# * <tt>reset_{options[:password_field]}</tt> - resets the password using the friendly_unique_token class method
|
18
18
|
# * <tt>reset_{options[:password_field]}!</tt> - calls reset_password and then saves the record
|
19
19
|
module Credentials
|
@@ -29,6 +29,12 @@ module Authlogic
|
|
29
29
|
validates_length_of options[:login_field], :within => 2..100, :allow_blank => true
|
30
30
|
validates_format_of options[:login_field], :with => options[:login_field_regex], :message => options[:login_field_regex_failed_message]
|
31
31
|
end
|
32
|
+
|
33
|
+
if options[:email_field]
|
34
|
+
validates_length_of options[:email_field], :within => 6..100
|
35
|
+
validates_format_of options[:email_field], :with => options[:email_field_regex], :message => options[:email_field_regex_failed_message]
|
36
|
+
validates_uniqueness_of options[:email_field], :scope => options[:scope]
|
37
|
+
end
|
32
38
|
|
33
39
|
validates_uniqueness_of options[:login_field], :scope => options[:scope]
|
34
40
|
validate :validate_password
|
@@ -54,8 +60,7 @@ module Authlogic
|
|
54
60
|
|
55
61
|
def valid_#{options[:password_field]}?(attempted_password)
|
56
62
|
return false if attempted_password.blank? || #{options[:crypted_password_field]}.blank? || #{options[:password_salt_field]}.blank?
|
57
|
-
|
58
|
-
(#{options[:crypto_provider]}.respond_to?(:decrypt) && #{options[:crypto_provider]}.decrypt(#{options[:crypted_password_field]}) == attempted_password + #{options[:password_salt_field]}) ||
|
63
|
+
(#{options[:crypto_provider]}.respond_to?(:decrypt) && #{options[:crypto_provider]}.decrypt(#{options[:crypted_password_field]}) == attempted_password + #{options[:password_salt_field]}) ||
|
59
64
|
(!#{options[:crypto_provider]}.respond_to?(:decrypt) && #{options[:crypto_provider]}.encrypt(attempted_password + #{options[:password_salt_field]}) == #{options[:crypted_password_field]})
|
60
65
|
end
|
61
66
|
|
@@ -22,8 +22,8 @@ module Authlogic
|
|
22
22
|
validates_numericality_of :login_count, :only_integer => :true, :greater_than_or_equal_to => 0, :allow_nil => true if column_names.include?("login_count")
|
23
23
|
|
24
24
|
if column_names.include?("last_request_at")
|
25
|
-
named_scope :logged_in, lambda { {:conditions => ["last_request_at > ?", options[:logged_in_timeout].ago]} }
|
26
|
-
named_scope :logged_out, lambda { {:conditions => ["last_request_at is NULL or last_request_at <= ?", options[:logged_in_timeout].ago]} }
|
25
|
+
named_scope :logged_in, lambda { {:conditions => ["last_request_at > ?", options[:logged_in_timeout].seconds.ago]} }
|
26
|
+
named_scope :logged_out, lambda { {:conditions => ["last_request_at is NULL or last_request_at <= ?", options[:logged_in_timeout].seconds.ago]} }
|
27
27
|
end
|
28
28
|
|
29
29
|
if column_names.include?("last_request_at")
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Authlogic
|
2
|
+
module ORMAdapters
|
3
|
+
module ActiveRecordAdapter
|
4
|
+
module ActsAsAuthentic
|
5
|
+
# = Password Reset
|
6
|
+
#
|
7
|
+
# Handles all logic the deals with maintaining the password reset token. This token should be used to authenticate a user that is not logged in so that they
|
8
|
+
# can change their password.
|
9
|
+
#
|
10
|
+
# === Class Methods
|
11
|
+
#
|
12
|
+
# * <tt>find_using_{options[:password_reset_token_field]}(token)</tt> - returns the record that matches the pased token. The record's updated at column must not be older than
|
13
|
+
# {options[:password_reset_token_valid_for]} ago. Lastly, if a blank token is passed no record will be returned.
|
14
|
+
#
|
15
|
+
# === Instance Methods
|
16
|
+
#
|
17
|
+
# * <tt>reset_#{options[:password_reset_token_field]}</tt> - resets the password reset token field to a friendly unique token.
|
18
|
+
# * <tt>reset_#{options[:password_reset_token_field]}!</tt> - same as above but saves the record afterwards.
|
19
|
+
module PasswordReset
|
20
|
+
def acts_as_authentic_with_password_reset(options = {})
|
21
|
+
acts_as_authentic_without_password_reset(options)
|
22
|
+
|
23
|
+
return if options[:password_reset_token_field].blank?
|
24
|
+
|
25
|
+
class_eval <<-"end_eval", __FILE__, __LINE__
|
26
|
+
validates_uniqueness_of :#{options[:password_reset_token_field]}
|
27
|
+
|
28
|
+
before_validation :reset_#{options[:password_reset_token_field]}, :unless => :resetting_#{options[:password_reset_token_field]}?
|
29
|
+
|
30
|
+
def self.find_using_#{options[:password_reset_token_field]}(token)
|
31
|
+
return if token.blank?
|
32
|
+
|
33
|
+
conditions_sql = "#{options[:password_reset_token_field]} = ?"
|
34
|
+
conditions_subs = [token]
|
35
|
+
|
36
|
+
if column_names.include?("updated_at") && #{options[:password_reset_token_valid_for]} > 0
|
37
|
+
conditions_sql += " and updated_at > ?"
|
38
|
+
conditions_subs << #{options[:password_reset_token_valid_for]}.seconds.ago
|
39
|
+
end
|
40
|
+
|
41
|
+
find(:first, :conditions => [conditions_sql, *conditions_subs])
|
42
|
+
end
|
43
|
+
|
44
|
+
def reset_#{options[:password_reset_token_field]}
|
45
|
+
self.#{options[:password_reset_token_field]} = self.class.friendly_unique_token
|
46
|
+
end
|
47
|
+
|
48
|
+
def reset_#{options[:password_reset_token_field]}!
|
49
|
+
reset_#{options[:password_reset_token_field]}
|
50
|
+
@resetting_#{options[:password_reset_token_field]} = true
|
51
|
+
result = save_without_session_maintenance
|
52
|
+
@resetting_#{options[:password_reset_token_field]} = false
|
53
|
+
result
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def resetting_#{options[:password_reset_token_field]}?
|
58
|
+
@resetting_#{options[:password_reset_token_field]} == true
|
59
|
+
end
|
60
|
+
end_eval
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
ActiveRecord::Base.class_eval do
|
69
|
+
class << self
|
70
|
+
include Authlogic::ORMAdapters::ActiveRecordAdapter::ActsAsAuthentic::PasswordReset
|
71
|
+
alias_method_chain :acts_as_authentic, :password_reset
|
72
|
+
end
|
73
|
+
end
|