ref: refs/heads/master
commit c3eadcf4816657cbd2b404b430bcd8932dd56b6f
Author: Josef Reidinger
Date: Tue Nov 3 14:35:59 2009 +0100
block only users which has too many failed attemts, so another user can login
---
webservice/app/controllers/sessions_controller.rb | 6 +-
webservice/lib/brute_force_protection.rb | 50 ++++++++++++--------
webservice/package/yast2-webservice.changes | 6 ++
.../test/unit/brute_force_protection_test.rb | 15 +++---
4 files changed, 47 insertions(+), 30 deletions(-)
diff --git a/webservice/app/controllers/sessions_controller.rb b/webservice/app/controllers/sessions_controller.rb
index 9b16cd9..bedcd60 100644
--- a/webservice/app/controllers/sessions_controller.rb
+++ b/webservice/app/controllers/sessions_controller.rb
@@ -34,9 +34,9 @@ class SessionsController < ApplicationController
self.current_account = Account.authenticate(params[:login], params[:password])
end
@cmd_ret = Hash.new
- if BruteForceProtection.instance.blocked?
+ if BruteForceProtection.instance.blocked? params[:login]
@cmd_ret["login"] = "blocked"
- @cmd_ret["remain"] = BruteForceProtection.instance.last_fail + BruteForceProtection::BAN_TIMEOUT
+ @cmd_ret["remain"] = BruteForceProtection.instance.last_fail(params[:login]) + BruteForceProtection::BAN_TIMEOUT
elsif logged_in?
if params[:remember_me]
current_account.remember_me unless current_account.remember_token?
@@ -48,7 +48,7 @@ class SessionsController < ApplicationController
else
logger.warn "Login failed from ip #{request.remote_ip} with user #{params[:login] ||""}"
@cmd_ret["login"] = "denied"
- BruteForceProtection.instance.fail_attempt
+ BruteForceProtection.instance.fail_attempt params[:login]
end
end
diff --git a/webservice/lib/brute_force_protection.rb b/webservice/lib/brute_force_protection.rb
index b5fc899..8205ddb 100644
--- a/webservice/lib/brute_force_protection.rb
+++ b/webservice/lib/brute_force_protection.rb
@@ -21,43 +21,53 @@ class BruteForceProtection
#Specifies how long is login blocked
BAN_TIMEOUT=10*60 #10 minutes
- attr_reader :last_fail
-
#Sets initial values
def initialize
- @blocked = false
- @last_fail = Time.new
- @count_failed = 0
+ @blocking_list = {}
end
#Returns if login is blocked
- def blocked?
- unless @blocked
- return false
- end
-
+ def blocked?(user)
clean_old_block
- return @blocked
+ return (@blocking_list[user] && @blocking_list[user][:blocked])
+ end
+
+ def last_failed(user)
+ return 0 unless @blocking_list[user]
+ return @blocking_list[user][:last_fail]
end
# notification that user fail to login
- def fail_attempt
+ def fail_attempt (user)
clean_old_block #clean old fail attempts
- @last_fail = Time.new
- @count_failed += 1
- sleep TIMEOUT_ON_FAIL
- @blocked = @count_failed >= ATTEMPTS_TO_BLOCK
+ if @blocking_list[user]
+ record = @blocking_list[user]
+ record[:last_fail] = Time.now
+ record[:count] += 1
+ record[:blocked] = record[:count] >= ATTEMPTS_TO_BLOCK
+ else
+ @blocking_list[user] = {
+ :last_fail => Time.now,
+ :count => 1,
+ :blocked => ATTEMPTS_TO_BLOCK == 1
+ }
+ end
+
+ sleep TIMEOUT_ON_FAIL #FIXME maybe unix_chkpwd is slow enought to disable sleep
end
private
#Cleans failed attempts if specified time pass
def clean_old_block
- if (Time.new - @last_fail) > BAN_TIMEOUT
- @blocked = false
- @count_failed=0
- end
+ @blocking_list.each_value {
+ |value|
+ if (Time.now - value[:last_fail]) > BAN_TIMEOUT
+ value[:blocked] = false
+ value[:count] = 0
+ end
+ }
end
end
diff --git a/webservice/package/yast2-webservice.changes b/webservice/package/yast2-webservice.changes
index 5fa067f..72d94e6 100644
--- a/webservice/package/yast2-webservice.changes
+++ b/webservice/package/yast2-webservice.changes
@@ -1,4 +1,10 @@
-------------------------------------------------------------------
+Tue Nov 3 14:34:58 CET 2009 - jreidinger@suse.cz
+
+- block only user which has too many attempts, so another user can
+ login (bnc#550377)
+
+-------------------------------------------------------------------
Mon Nov 2 16:52:08 CET 2009 - jreidinger@suse.cz
- log all failed login (user and its ip) (bnc#550377)
diff --git a/webservice/test/unit/brute_force_protection_test.rb b/webservice/test/unit/brute_force_protection_test.rb
index ec7aa6a..df1e7c0 100644
--- a/webservice/test/unit/brute_force_protection_test.rb
+++ b/webservice/test/unit/brute_force_protection_test.rb
@@ -8,26 +8,27 @@ class BruteForceProtectionTest < ActiveSupport::TestCase
end
def test_not_blocking_clean
- assert !@protection.blocked?
+ assert !@protection.blocked?("test")
end
def test_blocked
BruteForceProtection.const_set "TIMEOUT_ON_FAIL", 0 #disable sleep
(BruteForceProtection.const_get "ATTEMPTS_TO_BLOCK").times do
- @protection.fail_attempt
+ @protection.fail_attempt "test"
end
- assert @protection.blocked?
+ assert @protection.blocked?("test")
end
def test_unblocked_after_period
BruteForceProtection.const_set "TIMEOUT_ON_FAIL", 0 #disable sleep
BruteForceProtection::ATTEMPTS_TO_BLOCK.times do
- @protection.fail_attempt
+ @protection.fail_attempt "test"
end
- old_time = Time.new - (BruteForceProtection::BAN_TIMEOUT+10)
- @protection.instance_variable_set("@last_fail", old_time ) # simulate old time in counter
+ old_time = Time.now - (BruteForceProtection::BAN_TIMEOUT+10)
+ hash = @protection.instance_variable_get :@blocking_list
+ hash["test"][:last_fail] = old_time # simulate old time in counter
- assert !@protection.blocked?
+ assert !@protection.blocked?("test")
end
end
--
To unsubscribe, e-mail: yast-commit+unsubscribe@opensuse.org
For additional commands, e-mail: yast-commit+help@opensuse.org