ref: refs/heads/master
commit 4f74fe5c2ec8c1927b9ebac0073e5b703fb484df
Author: Josef Reidinger
Date: Mon Nov 2 16:24:21 2009 +0100
add Brute force protection
---
webservice/app/controllers/sessions_controller.rb | 6 ++-
webservice/lib/brute_force_protection.rb | 63 ++++++++++++++++++++
webservice/package/yast2-webservice.changes | 5 ++
.../test/unit/brute_force_protection_test.rb | 33 ++++++++++
4 files changed, 106 insertions(+), 1 deletions(-)
diff --git a/webservice/app/controllers/sessions_controller.rb b/webservice/app/controllers/sessions_controller.rb
index 86295c2..d88f3e0 100644
--- a/webservice/app/controllers/sessions_controller.rb
+++ b/webservice/app/controllers/sessions_controller.rb
@@ -34,7 +34,10 @@ class SessionsController < ApplicationController
self.current_account = Account.authenticate(params[:login], params[:password])
end
@cmd_ret = Hash.new
- if logged_in?
+ if BruteForceProtection.instance.blocked?
+ @cmd_ret["login"] = "blocked"
+ @cmd_ret["remain"] = BruteForceProtection.instance.last_fail + BruteForceProtection::BAN_TIMEOUT
+ elsif logged_in?
if params[:remember_me]
current_account.remember_me unless current_account.remember_token?
cookies[:auth_token] = { :value => self.current_account.remember_token , :expires => self.current_account.remember_token_expires_at }
@@ -44,6 +47,7 @@ class SessionsController < ApplicationController
@cmd_ret["auth_token"] = { :value => self.current_account.remember_token , :expires => self.current_account.remember_token_expires_at }
else
@cmd_ret["login"] = "denied"
+ BruteForceProtection.instance.fail_attempt
end
end
diff --git a/webservice/lib/brute_force_protection.rb b/webservice/lib/brute_force_protection.rb
new file mode 100644
index 0000000..b5fc899
--- /dev/null
+++ b/webservice/lib/brute_force_protection.rb
@@ -0,0 +1,63 @@
+# == Brute force Protection class
+# === Overview
+#
+# Singleton class thant remember fail attempts to log to REST-SERVICE.
+# After specified time period is failed attemps cleared.
+#
+# === Usage
+#
+# When user tries to login ensure that it is not blocked by BruteForceProtection.instance.blocked?
+# When user failed to login call BruteForceProtection.instance.fail_attempt
+
+class BruteForceProtection
+ include Singleton
+
+ #Specifies number of failed attempts before block
+ ATTEMPTS_TO_BLOCK=10
+
+ #Specifies timeout if user failed to login
+ TIMEOUT_ON_FAIL=2
+
+ #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
+ end
+
+ #Returns if login is blocked
+ def blocked?
+ unless @blocked
+ return false
+ end
+
+ clean_old_block
+
+ return @blocked
+ end
+
+ # notification that user fail to login
+ def fail_attempt
+ clean_old_block #clean old fail attempts
+ @last_fail = Time.new
+ @count_failed += 1
+ sleep TIMEOUT_ON_FAIL
+ @blocked = @count_failed >= ATTEMPTS_TO_BLOCK
+ 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
+ end
+
+end
diff --git a/webservice/package/yast2-webservice.changes b/webservice/package/yast2-webservice.changes
index 965889d..386731c 100644
--- a/webservice/package/yast2-webservice.changes
+++ b/webservice/package/yast2-webservice.changes
@@ -1,4 +1,9 @@
-------------------------------------------------------------------
+Mon Nov 2 16:12:32 CET 2009 - jreidinger@suse.cz
+
+- add brute force attack protection (bnc#550377)
+
+-------------------------------------------------------------------
Thu Oct 29 12:37:42 CET 2009 - mvidner@suse.cz
- Removed avahi (zeroconf) usage.
diff --git a/webservice/test/unit/brute_force_protection_test.rb b/webservice/test/unit/brute_force_protection_test.rb
new file mode 100644
index 0000000..ec7aa6a
--- /dev/null
+++ b/webservice/test/unit/brute_force_protection_test.rb
@@ -0,0 +1,33 @@
+require File.join(File.dirname(__FILE__),"..", "test_helper")
+
+class BruteForceProtectionTest < ActiveSupport::TestCase
+
+ def setup
+ @protection = BruteForceProtection.instance
+ @protection.send "initialize"
+ end
+
+ def test_not_blocking_clean
+ assert !@protection.blocked?
+ end
+
+ def test_blocked
+ BruteForceProtection.const_set "TIMEOUT_ON_FAIL", 0 #disable sleep
+ (BruteForceProtection.const_get "ATTEMPTS_TO_BLOCK").times do
+ @protection.fail_attempt
+ end
+ assert @protection.blocked?
+ end
+
+ def test_unblocked_after_period
+ BruteForceProtection.const_set "TIMEOUT_ON_FAIL", 0 #disable sleep
+ BruteForceProtection::ATTEMPTS_TO_BLOCK.times do
+ @protection.fail_attempt
+ end
+ old_time = Time.new - (BruteForceProtection::BAN_TIMEOUT+10)
+ @protection.instance_variable_set("@last_fail", old_time ) # simulate old time in counter
+
+ assert !@protection.blocked?
+ end
+
+end
--
To unsubscribe, e-mail: yast-commit+unsubscribe@opensuse.org
For additional commands, e-mail: yast-commit+help@opensuse.org