authlogic 2.0.13 → 2.0.14

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.

@@ -1,3 +1,10 @@
1
+ == 2.0.14 released 2009-6-13
2
+
3
+ * Fixed issue with using brute force protection AND generalize_credentials_error_messages. Brute force protection was looking to see if there were password errors, which generalize_credentials_error_messages was obfuscating. This is all fixed now though thanks to a handy article on Microsoft (http://support.microsoft.com/kb/168702), method #2, it works every time.
4
+ * Added db_setup? method to avoid errors during rake tasks where the db might not be set up. Ex: migrations
5
+ * Stop using errors.on(key) since that is now deprecated in Rails. Use errors[key] instead.
6
+ * Use valid_password? for the method name to validate a password instead of valid_#{password_field}?.
7
+
1
8
  == 2.0.13 released 2009-5-13
2
9
 
3
10
  * Add authlogic/regex.rb to manifest
@@ -66,6 +66,7 @@ If you find a bug or a problem please post it on lighthouse. If you need help wi
66
66
 
67
67
  * <b>Authlogic OpenID addon:</b> http://github.com/binarylogic/authlogic_openid
68
68
  * <b>Authlogic LDAP addon:</b> http://github.com/binarylogic/authlogic_ldap
69
+ * <b>Authlogic Facebook Connect:</b> http://github.com/kalasjocke/authlogic_facebook_connect
69
70
 
70
71
  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.
71
72
 
@@ -25,11 +25,7 @@ module Authlogic
25
25
  # See the various sub modules for the configuration they provide.
26
26
  def acts_as_authentic(unsupported_options = nil, &block)
27
27
  # Stop all configuration if the DB is not set up
28
- begin
29
- column_names
30
- rescue Exception
31
- return
32
- end
28
+ return if !db_setup?
33
29
 
34
30
  raise ArgumentError.new("You are using the old v1.X.X configuration method for Authlogic. Instead of " +
35
31
  "passing a hash of configuration options to acts_as_authentic, pass a block: acts_as_authentic { |c| c.my_option = my_value }") if !unsupported_options.nil?
@@ -68,6 +64,15 @@ module Authlogic
68
64
  inheritable_attributes.include?(key) ? read_inheritable_attribute(key) : []
69
65
  end
70
66
 
67
+ def db_setup?
68
+ begin
69
+ column_names
70
+ true
71
+ rescue Exception
72
+ false
73
+ end
74
+ end
75
+
71
76
  def rw_config(key, value, default_value = nil, read_value = nil)
72
77
  if value == read_value
73
78
  inheritable_attributes.include?(key) ? read_inheritable_attribute(key) : default_value
@@ -77,7 +82,9 @@ module Authlogic
77
82
  end
78
83
 
79
84
  def first_column_to_exist(*columns_to_check)
80
- columns_to_check.each { |column_name| return column_name.to_sym if column_names.include?(column_name.to_s) }
85
+ if db_setup?
86
+ columns_to_check.each { |column_name| return column_name.to_sym if column_names.include?(column_name.to_s) }
87
+ end
81
88
  columns_to_check.first && columns_to_check.first.to_sym
82
89
  end
83
90
  end
@@ -60,7 +60,7 @@ module Authlogic
60
60
  # If you want to use a different timeout value, just pass it as the second parameter:
61
61
  #
62
62
  # User.find_using_perishable_token(token, 1.hour)
63
- def find_using_perishable_token(token, age = perishable_token_valid_for)
63
+ def find_using_perishable_token(token, age = self.perishable_token_valid_for)
64
64
  return if token.blank?
65
65
  age = age.to_i
66
66
 
@@ -76,7 +76,7 @@ module Authlogic
76
76
 
77
77
  def validate_failed_logins
78
78
  errors.clear # Clear all other error messages, as they are irrelevant at this point and can only provide additional information that is not needed
79
- errors.add_to_base(I18n.t('error_messages.consecutive_failed_logins_limit_exceeded', :default => "Consecutive failed logins limit exceeded, account is disabled."))
79
+ errors.add(:base, I18n.t('error_messages.consecutive_failed_logins_limit_exceeded', :default => "Consecutive failed logins limit exceeded, account is disabled."))
80
80
  end
81
81
 
82
82
  def consecutive_failed_logins_limit
@@ -40,7 +40,7 @@ module Authlogic
40
40
  module InstanceMethods
41
41
  private
42
42
  def increase_failed_login_count
43
- if errors.on(password_field) && attempted_record.respond_to?(:failed_login_count)
43
+ if invalid_password? && attempted_record.respond_to?(:failed_login_count)
44
44
  attempted_record.failed_login_count ||= 0
45
45
  attempted_record.failed_login_count += 1
46
46
  end
@@ -46,7 +46,7 @@ module Authlogic
46
46
  return true if attempted_record.nil?
47
47
  [:active, :approved, :confirmed].each do |required_status|
48
48
  if attempted_record.respond_to?("#{required_status}?") && !attempted_record.send("#{required_status}?")
49
- errors.add_to_base(I18n.t("error_messages.not_#{required_status}", :default => "Your account is not #{required_status}"))
49
+ errors.add(:base, I18n.t("error_messages.not_#{required_status}", :default => "Your account is not #{required_status}"))
50
50
  return false
51
51
  end
52
52
  end
@@ -91,10 +91,10 @@ module Authlogic
91
91
 
92
92
  # The name of the method in your model used to verify the password. This should be an instance method. It should also be prepared to accept a raw password and a crytped password.
93
93
  #
94
- # * <tt>Default:</tt> "valid_#{password_field}?"
94
+ # * <tt>Default:</tt> "valid_password?"
95
95
  # * <tt>Accepts:</tt> Symbol or String
96
96
  def verify_password_method(value = nil)
97
- rw_config(:verify_password_method, value, "valid_#{password_field}?")
97
+ rw_config(:verify_password_method, value, "valid_password?")
98
98
  end
99
99
  alias_method :verify_password_method=, :verify_password_method
100
100
  end
@@ -151,12 +151,18 @@ module Authlogic
151
151
  end
152
152
  end
153
153
 
154
+ def invalid_password?
155
+ invalid_password == true
156
+ end
157
+
154
158
  private
155
159
  def authenticating_with_password?
156
160
  login_field && (!send(login_field).nil? || !send("protected_#{password_field}").nil?)
157
161
  end
158
162
 
159
163
  def validate_by_password
164
+ self.invalid_password = false
165
+
160
166
  errors.add(login_field, I18n.t('error_messages.login_blank', :default => "cannot be blank")) if send(login_field).blank?
161
167
  errors.add(password_field, I18n.t('error_messages.password_blank', :default => "cannot be blank")) if send("protected_#{password_field}").blank?
162
168
  return if errors.count > 0
@@ -169,11 +175,20 @@ module Authlogic
169
175
  end
170
176
 
171
177
  if !attempted_record.send(verify_password_method, send("protected_#{password_field}"))
178
+ self.invalid_password = true
172
179
  generalize_credentials_error_messages? ? add_general_credentials_error : errors.add(password_field, I18n.t('error_messages.password_invalid', :default => "is not valid"))
173
180
  return
174
181
  end
175
182
  end
176
183
 
184
+ def invalid_password
185
+ @invalid_password
186
+ end
187
+
188
+ def invalid_password=(value)
189
+ @invalid_password = value
190
+ end
191
+
177
192
  def find_by_login_method
178
193
  self.class.find_by_login_method
179
194
  end
@@ -183,7 +198,7 @@ module Authlogic
183
198
  end
184
199
 
185
200
  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"))
201
+ errors.add(:base, I18n.t('error_messages.general_credentials_error', :default => "#{login_field.to_s.humanize}/Password combination is not valid"))
187
202
  end
188
203
 
189
204
  def generalize_credentials_error_messages?
@@ -10,10 +10,14 @@ module Authlogic
10
10
  # private
11
11
  # def check_if_awesome
12
12
  # errors.add(:login, "must contain awesome") if login && !login.include?("awesome")
13
- # errors.add_to_base("You must be awesome to log in") unless attempted_record.awesome?
13
+ # errors.add(:base, "You must be awesome to log in") unless attempted_record.awesome?
14
14
  # end
15
15
  # end
16
16
  class Errors < ::ActiveRecord::Errors
17
+ def [](key)
18
+ value = super
19
+ value.is_a?(Array) ? value : [value].compact
20
+ end
17
21
  end
18
22
 
19
23
  # You should use this as a place holder for any records that you find during validation. The main reason for this is to
@@ -39,7 +43,7 @@ module Authlogic
39
43
  # private
40
44
  # def check_if_awesome
41
45
  # errors.add(:login, "must contain awesome") if login && !login.include?("awesome")
42
- # errors.add_to_base("You must be awesome to log in") unless attempted_record.awesome?
46
+ # errors.add(:base, "You must be awesome to log in") unless attempted_record.awesome?
43
47
  # end
44
48
  # end
45
49
  def errors
@@ -58,18 +62,18 @@ module Authlogic
58
62
  validate
59
63
  ensure_authentication_attempted
60
64
 
61
- if errors.empty?
65
+ if errors.size == 0
62
66
  new_session? ? after_validation_on_create : after_validation_on_update
63
67
  after_validation
64
68
  end
65
69
 
66
70
  save_record(attempted_record)
67
- errors.empty?
71
+ errors.size == 0
68
72
  end
69
73
 
70
74
  private
71
75
  def ensure_authentication_attempted
72
- errors.add_to_base(I18n.t('error_messages.no_authentication_details', :default => "You did not provide any details for authentication.")) if errors.empty? && attempted_record.nil?
76
+ errors.add(:base, I18n.t('error_messages.no_authentication_details', :default => "You did not provide any details for authentication.")) if errors.empty? && attempted_record.nil?
73
77
  end
74
78
  end
75
79
  end
@@ -41,7 +41,7 @@ module Authlogic # :nodoc:
41
41
 
42
42
  MAJOR = 2
43
43
  MINOR = 0
44
- TINY = 13
44
+ TINY = 14
45
45
 
46
46
  # The current version as a Version instance
47
47
  CURRENT = new(MAJOR, MINOR, TINY)
@@ -57,41 +57,41 @@ module ActsAsAuthenticTest
57
57
  u = User.new
58
58
  u.email = "a@a.a"
59
59
  assert !u.valid?
60
- assert u.errors.on(:email)
60
+ assert u.errors[:email].size > 0
61
61
 
62
62
  u.email = "a@a.com"
63
63
  assert !u.valid?
64
- assert !u.errors.on(:email)
64
+ assert u.errors[:email].size == 0
65
65
  end
66
66
 
67
67
  def test_validates_format_of_email_field
68
68
  u = User.new
69
69
  u.email = "aaaaaaaaaaaaa"
70
70
  assert !u.valid?
71
- assert u.errors.on(:email)
71
+ assert u.errors[:email].size > 0
72
72
 
73
73
  u.email = "a@a.com"
74
74
  assert !u.valid?
75
- assert !u.errors.on(:email)
75
+ assert u.errors[:email].size == 0
76
76
 
77
77
  u.email = "dakota.dux+1@gmail.com"
78
78
  assert !u.valid?
79
- assert !u.errors.on(:email)
79
+ assert u.errors[:email].size == 0
80
80
  end
81
81
 
82
82
  def test_validates_uniqueness_of_email_field
83
83
  u = User.new
84
84
  u.email = "bjohnson@binarylogic.com"
85
85
  assert !u.valid?
86
- assert u.errors.on(:email)
86
+ assert u.errors[:email].size > 0
87
87
 
88
88
  u.email = "BJOHNSON@binarylogic.com"
89
89
  assert !u.valid?
90
- assert u.errors.on(:email)
90
+ assert u.errors[:email].size > 0
91
91
 
92
92
  u.email = "a@a.com"
93
93
  assert !u.valid?
94
- assert !u.errors.on(:email)
94
+ assert u.errors[:email].size == 0
95
95
  end
96
96
  end
97
97
  end
@@ -57,41 +57,41 @@ module ActsAsAuthenticTest
57
57
  u = User.new
58
58
  u.login = "a"
59
59
  assert !u.valid?
60
- assert u.errors.on(:login)
60
+ assert u.errors[:login].size > 0
61
61
 
62
62
  u.login = "aaaaaaaaaa"
63
63
  assert !u.valid?
64
- assert !u.errors.on(:login)
64
+ assert u.errors[:login].size == 0
65
65
  end
66
66
 
67
67
  def test_validates_format_of_login_field
68
68
  u = User.new
69
69
  u.login = "fdsf@^&*"
70
70
  assert !u.valid?
71
- assert u.errors.on(:login)
71
+ assert u.errors[:login].size > 0
72
72
 
73
73
  u.login = "fdsfdsfdsfdsfs"
74
74
  assert !u.valid?
75
- assert !u.errors.on(:login)
75
+ assert u.errors[:login].size == 0
76
76
 
77
77
  u.login = "dakota.dux+1@gmail.com"
78
78
  assert !u.valid?
79
- assert !u.errors.on(:login)
79
+ assert u.errors[:login].size == 0
80
80
  end
81
81
 
82
82
  def test_validates_uniqueness_of_login_field
83
83
  u = User.new
84
84
  u.login = "bjohnson"
85
85
  assert !u.valid?
86
- assert u.errors.on(:login)
86
+ assert u.errors[:login].size > 0
87
87
 
88
88
  u.login = "BJOHNSON"
89
89
  assert !u.valid?
90
- assert u.errors.on(:login)
90
+ assert u.errors[:login].size > 0
91
91
 
92
92
  u.login = "fdsfdsf"
93
93
  assert !u.valid?
94
- assert !u.errors.on(:login)
94
+ assert u.errors[:login].size == 0
95
95
  end
96
96
 
97
97
  def test_find_by_smart_case_login_field
@@ -6,22 +6,22 @@ module ActsAsAuthenticTest
6
6
  u = User.new
7
7
  u.login_count = -1
8
8
  assert !u.valid?
9
- assert u.errors.on(:login_count)
9
+ assert u.errors[:login_count].size > 0
10
10
 
11
11
  u.login_count = 0
12
12
  assert !u.valid?
13
- assert !u.errors.on(:login_count)
13
+ assert u.errors[:login_count].size == 0
14
14
  end
15
15
 
16
16
  def test_validates_numericality_of_failed_login_count
17
17
  u = User.new
18
18
  u.failed_login_count = -1
19
19
  assert !u.valid?
20
- assert u.errors.on(:failed_login_count)
20
+ assert u.errors[:failed_login_count].size > 0
21
21
 
22
22
  u.failed_login_count = 0
23
23
  assert !u.valid?
24
- assert !u.errors.on(:failed_login_count)
24
+ assert u.errors[:failed_login_count].size == 0
25
25
  end
26
26
  end
27
27
  end
@@ -107,11 +107,11 @@ module ActsAsAuthenticTest
107
107
  u = User.new
108
108
  u.password_confirmation = "test2"
109
109
  assert !u.valid?
110
- assert u.errors.on(:password)
110
+ assert u.errors[:password].size > 0
111
111
 
112
112
  u.password = "test"
113
113
  assert !u.valid?
114
- assert !u.errors.on(:password_confirmation)
114
+ assert u.errors[:password_confirmation].size == 0
115
115
  end
116
116
 
117
117
  def test_validates_confirmation_of_password
@@ -119,11 +119,11 @@ module ActsAsAuthenticTest
119
119
  u.password = "test"
120
120
  u.password_confirmation = "test2"
121
121
  assert !u.valid?
122
- assert u.errors.on(:password)
122
+ assert u.errors[:password].size > 0
123
123
 
124
124
  u.password_confirmation = "test"
125
125
  assert !u.valid?
126
- assert !u.errors.on(:password)
126
+ assert u.errors[:password].size == 0
127
127
  end
128
128
 
129
129
  def test_validates_length_of_password_confirmation
@@ -132,18 +132,18 @@ module ActsAsAuthenticTest
132
132
  u.password = "test"
133
133
  u.password_confirmation = ""
134
134
  assert !u.valid?
135
- assert u.errors.on(:password_confirmation)
135
+ assert u.errors[:password_confirmation].size > 0
136
136
 
137
137
  u.password_confirmation = "test"
138
138
  assert !u.valid?
139
- assert !u.errors.on(:password_confirmation)
139
+ assert u.errors[:password_confirmation].size == 0
140
140
 
141
141
  ben = users(:ben)
142
142
  assert ben.valid?
143
143
 
144
144
  ben.password = "newpass"
145
145
  assert !ben.valid?
146
- assert ben.errors.on(:password_confirmation)
146
+ assert ben.errors[:password_confirmation].size > 0
147
147
 
148
148
  ben.password_confirmation = "newpass"
149
149
  assert ben.valid?
@@ -26,7 +26,7 @@ module ActsAsAuthenticTest
26
26
  u = User.new
27
27
  u.perishable_token = users(:ben).perishable_token
28
28
  assert !u.valid?
29
- assert u.errors.on(:perishable_token)
29
+ assert u.errors[:perishable_token].size > 0
30
30
  end
31
31
 
32
32
  def test_before_save_reset_perishable_token
@@ -52,5 +52,33 @@ module ActsAsAuthenticTest
52
52
  ben.reload
53
53
  assert_not_equal old_perishable_token, ben.perishable_token
54
54
  end
55
+
56
+ def test_find_using_perishable_token
57
+ ben = users(:ben)
58
+ assert_equal ben, User.find_using_perishable_token(ben.perishable_token)
59
+ end
60
+
61
+ def test_find_using_perishable_token_when_perished
62
+ ben = users(:ben)
63
+ ActiveRecord::Base.connection.execute("UPDATE users set updated_at = '#{1.week.ago.to_s(:db)}' where id = #{ben.id}")
64
+ assert_nil User.find_using_perishable_token(ben.perishable_token)
65
+ end
66
+
67
+ def test_find_using_perishable_token_when_perished
68
+ User.perishable_token_valid_for = 1.minute
69
+ ben = users(:ben)
70
+ ActiveRecord::Base.connection.execute("UPDATE users set updated_at = '#{2.minutes.ago.to_s(:db)}' where id = #{ben.id}")
71
+ assert_nil User.find_using_perishable_token(ben.perishable_token)
72
+ User.perishable_token_valid_for = 10.minutes
73
+ end
74
+
75
+ def test_find_using_perishable_token_when_passing_threshold
76
+ User.perishable_token_valid_for = 1.minute
77
+ ben = users(:ben)
78
+ ActiveRecord::Base.connection.execute("UPDATE users set updated_at = '#{10.minutes.ago.to_s(:db)}' where id = #{ben.id}")
79
+ assert_nil User.find_using_perishable_token(ben.perishable_token, 5.minutes)
80
+ assert_equal ben, User.find_using_perishable_token(ben.perishable_token, 20.minutes)
81
+ User.perishable_token_valid_for = 10.minutes
82
+ end
55
83
  end
56
84
  end
@@ -16,7 +16,7 @@ module ActsAsAuthenticTest
16
16
  u = User.new
17
17
  u.single_access_token = users(:ben).single_access_token
18
18
  assert !u.valid?
19
- assert u.errors.on(:single_access_token)
19
+ assert u.errors[:single_access_token].size > 0
20
20
  end
21
21
 
22
22
  def test_before_validation_reset_single_access_token
@@ -45,26 +45,27 @@ module SessionTest
45
45
  2.times do |i|
46
46
  session = UserSession.new(:login => ben.login, :password => "badpassword1")
47
47
  assert !session.save
48
- assert session.errors.on(:password)
48
+ assert session.errors[:password].size > 0
49
49
  assert_equal i + 1, ben.reload.failed_login_count
50
50
  end
51
-
51
+
52
52
  session = UserSession.new(:login => ben.login, :password => "badpassword2")
53
53
  assert !session.save
54
- assert !session.errors.on(:password)
55
- assert_equal 2, ben.reload.failed_login_count
54
+ assert session.errors[:password].size == 0
55
+ assert_equal 3, ben.reload.failed_login_count
56
56
 
57
57
  UserSession.consecutive_failed_logins_limit = 50
58
58
  end
59
59
 
60
60
  def test_exceeded_ban_for
61
61
  UserSession.consecutive_failed_logins_limit = 2
62
+ UserSession.generalize_credentials_error_messages true
62
63
  ben = users(:ben)
63
64
 
64
65
  2.times do |i|
65
66
  session = UserSession.new(:login => ben.login, :password => "badpassword1")
66
67
  assert !session.save
67
- assert session.errors.on(:password)
68
+ assert session.invalid_password?
68
69
  assert_equal i + 1, ben.reload.failed_login_count
69
70
  end
70
71
 
@@ -74,6 +75,7 @@ module SessionTest
74
75
  assert_equal 0, ben.reload.failed_login_count
75
76
 
76
77
  UserSession.consecutive_failed_logins_limit = 50
78
+ UserSession.generalize_credentials_error_messages false
77
79
  end
78
80
 
79
81
  def test_exceeded_ban_and_failed_doesnt_ban_again
@@ -83,7 +85,7 @@ module SessionTest
83
85
  2.times do |i|
84
86
  session = UserSession.new(:login => ben.login, :password => "badpassword1")
85
87
  assert !session.save
86
- assert session.errors.on(:password)
88
+ assert session.errors[:password].size > 0
87
89
  assert_equal i + 1, ben.reload.failed_login_count
88
90
  end
89
91
 
@@ -31,7 +31,7 @@ module SessionTest
31
31
 
32
32
  ben.update_attribute(:active, false)
33
33
  assert !session.valid?
34
- assert session.errors.on_base.size > 0
34
+ assert session.errors[:base].size > 0
35
35
  end
36
36
 
37
37
  def test_validate_validate_magic_states_approved
@@ -42,7 +42,7 @@ module SessionTest
42
42
 
43
43
  ben.update_attribute(:approved, false)
44
44
  assert !session.valid?
45
- assert session.errors.on_base.size > 0
45
+ assert session.errors[:base].size > 0
46
46
  end
47
47
 
48
48
  def test_validate_validate_magic_states_confirmed
@@ -53,7 +53,7 @@ module SessionTest
53
53
 
54
54
  ben.update_attribute(:confirmed, false)
55
55
  assert !session.valid?
56
- assert session.errors.on_base.size > 0
56
+ assert session.errors[:base].size > 0
57
57
  end
58
58
  end
59
59
  end
@@ -4,6 +4,16 @@ require "ruby-debug"
4
4
  require "active_record"
5
5
  require "active_record/fixtures"
6
6
 
7
+ # A temporary fix to bring active record errors up to speed with rails edge.
8
+ # I need to remove this once the new gem is released. This is only here so my tests pass.
9
+ class ActiveRecord::Errors
10
+ def [](key)
11
+ value = on(key)
12
+ value.is_a?(Array) ? value : [value].compact
13
+ end
14
+ end
15
+
16
+
7
17
  ActiveRecord::Schema.verbose = false
8
18
  ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
9
19
  ActiveRecord::Base.configurations = true
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.13
4
+ version: 2.0.14
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-05-13 00:00:00 -04:00
12
+ date: 2009-06-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.2
33
+ version: 2.0.0
34
34
  version:
35
35
  description: A clean, simple, and unobtrusive ruby authentication solution.
36
36
  email: bjohnson@binarylogic.com
@@ -186,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
186
186
  requirements: []
187
187
 
188
188
  rubyforge_project: authlogic
189
- rubygems_version: 1.3.3
189
+ rubygems_version: 1.3.4
190
190
  signing_key:
191
191
  specification_version: 3
192
192
  summary: A clean, simple, and unobtrusive ruby authentication solution.