authlogic 2.0.11 → 2.0.12

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.

Files changed (34) hide show
  1. data/CHANGELOG.rdoc +9 -0
  2. data/README.rdoc +53 -23
  3. data/init.rb +1 -1
  4. data/lib/authlogic.rb +1 -0
  5. data/lib/authlogic/acts_as_authentic/base.rb +1 -1
  6. data/lib/authlogic/acts_as_authentic/email.rb +6 -15
  7. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +1 -1
  8. data/lib/authlogic/acts_as_authentic/login.rb +6 -6
  9. data/lib/authlogic/acts_as_authentic/password.rb +14 -14
  10. data/lib/authlogic/acts_as_authentic/perishable_token.rb +2 -2
  11. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +4 -3
  12. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +3 -3
  13. data/lib/authlogic/acts_as_authentic/single_access_token.rb +1 -1
  14. data/lib/authlogic/acts_as_authentic/validations_scope.rb +1 -1
  15. data/lib/authlogic/controller_adapters/abstract_adapter.rb +8 -0
  16. data/lib/authlogic/i18n.rb +1 -1
  17. data/lib/authlogic/session/brute_force_protection.rb +9 -6
  18. data/lib/authlogic/session/cookies.rb +3 -3
  19. data/lib/authlogic/session/foundation.rb +1 -1
  20. data/lib/authlogic/session/http_auth.rb +1 -1
  21. data/lib/authlogic/session/magic_columns.rb +19 -3
  22. data/lib/authlogic/session/magic_states.rb +1 -1
  23. data/lib/authlogic/session/params.rb +2 -2
  24. data/lib/authlogic/session/password.rb +49 -10
  25. data/lib/authlogic/session/session.rb +1 -1
  26. data/lib/authlogic/session/timeout.rb +1 -1
  27. data/lib/authlogic/test_case.rb +14 -0
  28. data/lib/authlogic/test_case/mock_request.rb +1 -1
  29. data/lib/authlogic/version.rb +1 -1
  30. data/test/acts_as_authentic_test/email_test.rb +1 -1
  31. data/test/acts_as_authentic_test/login_test.rb +1 -1
  32. data/test/acts_as_authentic_test/password_test.rb +1 -4
  33. data/test/session_test/password_test.rb +8 -0
  34. metadata +7 -5
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,12 @@
1
+ == 2.0.12 release 2009-5-13
2
+
3
+ * Added the ability to add a last_request_update_allowed? method in your controller to pragmatically tell Authlogic when and when not to update the last_request_at field in your database. This only takes effect if the method if present.
4
+ * Extracted Authlogic's regular expressions into it's own module to allow easy use of them outside of Authlogic. See Authlogic::Regex for more info.
5
+ * Made being_brute_force_protected? true for the Authlogic::Session::BruteForceProtection module.
6
+ * Added the configuration option generalize_credentials_error_messages for the Authlogic::Session::Password module. This allows you to generalize your login / password errors messages as to not reveal was the problem was when authenticating. If enabled, when an invalid login is supplied it will use the same exact error message when an invalid password is supplied.
7
+ * Update email regular expression to use A-Z0-9 instead of /w as to not allow for diacritical marks in an email address.
8
+ * Changed config() convenience method to rw_config() to be more descriptive and less vague.
9
+
1
10
  == 2.0.11 release 2009-4-25
2
11
 
3
12
  * Fix bug when password is turned off and the SingleAccessToken module calls the after_password_set callback.
data/README.rdoc CHANGED
@@ -4,33 +4,57 @@ Authlogic is a clean, simple, and unobtrusive ruby authentication solution.
4
4
 
5
5
  A code example can replace a thousand words...
6
6
 
7
- Authlogic introduces a new type of model. You can have as many as you want, and name them whatever you want, just like your other models. In this example we want to authenticate with the User model, which is inferred by the name:
7
+ Authlogic introduces a new type of model. You can have as many as you want, and name them whatever you want, just like your other models. In this example, we want to authenticate with the User model, which is inferred by the name:
8
8
 
9
9
  class UserSession < Authlogic::Session::Base
10
+ # specify configuration here, such as:
11
+ # logout_on_timeout true
12
+ # ...many more options in the documentation
10
13
  end
11
14
 
12
- Log in with any of the following. Use it just like your other models:
15
+ Log in with any of the following. Create a UserSessionsController and use it just like your other models:
13
16
 
14
- UserSession.create(my_user_object)
15
- UserSession.create(:login => "bjohnson", :password => "my password")
16
- session = UserSession.new(:login => "bjohnson", :password => "my password"); session.save
17
- UserSession.create(:openid_identifier => "identifier") # requires the authlogic-oid "add on" gem
17
+ UserSession.create(:login => "bjohnson", :password => "my password", :remember_me => true)
18
+ session = UserSession.new(:login => "bjohnson", :password => "my password", :remember_me => true); session.save
19
+ UserSession.create(:openid_identifier => "identifier", :remember_me => true) # requires the authlogic-oid "add on" gem
20
+ UserSession.create(my_user_object, true) # skip authentication and log the user in directly, the true means "remember me"
21
+
22
+ The above handles the entire authentication process for you. It first authenticates, then it sets up the proper session values and cookies to persist the session. Just like you would if you rolled your own authentication solution.
23
+
24
+ You can also log out / destroy the session:
25
+
26
+ session.destroy
18
27
 
19
28
  After a session has been created, you can persist it across requests. Thus keeping the user logged in:
20
29
 
21
30
  session = UserSession.find
22
31
 
23
- You can also log out / destroy the session:
32
+ To get all of the nice authentication functionality in your model just do this:
24
33
 
25
- session.destroy
34
+ class User < ActiveRecord::Base
35
+ acts_as_authentic do |c|
36
+ c.my_config_option = my_value
37
+ end # the configuration block is optional
38
+ end
39
+
40
+ This handles validations, etc. It is also "smart" in the sense that it if a login field is present it will use that to authenticate, if not it will look for an email field, etc. This is all configurable, but for 99% of cases that above is all you will need to do.
41
+
42
+ Also, sessions are automatically maintained. You can switch this on and off with configuration, but the following will automatically log a user in after a successful registration:
43
+
44
+ User.create(params[:user])
45
+
46
+ This also updates the session when the user changes his/her password.
47
+
48
+ Authlogic is very flexible, it has a strong public API and a plethora of hooks to allow you to modify behavior and extend it. Check out the helpful links below to dig deeper.
26
49
 
27
50
  == Helpful links
28
51
 
29
- * <b>Documentation:</b> http://authlogic.rubyforge.org
30
- * <b>Repository:</b> http://github.com/binarylogic/authlogic/tree/master
31
- * <b>Live example with OpenID "add on":</b> http://authlogicexample.binarylogic.com
32
- * <b>Live example repository with tutorial:</b> http://github.com/binarylogic/authlogic_example/tree/master
33
- * <b>Tutorial: Reset passwords with Authlogic the RESTful way:</b> http://www.binarylogic.com/2008/11/16/tutorial-reset-passwords-with-authlogic
52
+ * <b>Documentation:</b> http://authlogic.rubyforge.org
53
+ * <b>Repository:</b> http://github.com/binarylogic/authlogic/tree/master
54
+ * <b>Railscasts Screencast:</b> http://railscasts.com/episodes/160-authlogic
55
+ * <b>Live example with OpenID "add on":</b> http://authlogicexample.binarylogic.com
56
+ * <b>Live example repository with tutorial in README:</b> http://github.com/binarylogic/authlogic_example/tree/master
57
+ * <b>Tutorial: Reset passwords with Authlogic the RESTful way:</b> http://www.binarylogic.com/2008/11/16/tutorial-reset-passwords-with-authlogic
34
58
  * <b>Bugs / feature suggestions:</b> http://binarylogic.lighthouseapp.com/projects/18752-authlogic
35
59
  * <b>Google group:</b> http://groups.google.com/group/authlogic
36
60
 
@@ -40,14 +64,18 @@ If you find a bug or a problem please post it on lighthouse. If you need help wi
40
64
 
41
65
  == Authlogic "add ons"
42
66
 
43
- * <b>Authlogic OpenID addon:</b> http://github.com/binarylogic/authlogic_openid
44
- * <b>Authlogic LDAP addon:</b> http://github.com/binarylogic/authlogic_ldap
67
+ * <b>Authlogic OpenID addon:</b> http://github.com/binarylogic/authlogic_openid
68
+ * <b>Authlogic LDAP addon:</b> http://github.com/binarylogic/authlogic_ldap
45
69
 
46
70
  If you create one of your own, please let me know about it so I can add it to this list. Or just fork the project, add your link, and send me a pull request.
47
71
 
72
+ == Session bugs (please read if you are having issues with logging in / out)
73
+
74
+ Apparently there is a bug with apache / passenger for v2.1.X with sessions not working properly. This is most likely your problem if you are having trouble logging in / out. This is *not* an Authlogic issue. This can be solved by updating passener or using an alternative session store solution, such as active record store.
75
+
48
76
  == Documentation explanation
49
77
 
50
- You can find anything you want about Authlogic in the {documentation}, all that you need to do is understand the basic design behind it.
78
+ You can find anything you want about Authlogic in the {documentation}[http://authlogic.rubyforge.org], all that you need to do is understand the basic design behind it.
51
79
 
52
80
  That being said, there are 2 models involved during authentication. Your Authlogic model and your ActiveRecord model:
53
81
 
@@ -56,7 +84,7 @@ That being said, there are 2 models involved during authentication. Your Authlog
56
84
 
57
85
  Each of the above has its various sub modules that contain common logic. The sub modules are responsible for including *everything* related to it: configuration, class methods, instance methods, etc.
58
86
 
59
- For example, if you want to timeout users after a certain period of inactivity, you would look in <b>Authlogic::Session::Timeout</b>. To help you out, I listed the following "publicly relevant" modules with short descriptions. For the sake of brevity, there are more modules than listed here, the ones not listed are more for internal use, but you can easily read up on them in the {documentation}[http://authlogic.rubyforge.org].
87
+ For example, if you want to timeout users after a certain period of inactivity, you would look in <b>Authlogic::Session::Timeout</b>. To help you out, I listed the following publicly relevant modules with short descriptions. For the sake of brevity, there are more modules than listed here, the ones not listed are more for internal use, but you can easily read up on them in the {documentation}[http://authlogic.rubyforge.org].
60
88
 
61
89
  === Authlogic::ActsAsAuthentic sub modules
62
90
 
@@ -66,21 +94,21 @@ These modules are for the ActiveRecord side of things, the models that call acts
66
94
  * <b>Authlogic::ActsAsAuthentic::Email</b> - Handles everything related to the email field.
67
95
  * <b>Authlogic::ActsAsAuthentic::LoggedInStatus</b> - Provides handy named scopes and methods for determining if the user is logged in or out.
68
96
  * <b>Authlogic::ActsAsAuthentic::Login</b> - Handles everything related to the login field.
69
- * <b>Authlogic::ActsAsAuthentic::MagicColumns</b> - Handles everything related to the "magic" fields: login_count, failed_login_count, etc.
97
+ * <b>Authlogic::ActsAsAuthentic::MagicColumns</b> - Handles everything related to the "magic" fields: login_count, failed_login_count, last_request_at, etc.
70
98
  * <b>Authlogic::ActsAsAuthentic::Password</b> - This one is important. It handles encrypting your password, salting it, etc. It also has support for transitioning password algorithms.
71
99
  * <b>Authlogic::ActsAsAuthentic::PerishableToken</b> - Handles maintaining the perishable token field, also provides a class level method for finding record using the token.
72
100
  * <b>Authlogic::ActsAsAuthentic::PersistenceToken</b> - Handles maintaining the persistence token. This is the token stored in cookies and sessions to persist the users session.
73
101
  * <b>Authlogic::ActsAsAuthentic::RestfulAuthentication</b> - Provides configuration options to easily migrate from the restful_authentication plugin.
74
- * <b>Authlogic::ActsAsAuthentic::SessionMaintenance</b> - Handles automatically logging the user in. EX: a new user registers, automatically log them in.
102
+ * <b>Authlogic::ActsAsAuthentic::SessionMaintenance</b> - Handles automatic session maintenance. EX: a new user registers, automatically log them in. Or a user changes their password, update their session.
75
103
  * <b>Authlogic::ActsAsAuthentic::SingleAccessToken</b> - Handles maintaining the single access token.
76
- * <b>Authlogic::ActsAsAuthentic::ValidationsScope</b> - Allows you to scope validations, etc. Just like the :scope option for validates_uniqueness_of
104
+ * <b>Authlogic::ActsAsAuthentic::ValidationsScope</b> - Allows you to scope all validations, etc. Just like the :scope option for validates_uniqueness_of
77
105
 
78
106
  === Authlogic::Session sub modules
79
107
 
80
108
  These modules are for the models that extend Authlogic::Session::Base.
81
109
 
82
110
  * <b>Authlogic::Session::BruteForceProtection</b> - Disables accounts after a certain number of consecutive failed logins attempted.
83
- * <b>Authlogic::Session::Callbacks</b> - Your tools to extend, change, or add onto Authlogic. Lets you hook in and do just about anything you want. Start here if you want to write a plugin or add on for Authlogic
111
+ * <b>Authlogic::Session::Callbacks</b> - Your tools to extend, change, or add onto Authlogic. Lets you hook in and do just about anything you want. Start here if you want to write a plugin or add-on for Authlogic
84
112
  * <b>Authlogic::Session::Cookies</b> - Authentication via cookies.
85
113
  * <b>Authlogic::Session::Existence</b> - Creating, saving, and destroying objects.
86
114
  * <b>Authlogic::Session::HttpAuth</b> - Authentication via basic HTTP authentication.
@@ -92,7 +120,7 @@ These modules are for the models that extend Authlogic::Session::Base.
92
120
  * <b>Authlogic::Session::Persistence</b> - Persisting sessions / finding sessions.
93
121
  * <b>Authlogic::Session::Session</b> - Authentication via the session, the controller session that is.
94
122
  * <b>Authlogic::Session::Timeout</b> - Automatically logging out after a certain period of inactivity.
95
- * <b>Authlogic::Session::UnauthorizedRecord</b> - Handles authentication by passing an ActiveRecord object.
123
+ * <b>Authlogic::Session::UnauthorizedRecord</b> - Handles authentication by passing an ActiveRecord object directly.
96
124
  * <b>Authlogic::Session::Validation</b> - Validation / errors.
97
125
 
98
126
  === Miscellaneous modules
@@ -103,6 +131,7 @@ Miscellaneous modules that shared across the authentication process and are more
103
131
  * <b>Authlogic::CryptoProviders</b> - Contains various encryption algorithms that Authlogic uses, allowing you to choose your encryption method.
104
132
  * <b>Authlogic::I18n</b> - Acts JUST LIKE the rails I18n library, and provides internationalization to Authlogic.
105
133
  * <b>Authlogic::Random</b> - A simple class to generate random tokens.
134
+ * <b>Authlogic::Regex</b> - Contains regular expressions used in Authlogic. Such as those to validate the format of the log or email.
106
135
  * <b>Authlogic::TestCase</b> - Various helper methods for testing frameworks to help you test your code.
107
136
  * <b>Authlogic::Version</b> - A handy class for determine the version of Authlogic in a number of ways.
108
137
 
@@ -193,7 +222,7 @@ That being said, testing your code that uses Authlogic is easy. Since everyone u
193
222
 
194
223
  == Tell me quickly how Authlogic works
195
224
 
196
- Interested in how all of this all works? Think about an ActiveRecord model. A database connection must be established before you can use it. In the case of Authlogic, a controller connection must be established before you can use it. It uses that controller connection to modify cookies, the current session, login with HTTP basic, etc. It connects to the controller through a before filter that is automatically set in your controller which lets Authlogic know about the current controller object. Then Authlogic leverages that to do everything, it's a pretty simple design.
225
+ Interested in how all of this all works? Think about an ActiveRecord model. A database connection must be established before you can use it. In the case of Authlogic, a controller connection must be established before you can use it. It uses that controller connection to modify cookies, the current session, login with HTTP basic, etc. It connects to the controller through a before filter that is automatically set in your controller which lets Authlogic know about the current controller object. Then Authlogic leverages that to do everything, it's a pretty simple design. Nothing crazy going on, Authlogic is just leveraging the tools your framework provides in the controller object.
197
226
 
198
227
  == What sets Authlogic apart and why I created it
199
228
 
@@ -203,6 +232,7 @@ What inspired me to create Authlogic was the messiness of the current authentica
203
232
  2. <b>Easier to stay up-to-date.</b> To make my point, take a look at the commits to any other authentication solution, then look at the {commits for authlogic}[http://github.com/binarylogic/authlogic/commits/master]. How many commits could you easily start using if you already had an app using that solution? With an alternate solution, very few, if any. All of those cool new features and bug fixes are going to have be manually added or wait for your next application. Which is the main reason a generator is not suitable as an authentication solution. With Authlogic you can start using the latest code with a simple update of a gem. No generators, no mess.
204
233
  3. <b>It ties everything together on the domain level.</b> Take a new user registration for example, no reason to manually log the user in, authlogic handles this for you via callbacks. The same applies to a user changing their password. Authlogic handles maintaining the session for you.
205
234
  4. <b>No redundant tests.</b> Because Authlogic doesn't use generators, #1 also applies to tests. Authlogic is *thoroughly* tested for you. You don't go and test the internals of ActiveRecord in each of your apps do you? So why do the same for Authlogic? Your application tests should be for application specific code. Get rid of the noise and make your tests focused and concise, no reason to copy tests from app to app.
235
+ 5. <b>Framework agnostic</b>. Authlogic can be used in *any* ruby framework you want: Rails, Merb, Sinatra, Mack, your own framework, whatever. It's not tied down to Rails. It does this by abstracting itself from these framework's controllers by using a controller adapter. Thanks to {Rack}[http://rack.rubyforge.org/], there is a defined standard for controller structure, and that's what Authlogic's abstract adapter follows. So if your controller follows the rack standards, you don't need to do anything. Any place it deviates from this is solved by a simple adapter for your framework that closes these gaps. For an example, checkout the Authlogic::ControllerAdapters::MerbAdapter.
206
236
  5. <b>You are not restricted to a single session.</b> Think about Apple's me.com, where they need you to authenticate a second time before changing your billing information. Why not just create a second session for this? It works just like your initial session. Then your billing controller can require an "ultra secure" session.
207
237
  6. <b>Easily extendable.</b> One of the distinct advantages of using a library is the ability to use it's API, assuming it has one. Authlogic has an *excellent* public API, meaning it can easily be extended and grow beyond the core library. Checkout the "add ons" list above to see what I mean.
208
238
 
data/init.rb CHANGED
@@ -1 +1 @@
1
- require "authlogic"
1
+ require File.dirname(__FILE__) + "/rails/init.rb"
data/lib/authlogic.rb CHANGED
@@ -3,6 +3,7 @@ require "active_support"
3
3
  require File.dirname(__FILE__) + "/authlogic/version"
4
4
  require File.dirname(__FILE__) + "/authlogic/i18n"
5
5
  require File.dirname(__FILE__) + "/authlogic/random"
6
+ require File.dirname(__FILE__) + "/authlogic/regex"
6
7
 
7
8
  require File.dirname(__FILE__) + "/authlogic/controller_adapters/abstract_adapter"
8
9
  require File.dirname(__FILE__) + "/authlogic/controller_adapters/rails_adapter" if defined?(Rails)
@@ -68,7 +68,7 @@ module Authlogic
68
68
  inheritable_attributes.include?(key) ? read_inheritable_attribute(key) : []
69
69
  end
70
70
 
71
- def config(key, value, default_value = nil, read_value = nil)
71
+ def rw_config(key, value, default_value = nil, read_value = nil)
72
72
  if value == read_value
73
73
  inheritable_attributes.include?(key) ? read_inheritable_attribute(key) : default_value
74
74
  else
@@ -19,7 +19,7 @@ module Authlogic
19
19
  # * <tt>Default:</tt> :email, if it exists
20
20
  # * <tt>Accepts:</tt> Symbol
21
21
  def email_field(value = nil)
22
- config(:email_field, value, first_column_to_exist(nil, :email, :email_address))
22
+ rw_config(:email_field, value, first_column_to_exist(nil, :email, :email_address))
23
23
  end
24
24
  alias_method :email_field=, :email_field
25
25
 
@@ -28,7 +28,7 @@ module Authlogic
28
28
  # * <tt>Default:</tt> true
29
29
  # * <tt>Accepts:</tt> Boolean
30
30
  def validate_email_field(value = nil)
31
- config(:validate_email_field, value, true)
31
+ rw_config(:validate_email_field, value, true)
32
32
  end
33
33
  alias_method :validate_email_field=, :validate_email_field
34
34
 
@@ -41,7 +41,7 @@ module Authlogic
41
41
  # * <tt>Default:</tt> {:within => 6..100}
42
42
  # * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
43
43
  def validates_length_of_email_field_options(value = nil)
44
- config(:validates_length_of_email_field_options, value, {:within => 6..100})
44
+ rw_config(:validates_length_of_email_field_options, value, {:within => 6..100})
45
45
  end
46
46
  alias_method :validates_length_of_email_field_options=, :validates_length_of_email_field_options
47
47
 
@@ -62,10 +62,10 @@ module Authlogic
62
62
  # merge options into it. Checkout the convenience function merge_validates_format_of_email_field_options to merge
63
63
  # options.</b>
64
64
  #
65
- # * <tt>Default:</tt> {:with => email_regex, :message => I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}
65
+ # * <tt>Default:</tt> {:with => Authlogic::Regex.email, :message => I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}
66
66
  # * <tt>Accepts:</tt> Hash of options accepted by validates_format_of
67
67
  def validates_format_of_email_field_options(value = nil)
68
- config(:validates_format_of_email_field_options, value, {:with => email_regex, :message => I18n.t('error_messages.email_invalid', :default => "should look like an email address.")})
68
+ rw_config(:validates_format_of_email_field_options, value, {:with => Authlogic::Regex.email, :message => I18n.t('error_messages.email_invalid', :default => "should look like an email address.")})
69
69
  end
70
70
  alias_method :validates_format_of_email_field_options=, :validates_format_of_email_field_options
71
71
 
@@ -83,7 +83,7 @@ module Authlogic
83
83
  # * <tt>Default:</tt> {:case_sensitive => false, :scope => validations_scope, :if => "#{email_field}_changed?".to_sym}
84
84
  # * <tt>Accepts:</tt> Hash of options accepted by validates_uniqueness_of
85
85
  def validates_uniqueness_of_email_field_options(value = nil)
86
- config(:validates_uniqueness_of_email_field_options, value, {:case_sensitive => false, :scope => validations_scope, :if => "#{email_field}_changed?".to_sym})
86
+ rw_config(:validates_uniqueness_of_email_field_options, value, {:case_sensitive => false, :scope => validations_scope, :if => "#{email_field}_changed?".to_sym})
87
87
  end
88
88
  alias_method :validates_uniqueness_of_email_field_options=, :validates_uniqueness_of_email_field_options
89
89
 
@@ -91,15 +91,6 @@ module Authlogic
91
91
  def merge_validates_uniqueness_of_email_field_options(options = {})
92
92
  self.validates_uniqueness_of_email_field_options = validates_uniqueness_of_email_field_options.merge(options)
93
93
  end
94
-
95
- private
96
- def email_regex
97
- return @email_regex if @email_regex
98
- email_name_regex = '[\w\.%\+\-]+'
99
- domain_head_regex = '(?:[A-Z0-9\-]+\.)+'
100
- domain_tld_regex = '(?:[A-Z]{2,4}|museum|travel)'
101
- @email_regex = /\A#{email_name_regex}@#{domain_head_regex}#{domain_tld_regex}\z/i
102
- end
103
94
  end
104
95
 
105
96
  # All methods relating to the email field
@@ -19,7 +19,7 @@ module Authlogic
19
19
  # * <tt>Default:</tt> 10.minutes
20
20
  # * <tt>Accepts:</tt> Fixnum
21
21
  def logged_in_timeout(value = nil)
22
- config(:logged_in_timeout, (!value.nil? && value.to_i) || value, 10.minutes.to_i)
22
+ rw_config(:logged_in_timeout, (!value.nil? && value.to_i) || value, 10.minutes.to_i)
23
23
  end
24
24
  alias_method :logged_in_timeout=, :logged_in_timeout
25
25
  end
@@ -16,7 +16,7 @@ module Authlogic
16
16
  # * <tt>Default:</tt> :login or :username, if they exist
17
17
  # * <tt>Accepts:</tt> Symbol
18
18
  def login_field(value = nil)
19
- config(:login_field, value, first_column_to_exist(nil, :login, :username))
19
+ rw_config(:login_field, value, first_column_to_exist(nil, :login, :username))
20
20
  end
21
21
  alias_method :login_field=, :login_field
22
22
 
@@ -25,7 +25,7 @@ module Authlogic
25
25
  # * <tt>Default:</tt> true
26
26
  # * <tt>Accepts:</tt> Boolean
27
27
  def validate_login_field(value = nil)
28
- config(:validate_login_field, value, true)
28
+ rw_config(:validate_login_field, value, true)
29
29
  end
30
30
  alias_method :validate_login_field=, :validate_login_field
31
31
 
@@ -38,7 +38,7 @@ module Authlogic
38
38
  # * <tt>Default:</tt> {:within => 3..100}
39
39
  # * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
40
40
  def validates_length_of_login_field_options(value = nil)
41
- config(:validates_length_of_login_field_options, value, {:within => 3..100})
41
+ rw_config(:validates_length_of_login_field_options, value, {:within => 3..100})
42
42
  end
43
43
  alias_method :validates_length_of_login_field_options=, :validates_length_of_login_field_options
44
44
 
@@ -59,10 +59,10 @@ module Authlogic
59
59
  # merge options into it. Checkout the convenience function merge_validates_format_of_login_field_options to merge
60
60
  # options.</b>
61
61
  #
62
- # * <tt>Default:</tt> {:with => /\A\w[\w\.\-_@ ]+\z/, :message => I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")}
62
+ # * <tt>Default:</tt> {:with => Authlogic::Regex.login, :message => I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")}
63
63
  # * <tt>Accepts:</tt> Hash of options accepted by validates_format_of
64
64
  def validates_format_of_login_field_options(value = nil)
65
- config(:validates_format_of_login_field_options, value, {:with => /\A\w[\w\.+-_@ ]+\z/, :message => I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")})
65
+ rw_config(:validates_format_of_login_field_options, value, {:with => Authlogic::Regex.login, :message => I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")})
66
66
  end
67
67
  alias_method :validates_format_of_login_field_options=, :validates_format_of_login_field_options
68
68
 
@@ -80,7 +80,7 @@ module Authlogic
80
80
  # * <tt>Default:</tt> {:case_sensitive => false, :scope => validations_scope, :if => "#{login_field}_changed?".to_sym}
81
81
  # * <tt>Accepts:</tt> Hash of options accepted by validates_uniqueness_of
82
82
  def validates_uniqueness_of_login_field_options(value = nil)
83
- config(:validates_uniqueness_of_login_field_options, value, {:case_sensitive => false, :scope => validations_scope, :if => "#{login_field}_changed?".to_sym})
83
+ rw_config(:validates_uniqueness_of_login_field_options, value, {:case_sensitive => false, :scope => validations_scope, :if => "#{login_field}_changed?".to_sym})
84
84
  end
85
85
  alias_method :validates_uniqueness_of_login_field_options=, :validates_uniqueness_of_login_field_options
86
86
 
@@ -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
- config(:crypted_password_field, value, first_column_to_exist(nil, :crypted_password, :encrypted_password, :password_hash, :pw_hash))
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,7 +27,7 @@ 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
- config(:password_salt_field, value, first_column_to_exist(nil, :password_salt, :pw_salt, :salt))
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
 
@@ -37,7 +37,7 @@ module Authlogic
37
37
  # * <tt>Default:</tt> true
38
38
  # * <tt>Accepts:</tt> Boolean
39
39
  def require_password_confirmation(value = nil)
40
- config(:require_password_confirmation, value, true)
40
+ rw_config(:require_password_confirmation, value, true)
41
41
  end
42
42
  alias_method :require_password_confirmation=, :require_password_confirmation
43
43
 
@@ -53,7 +53,7 @@ module Authlogic
53
53
  # * <tt>Default:</tt> true
54
54
  # * <tt>Accepts:</tt> Boolean
55
55
  def ignore_blank_passwords(value = nil)
56
- config(:ignore_blank_passwords, value, true)
56
+ rw_config(:ignore_blank_passwords, value, true)
57
57
  end
58
58
  alias_method :ignore_blank_passwords=, :ignore_blank_passwords
59
59
 
@@ -70,7 +70,7 @@ module Authlogic
70
70
  # * <tt>Default:</tt> true
71
71
  # * <tt>Accepts:</tt> Boolean
72
72
  def check_passwords_against_database(value = nil)
73
- config(:check_passwords_against_database, value, true)
73
+ rw_config(:check_passwords_against_database, value, true)
74
74
  end
75
75
  alias_method :check_passwords_against_database=, :check_passwords_against_database
76
76
 
@@ -79,7 +79,7 @@ module Authlogic
79
79
  # * <tt>Default:</tt> true
80
80
  # * <tt>Accepts:</tt> Boolean
81
81
  def validate_password_field(value = nil)
82
- config(:validate_password_field, value, true)
82
+ rw_config(:validate_password_field, value, true)
83
83
  end
84
84
  alias_method :validate_password_field=, :validate_password_field
85
85
 
@@ -92,7 +92,7 @@ module Authlogic
92
92
  # * <tt>Default:</tt> {:minimum => 4, :if => :require_password?}
93
93
  # * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
94
94
  def validates_length_of_password_field_options(value = nil)
95
- config(:validates_length_of_password_field_options, value, {:minimum => 4, :if => :require_password?})
95
+ rw_config(:validates_length_of_password_field_options, value, {:minimum => 4, :if => :require_password?})
96
96
  end
97
97
  alias_method :validates_length_of_password_field_options=, :validates_length_of_password_field_options
98
98
 
@@ -110,13 +110,13 @@ module Authlogic
110
110
  # A hash of options for the validates_confirmation_of call for the password field. Allows you to change this however you want.
111
111
  #
112
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_login_field_options to merge
113
+ # merge options into it. Checkout the convenience function merge_validates_length_of_password_field_options to merge
114
114
  # options.</b>
115
115
  #
116
- # * <tt>Default:</tt> {:minimum => 4, :if => "#{password_salt_field}_changed?".to_sym}
116
+ # * <tt>Default:</tt> {:if => :require_password?}
117
117
  # * <tt>Accepts:</tt> Hash of options accepted by validates_confirmation_of
118
118
  def validates_confirmation_of_password_field_options(value = nil)
119
- config(:validates_confirmation_of_password_field_options, value, {:minimum => 4, :if => :require_password?})
119
+ rw_config(:validates_confirmation_of_password_field_options, value, {:if => :require_password?})
120
120
  end
121
121
  alias_method :validates_confirmation_of_password_field_options=, :validates_confirmation_of_password_field_options
122
122
 
@@ -128,13 +128,13 @@ module Authlogic
128
128
  # A hash of options for the validates_length_of call for the password_confirmation field. Allows you to change this however you want.
129
129
  #
130
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_login_field_options to merge
131
+ # merge options into it. Checkout the convenience function merge_validates_length_of_password_field_options to merge
132
132
  # options.</b>
133
133
  #
134
134
  # * <tt>Default:</tt> validates_length_of_password_field_options
135
135
  # * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
136
136
  def validates_length_of_password_confirmation_field_options(value = nil)
137
- config(:validates_length_of_password_confirmation_field_options, value, validates_length_of_password_field_options)
137
+ rw_config(:validates_length_of_password_confirmation_field_options, value, validates_length_of_password_field_options)
138
138
  end
139
139
  alias_method :validates_length_of_password_confirmation_field_options=, :validates_length_of_password_confirmation_field_options
140
140
 
@@ -149,7 +149,7 @@ module Authlogic
149
149
  # * <tt>Default:</tt> CryptoProviders::Sha512
150
150
  # * <tt>Accepts:</tt> Class
151
151
  def crypto_provider(value = nil)
152
- config(:crypto_provider, value, CryptoProviders::Sha512)
152
+ rw_config(:crypto_provider, value, CryptoProviders::Sha512)
153
153
  end
154
154
  alias_method :crypto_provider=, :crypto_provider
155
155
 
@@ -165,7 +165,7 @@ module Authlogic
165
165
  # * <tt>Default:</tt> nil
166
166
  # * <tt>Accepts:</tt> Class or Array
167
167
  def transition_from_crypto_providers(value = nil)
168
- config(:transition_from_crypto_providers, (!value.nil? && [value].flatten.compact) || value, [])
168
+ rw_config(:transition_from_crypto_providers, (!value.nil? && [value].flatten.compact) || value, [])
169
169
  end
170
170
  alias_method :transition_from_crypto_providers=, :transition_from_crypto_providers
171
171
  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
- config(:perishable_token_valid_for, (!value.nil? && value.to_i) || value, 10.minutes.to_i)
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
- config(:disable_perishable_token_maintenance, value, false)
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
@@ -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 = config(:act_like_restful_authentication, value, false)
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 = config(:transition_from_restful_authentication, value, false)
32
+ r = rw_config(:transition_from_restful_authentication, value, false)
32
33
  set_restful_authentication_config if value
33
34
  r
34
35
  end
@@ -33,7 +33,7 @@ module Authlogic
33
33
  # * <tt>Default:</tt> true
34
34
  # * <tt>Accepts:</tt> Boolean
35
35
  def maintain_sessions(value = nil)
36
- config(:maintain_sessions, value, true)
36
+ rw_config(:maintain_sessions, value, true)
37
37
  end
38
38
  alias_method :maintain_sessions=, :maintain_sessions
39
39
 
@@ -44,7 +44,7 @@ module Authlogic
44
44
  # * <tt>Default:</tt> [nil]
45
45
  # * <tt>Accepts:</tt> Array
46
46
  def session_ids(value = nil)
47
- config(:session_ids, value, [nil])
47
+ rw_config(:session_ids, value, [nil])
48
48
  end
49
49
  alias_method :session_ids=, :session_ids
50
50
 
@@ -54,7 +54,7 @@ module Authlogic
54
54
  # * <tt>Accepts:</tt> Class
55
55
  def session_class(value = nil)
56
56
  const = "#{base_class.name}Session".constantize rescue nil
57
- config(:session_class, value, const)
57
+ rw_config(:session_class, value, const)
58
58
  end
59
59
  alias_method :session_class=, :session_class
60
60
  end
@@ -20,7 +20,7 @@ module Authlogic
20
20
  # * <tt>Default:</tt> false
21
21
  # * <tt>Accepts:</tt> Boolean
22
22
  def change_single_access_token_with_password(value = nil)
23
- config(:change_single_access_token_with_password, value, false)
23
+ rw_config(:change_single_access_token_with_password, value, false)
24
24
  end
25
25
  alias_method :change_single_access_token_with_password=, :change_single_access_token_with_password
26
26
  end
@@ -23,7 +23,7 @@ module Authlogic
23
23
  # * <tt>Default:</tt> nil
24
24
  # * <tt>Accepts:</tt> Symbol or Array of symbols
25
25
  def validations_scope(value = nil)
26
- config(:validations_scope, value)
26
+ rw_config(:validations_scope, value)
27
27
  end
28
28
  alias_method :validations_scope=, :validations_scope
29
29
  end
@@ -50,6 +50,14 @@ module Authlogic
50
50
  controller.send(:single_access_allowed?)
51
51
  end
52
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?)
59
+ end
60
+
53
61
  private
54
62
  def method_missing(id, *args, &block)
55
63
  controller.send(id, *args, &block)
@@ -29,7 +29,7 @@ module Authlogic
29
29
  # authlogic:
30
30
  # error_messages:
31
31
  # login_blank: can not be blank
32
- # login_not_found: does not exist
32
+ # login_not_found: is not valid
33
33
  # login_invalid: should use only letters, numbers, spaces, and .-_@ please.
34
34
  # consecutive_failed_logins_limit_exceeded: Consecutive failed logins limit exceeded, account is disabled.
35
35
  # email_invalid: should look like an email address.
@@ -37,7 +37,7 @@ module Authlogic
37
37
  # * <tt>Default:</tt> 50
38
38
  # * <tt>Accepts:</tt> Integer, set to 0 to disable
39
39
  def consecutive_failed_logins_limit(value = nil)
40
- config(:consecutive_failed_logins_limit, value, 50)
40
+ rw_config(:consecutive_failed_logins_limit, value, 50)
41
41
  end
42
42
  alias_method :consecutive_failed_logins_limit=, :consecutive_failed_logins_limit
43
43
 
@@ -46,23 +46,26 @@ module Authlogic
46
46
  # * <tt>Default:</tt> 2.hours
47
47
  # * <tt>Accepts:</tt> Fixnum, set to 0 for permanent ban
48
48
  def failed_login_ban_for(value = nil)
49
- config(:failed_login_ban_for, (!value.nil? && value) || value, 2.hours.to_i)
49
+ rw_config(:failed_login_ban_for, (!value.nil? && value) || value, 2.hours.to_i)
50
50
  end
51
51
  alias_method :failed_login_ban_for=, :failed_login_ban_for
52
52
  end
53
53
 
54
54
  # The methods available for an Authlogic::Session::Base object that make up the brute force protection feature.
55
55
  module InstanceMethods
56
+ # Returns true when the consecutive_failed_logins_limit has been exceeded and is being temporarily banned.
57
+ # Notice the word temporary, the user will not be permanently banned unless you choose to do so with configuration.
58
+ # By default they will be banned for 2 hours. During that 2 hour period this method will return true.
59
+ def being_brute_force_protected?
60
+ exceeded_failed_logins_limit? && (failed_login_ban_for <= 0 || (attempted_record.respond_to?(:updated_at) && attempted_record.updated_at >= failed_login_ban_for.seconds.ago))
61
+ end
62
+
56
63
  private
57
64
  def exceeded_failed_logins_limit?
58
65
  !attempted_record.nil? && attempted_record.respond_to?(:failed_login_count) && consecutive_failed_logins_limit > 0 &&
59
66
  attempted_record.failed_login_count && attempted_record.failed_login_count >= consecutive_failed_logins_limit
60
67
  end
61
68
 
62
- def being_brute_force_protected?
63
- exceeded_failed_logins_limit? && (failed_login_ban_for <= 0 || (attempted_record.respond_to?(:updated_at) && attempted_record.updated_at >= failed_login_ban_for.seconds.ago))
64
- end
65
-
66
69
  def reset_failed_login_count?
67
70
  exceeded_failed_logins_limit? && !being_brute_force_protected?
68
71
  end
@@ -26,7 +26,7 @@ module Authlogic
26
26
  # * <tt>Default:</tt> "#{klass_name.underscore}_credentials"
27
27
  # * <tt>Accepts:</tt> String
28
28
  def cookie_key(value = nil)
29
- config(:cookie_key, value, "#{klass_name.underscore}_credentials")
29
+ rw_config(:cookie_key, value, "#{klass_name.underscore}_credentials")
30
30
  end
31
31
  alias_method :cookie_key=, :cookie_key
32
32
 
@@ -35,7 +35,7 @@ module Authlogic
35
35
  # * <tt>Default:</tt> false
36
36
  # * <tt>Accepts:</tt> Boolean
37
37
  def remember_me(value = nil)
38
- config(:remember_me, value, false)
38
+ rw_config(:remember_me, value, false)
39
39
  end
40
40
  alias_method :remember_me=, :remember_me
41
41
 
@@ -44,7 +44,7 @@ module Authlogic
44
44
  # * <tt>Default:</tt> 3.months
45
45
  # * <tt>Accepts:</tt> Integer, length of time in seconds, such as 60 or 3.months
46
46
  def remember_me_for(value = :_read)
47
- config(:remember_me_for, value, 3.months, :_read)
47
+ rw_config(:remember_me_for, value, 3.months, :_read)
48
48
  end
49
49
  alias_method :remember_me_for=, :remember_me_for
50
50
  end
@@ -13,7 +13,7 @@ module Authlogic
13
13
 
14
14
  module ClassMethods
15
15
  private
16
- def config(key, value, default_value = nil, read_value = nil)
16
+ def rw_config(key, value, default_value = nil, read_value = nil)
17
17
  if value == read_value
18
18
  return read_inheritable_attribute(key) if inheritable_attributes.include?(key)
19
19
  write_inheritable_attribute(key, default_value)
@@ -25,7 +25,7 @@ module Authlogic
25
25
  # * <tt>Default:</tt> true
26
26
  # * <tt>Accepts:</tt> Boolean
27
27
  def allow_http_basic_auth(value = nil)
28
- config(:allow_http_basic_auth, value, true)
28
+ rw_config(:allow_http_basic_auth, value, true)
29
29
  end
30
30
  alias_method :allow_http_basic_auth=, :allow_http_basic_auth
31
31
  end
@@ -31,7 +31,7 @@ module Authlogic
31
31
  # * <tt>Default:</tt> 0
32
32
  # * <tt>Accepts:</tt> integer representing time in seconds
33
33
  def last_request_at_threshold(value = nil)
34
- config(:last_request_at_threshold, value, 0)
34
+ rw_config(:last_request_at_threshold, value, 0)
35
35
  end
36
36
  alias_method :last_request_at_threshold=, :last_request_at_threshold
37
37
  end
@@ -61,8 +61,24 @@ module Authlogic
61
61
  end
62
62
  end
63
63
 
64
- def set_last_request_at?
65
- record && record.class.column_names.include?("last_request_at") && (record.last_request_at.blank? || last_request_at_threshold.to_i.seconds.ago >= record.last_request_at)
64
+ # This method lets authlogic know whether it should allow the last_request_at field to be updated
65
+ # with the current time (Time.now). One thing to note here is that it also checks for the existence of a
66
+ # last_request_update_allowed? method in your controller. This allows you to control this method pragmatically
67
+ # in your controller.
68
+ #
69
+ # For example, what if you had a javascript function that polled the server updating how much time is left in their
70
+ # session before it times out. Obviously you would want to ignore this request, because then the user would never time out.
71
+ # So you can do something like this in your controller:
72
+ #
73
+ # def last_request_update_allowed?
74
+ # action_name =! "update_session_time_left"
75
+ # end
76
+ #
77
+ # You can do whatever you want with that method.
78
+ def set_last_request_at? # :doc:
79
+ return false if !record || !klass.column_names.include?("last_request_at")
80
+ return controller.last_request_update_allowed? if controller.responds_to_last_request_update_allowed?
81
+ record.last_request_at.blank? || last_request_at_threshold.to_i.seconds.ago >= record.last_request_at
66
82
  end
67
83
 
68
84
  def set_last_request_at
@@ -30,7 +30,7 @@ module Authlogic
30
30
  # * <tt>Default:</tt> false
31
31
  # * <tt>Accepts:</tt> Boolean
32
32
  def disable_magic_states(value = nil)
33
- config(:disable_magic_states, value, false)
33
+ rw_config(:disable_magic_states, value, false)
34
34
  end
35
35
  alias_method :disable_magic_states=, :disable_magic_states
36
36
  end
@@ -43,7 +43,7 @@ module Authlogic
43
43
  # * <tt>Default:</tt> cookie_key
44
44
  # * <tt>Accepts:</tt> String
45
45
  def params_key(value = nil)
46
- config(:params_key, value, cookie_key)
46
+ rw_config(:params_key, value, cookie_key)
47
47
  end
48
48
  alias_method :params_key=, :params_key
49
49
 
@@ -53,7 +53,7 @@ module Authlogic
53
53
  # * <tt>Default:</tt> ["application/rss+xml", "application/atom+xml"]
54
54
  # * <tt>Accepts:</tt> String of a request type, or :all or :any to allow single access authentication for any and all request types
55
55
  def single_access_allowed_request_types(value = nil)
56
- config(:single_access_allowed_request_types, value, ["application/rss+xml", "application/atom+xml"])
56
+ rw_config(:single_access_allowed_request_types, value, ["application/rss+xml", "application/atom+xml"])
57
57
  end
58
58
  alias_method :single_access_allowed_request_types=, :single_access_allowed_request_types
59
59
  end
@@ -29,16 +29,45 @@ module Authlogic
29
29
  # end
30
30
  # end
31
31
  #
32
- # Now just specifcy the name of this method for this configuration option and you are all set. You can do anything you want here. Maybe you allow users to have multiple logins
32
+ # Now just specify the name of this method for this configuration option and you are all set. You can do anything you want here. Maybe you allow users to have multiple logins
33
33
  # and you want to search a has_many relationship, etc. The sky is the limit.
34
34
  #
35
35
  # * <tt>Default:</tt> "find_by_smart_case_login_field"
36
36
  # * <tt>Accepts:</tt> Symbol or String
37
37
  def find_by_login_method(value = nil)
38
- config(:find_by_login_method, value, "find_by_smart_case_login_field")
38
+ rw_config(:find_by_login_method, value, "find_by_smart_case_login_field")
39
39
  end
40
40
  alias_method :find_by_login_method=, :find_by_login_method
41
41
 
42
+ # The text used to identify credentials (username/password) combination when a bad login attempt occurs.
43
+ # When you show error messages for a bad login, it's considered good security practice to hide which field
44
+ # the user has entered incorrectly (the login field or the password field). For a full explanation, see
45
+ # http://www.gnucitizen.org/blog/username-enumeration-vulnerabilities/
46
+ #
47
+ # Example of use:
48
+ #
49
+ # class UserSession < Authlogic::Session::Base
50
+ # generalize_credentials_error_messages true
51
+ # end
52
+ #
53
+ # This would make the error message for bad logins and bad passwords look identical:
54
+ #
55
+ # Login/Password combination is not valid
56
+ #
57
+ # The downside to enabling this is that is can be too vague for a user that has a hard time remembering
58
+ # their username and password combinations. It also disables the ability to to highlight the field
59
+ # with the error when you use form_for.
60
+ #
61
+ # If you are developing an app where security is an extreme priority (such as a financial application),
62
+ # then you should enable this. Otherwise, leaving this off is fine.
63
+ #
64
+ # * <tt>Default</tt> false
65
+ # * <tt>Accepts:</tt> Boolean
66
+ def generalize_credentials_error_messages(value = nil)
67
+ rw_config(:generalize_credentials_error_messages, value, false)
68
+ end
69
+ alias_method :generalize_credentials_error_messages=, :generalize_credentials_error_messages
70
+
42
71
  # The name of the method you want Authlogic to create for storing the login / username. Keep in mind this is just for your
43
72
  # Authlogic::Session, if you want it can be something completely different than the field in your model. So if you wanted people to
44
73
  # login with a field called "login" and then find users by email this is compeltely doable. See the find_by_login_method configuration
@@ -47,7 +76,7 @@ module Authlogic
47
76
  # * <tt>Default:</tt> klass.login_field || klass.email_field
48
77
  # * <tt>Accepts:</tt> Symbol or String
49
78
  def login_field(value = nil)
50
- config(:login_field, value, klass.login_field || klass.email_field)
79
+ rw_config(:login_field, value, klass.login_field || klass.email_field)
51
80
  end
52
81
  alias_method :login_field=, :login_field
53
82
 
@@ -56,7 +85,7 @@ module Authlogic
56
85
  # * <tt>Default:</tt> :password
57
86
  # * <tt>Accepts:</tt> Symbol or String
58
87
  def password_field(value = nil)
59
- config(:password_field, value, login_field && :password)
88
+ rw_config(:password_field, value, login_field && :password)
60
89
  end
61
90
  alias_method :password_field=, :password_field
62
91
 
@@ -65,7 +94,7 @@ module Authlogic
65
94
  # * <tt>Default:</tt> "valid_#{password_field}?"
66
95
  # * <tt>Accepts:</tt> Symbol or String
67
96
  def verify_password_method(value = nil)
68
- config(:verify_password_method, value, "valid_#{password_field}?")
97
+ rw_config(:verify_password_method, value, "valid_#{password_field}?")
69
98
  end
70
99
  alias_method :verify_password_method=, :verify_password_method
71
100
  end
@@ -85,7 +114,7 @@ module Authlogic
85
114
 
86
115
  self.class.class_eval <<-"end_eval", __FILE__, __LINE__
87
116
  private
88
- # The password should not be accessible publicly. This way forms using form_for don't fill the password with the attempted password. The prevent this we just create this method that is private.
117
+ # The password should not be accessible publicly. This way forms using form_for don't fill the password with the attempted password. To prevent this we just create this method that is private.
89
118
  def protected_#{password_field}
90
119
  @#{password_field}
91
120
  end
@@ -98,6 +127,7 @@ module Authlogic
98
127
  super
99
128
  end
100
129
 
130
+ # Returns the login_field / password_field credentials combination in hash form.
101
131
  def credentials
102
132
  if authenticating_with_password?
103
133
  details = {}
@@ -109,6 +139,7 @@ module Authlogic
109
139
  end
110
140
  end
111
141
 
142
+ # Accepts the login_field / password_field credentials combination in hash form.
112
143
  def credentials=(value)
113
144
  super
114
145
  values = value.is_a?(Array) ? value : [value]
@@ -126,19 +157,19 @@ module Authlogic
126
157
  end
127
158
 
128
159
  def validate_by_password
129
- errors.add(login_field, I18n.t('error_messages.login_blank', :default => "can not be blank")) if send(login_field).blank?
130
- errors.add(password_field, I18n.t('error_messages.password_blank', :default => "can not be blank")) if send("protected_#{password_field}").blank?
160
+ errors.add(login_field, I18n.t('error_messages.login_blank', :default => "cannot be blank")) if send(login_field).blank?
161
+ errors.add(password_field, I18n.t('error_messages.password_blank', :default => "cannot be blank")) if send("protected_#{password_field}").blank?
131
162
  return if errors.count > 0
132
163
 
133
164
  self.attempted_record = search_for_record(find_by_login_method, send(login_field))
134
165
 
135
166
  if attempted_record.blank?
136
- errors.add(login_field, I18n.t('error_messages.login_not_found', :default => "does not exist"))
167
+ generalize_credentials_error_messages? ? add_general_credentials_error : errors.add(login_field, I18n.t('error_messages.login_not_found', :default => "is not valid"))
137
168
  return
138
169
  end
139
170
 
140
171
  if !attempted_record.send(verify_password_method, send("protected_#{password_field}"))
141
- errors.add(password_field, I18n.t('error_messages.password_invalid', :default => "is not valid"))
172
+ generalize_credentials_error_messages? ? add_general_credentials_error : errors.add(password_field, I18n.t('error_messages.password_invalid', :default => "is not valid"))
142
173
  return
143
174
  end
144
175
  end
@@ -151,6 +182,14 @@ module Authlogic
151
182
  self.class.login_field
152
183
  end
153
184
 
185
+ def add_general_credentials_error
186
+ errors.add_to_base(I18n.t('error_messages.general_credentials_error', :default => "#{login_field.to_s.humanize}/Password combination is not valid"))
187
+ end
188
+
189
+ def generalize_credentials_error_messages?
190
+ self.class.generalize_credentials_error_messages == true
191
+ end
192
+
154
193
  def password_field
155
194
  self.class.password_field
156
195
  end
@@ -20,7 +20,7 @@ module Authlogic
20
20
  # * <tt>Default:</tt> cookie_key
21
21
  # * <tt>Accepts:</tt> Symbol or String
22
22
  def session_key(value = nil)
23
- config(:session_key, value, cookie_key)
23
+ rw_config(:session_key, value, cookie_key)
24
24
  end
25
25
  alias_method :session_key=, :session_key
26
26
  end
@@ -48,7 +48,7 @@ module Authlogic
48
48
  # * <tt>Default:</tt> false
49
49
  # * <tt>Accepts:</tt> Boolean
50
50
  def logout_on_timeout(value = nil)
51
- config(:logout_on_timeout, value, false)
51
+ rw_config(:logout_on_timeout, value, false)
52
52
  end
53
53
  alias_method :logout_on_timeout=, :logout_on_timeout
54
54
  end
@@ -35,6 +35,20 @@ module Authlogic
35
35
  # Authlogic::Session::Activation::NotActivatedError any time you try to instantiate an object without a "connection".
36
36
  # So before you do anything with Authlogic, you need to activate / connect Authlogic. Let's walk through how to do this in tests:
37
37
  #
38
+ # === Fixtures / Factories
39
+ #
40
+ # Creating users via fixtures / factories is easy. Here's an example of a fixture:
41
+ #
42
+ # ben:
43
+ # email: whatever@whatever.com
44
+ # password_salt: <%= salt = Authlogic::Random.hex_token %>
45
+ # crypted_password: <%= Authlogic::CryptoProviders::Sha512.encrypt("benrocks" + salt) %>
46
+ # persistence_token: <%= Authlogic::Random.hex_token %>
47
+ # single_access_token: <%= Authlogic::Random.friendly_token %>
48
+ # perishable_token: <%= Authlogic::Random.friendly_token %>
49
+ #
50
+ # Notice the crypted_password value. Just supplement that with whatever crypto provider you are using, if you are not using the default.
51
+ #
38
52
  # === Functional tests
39
53
  #
40
54
  # Activating Authlogic isn't a problem here, because making a request will activate Authlogic for you. The problem is
@@ -12,7 +12,7 @@ module Authlogic
12
12
  end
13
13
 
14
14
  private
15
- def method_missiing(*args, &block)
15
+ def method_missing(*args, &block)
16
16
  end
17
17
  end
18
18
  end
@@ -41,7 +41,7 @@ module Authlogic # :nodoc:
41
41
 
42
42
  MAJOR = 2
43
43
  MINOR = 0
44
- TINY = 11
44
+ TINY = 12
45
45
 
46
46
  # The current version as a Version instance
47
47
  CURRENT = new(MAJOR, MINOR, TINY)
@@ -33,7 +33,7 @@ module ActsAsAuthenticTest
33
33
  end
34
34
 
35
35
  def test_validates_format_of_email_field_options_config
36
- default = {:with => User.send(:email_regex), :message => I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}
36
+ default = {:with => Authlogic::Regex.email, :message => I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}
37
37
  assert_equal default, User.validates_format_of_email_field_options
38
38
  assert_equal default, Employee.validates_format_of_email_field_options
39
39
 
@@ -33,7 +33,7 @@ module ActsAsAuthenticTest
33
33
  end
34
34
 
35
35
  def test_validates_format_of_login_field_options_config
36
- default = {:with => /\A\w[\w\.+-_@ ]+\z/, :message => I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")}
36
+ default = {:with => /\A\w[\w\.+\-_@ ]+\z/, :message => I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")}
37
37
  assert_equal default, User.validates_format_of_login_field_options
38
38
  assert_equal default, Employee.validates_format_of_login_field_options
39
39
 
@@ -62,7 +62,7 @@ module ActsAsAuthenticTest
62
62
  end
63
63
 
64
64
  def test_validates_confirmation_of_password_field_options_config
65
- default = {:minimum => 4, :if => :require_password?}
65
+ default = {:if => :require_password?}
66
66
  assert_equal default, User.validates_confirmation_of_password_field_options
67
67
  assert_equal default, Employee.validates_confirmation_of_password_field_options
68
68
 
@@ -129,9 +129,6 @@ module ActsAsAuthenticTest
129
129
  def test_validates_length_of_password_confirmation
130
130
  u = User.new
131
131
 
132
- assert !u.valid?
133
- assert u.errors.on(:password_confirmation)
134
-
135
132
  u.password = "test"
136
133
  u.password_confirmation = ""
137
134
  assert !u.valid?
@@ -19,6 +19,14 @@ module SessionTest
19
19
  assert_equal "valid_password?", UserSession.verify_password_method
20
20
  end
21
21
 
22
+ def test_generalize_credentials_error_messages
23
+ UserSession.generalize_credentials_error_messages = true
24
+ assert UserSession.generalize_credentials_error_messages
25
+
26
+ UserSession.generalize_credentials_error_messages false
27
+ assert !UserSession.generalize_credentials_error_messages
28
+ end
29
+
22
30
  def test_login_field
23
31
  UserSession.configured_password_methods = false
24
32
  UserSession.login_field = :saweet
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authlogic
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.11
4
+ version: 2.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Johnson of Binary Logic
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-25 00:00:00 -04:00
12
+ date: 2009-05-13 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 1.12.1
33
+ version: 1.12.2
34
34
  version:
35
35
  description: A clean, simple, and unobtrusive ruby authentication solution.
36
36
  email: bjohnson@binarylogic.com
@@ -161,6 +161,8 @@ files:
161
161
  - test/test_helper.rb
162
162
  has_rdoc: true
163
163
  homepage: http://github.com/binarylogic/authlogic
164
+ licenses: []
165
+
164
166
  post_install_message:
165
167
  rdoc_options:
166
168
  - --main
@@ -182,9 +184,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
182
184
  requirements: []
183
185
 
184
186
  rubyforge_project: authlogic
185
- rubygems_version: 1.3.1
187
+ rubygems_version: 1.3.3
186
188
  signing_key:
187
- specification_version: 2
189
+ specification_version: 3
188
190
  summary: A clean, simple, and unobtrusive ruby authentication solution.
189
191
  test_files:
190
192
  - test/authenticates_many_test.rb