<html>
<head>
<meta content="text/html; charset=windows-1252"
http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<p><br>
</p>
<br>
<div class="moz-cite-prefix">On 01/17/2017 10:12 AM, Lucio Correia
wrote:<br>
</div>
<blockquote
cite="mid:e5e74c8c-afa1-a282-f227-5e3a18ee3517@linux.vnet.ibm.com"
type="cite">On 16/01/2017 17:29, Ramon Medeiros wrote:
<br>
<blockquote type="cite">To prevent brute force attack, creates a
mechanism to allow 3 tries
<br>
first. After that, a timeout will start and will be added 30
seconds for
<br>
each failed try in a row.
<br>
<br>
Signed-off-by: Ramon Medeiros <a class="moz-txt-link-rfc2396E" href="mailto:ramonn@linux.vnet.ibm.com"><ramonn@linux.vnet.ibm.com></a>
<br>
---
<br>
Changes:
<br>
<br>
v2:
<br>
fix pep8 issues
<br>
<br>
src/wok/i18n.py | 1 +
<br>
src/wok/root.py | 37
++++++++++++++++++++++++++++++++++---
<br>
ui/js/src/wok.login.js | 11 ++++++++++-
<br>
ui/pages/login.html.tmpl | 3 ++-
<br>
4 files changed, 47 insertions(+), 5 deletions(-)
<br>
<br>
diff --git a/src/wok/i18n.py b/src/wok/i18n.py
<br>
index e454e31..21cc4ea 100644
<br>
--- a/src/wok/i18n.py
<br>
+++ b/src/wok/i18n.py
<br>
@@ -41,6 +41,7 @@ messages = {
<br>
"WOKAUTH0001E": _("Authentication failed for user
'%(username)s'. [Error code: %(code)s]"),
<br>
"WOKAUTH0002E": _("You are not authorized to access Wok.
Please, login first."),
<br>
"WOKAUTH0003E": _("Specify %(item)s to login into Wok."),
<br>
+ "WOKAUTH0004E": _("You have failed to login in too much
attempts. Please, wait for %(seconds)s seconds to try again."),
<br>
</blockquote>
<br>
Suggestion: Too many login attempts failed. Wait %(seconds)s to
try again.
<br>
<br>
<blockquote type="cite"> "WOKAUTH0005E": _("Invalid LDAP
configuration: %(item)s : %(value)s"),
<br>
<br>
"WOKLOG0001E": _("Invalid filter parameter. Filter
parameters allowed: %(filters)s"),
<br>
diff --git a/src/wok/root.py b/src/wok/root.py
<br>
index 080b7f0..65226fb 100644
<br>
--- a/src/wok/root.py
<br>
+++ b/src/wok/root.py
<br>
@@ -1,7 +1,7 @@
<br>
#
<br>
# Project Wok
<br>
#
<br>
-# Copyright IBM Corp, 2015-2016
<br>
+# Copyright IBM Corp, 2015-2017
<br>
#
<br>
# Code derived from Project Kimchi
<br>
#
<br>
@@ -22,6 +22,7 @@
<br>
import cherrypy
<br>
import json
<br>
import os
<br>
+import time
<br>
from distutils.version import LooseVersion
<br>
<br>
from wok import auth
<br>
@@ -31,7 +32,7 @@ from wok.config import paths as wok_paths
<br>
from wok.control import sub_nodes
<br>
from wok.control.base import Resource
<br>
from wok.control.utils import parse_request
<br>
-from wok.exception import MissingParameter
<br>
+from wok.exception import MissingParameter, UnauthorizedError
<br>
from wok.reqlogger import log_request
<br>
<br>
<br>
@@ -48,7 +49,8 @@ class Root(Resource):
<br>
super(Root, self).__init__(model)
<br>
self._handled_error = ['error_page.400',
'error_page.404',
<br>
'error_page.405',
'error_page.406',
<br>
- 'error_page.415',
'error_page.500']
<br>
+ 'error_page.415',
'error_page.500',
<br>
+ 'error_page.403']
<br>
<br>
if not dev_env:
<br>
self._cp_config = dict([(key,
self.error_production_handler)
<br>
@@ -146,6 +148,8 @@ class WokRoot(Root):
<br>
self.domain = 'wok'
<br>
self.messages = messages
<br>
self.extends = None
<br>
+ self.failed_logins = []
<br>
+ self.fail_timeout = 30
<br>
<br>
# set user log messages and make sure all parameters
are present
<br>
self.log_map = ROOT_REQUESTS
<br>
@@ -153,6 +157,12 @@ class WokRoot(Root):
<br>
<br>
@cherrypy.expose
<br>
def login(self, *args):
<br>
+ def _raise_timeout():
<br>
+ details = e = UnauthorizedError("WOKAUTH0004E",
<br>
+ {"seconds":
self.fail_timeout})
<br>
+ log_request(code, params, details, method, 403)
<br>
+ raise cherrypy.HTTPError(403, e.message)
<br>
+
<br>
details = None
<br>
method = 'POST'
<br>
code = self.getRequestMessage(method, 'login')
<br>
@@ -166,10 +176,31 @@ class WokRoot(Root):
<br>
log_request(code, params, details, method, 400)
<br>
raise cherrypy.HTTPError(400, e.message)
<br>
<br>
+ # check for repestly
<br>
+ l = len(self.failed_logins)
<br>
+ if l >= 3:
<br>
+
<br>
+ # verify if timeout is still valid
<br>
+ last_try = self.failed_logins[l - 1]
<br>
+ if time.time() < (last_try["time"] +
self.fail_timeout):
<br>
+ _raise_timeout()
<br>
try:
<br>
status = 200
<br>
user_info = auth.login(username, password)
<br>
+
<br>
+ # user logged sucessfuly: reset counters
<br>
+ self.failed_logins = []
<br>
+ self.timeout = 30
<br>
except cherrypy.HTTPError, e:
<br>
+ # store time and prevent too much tries
<br>
+ self.failed_logins.append({"user": username,
<br>
+ "time": time.time()})
<br>
+
<br>
+ # more than 3 fails: raise error
<br>
+ if len(self.failed_logins) > 3:
<br>
+ self.fail_timeout += (len(self.failed_logins) -
3) * 30
<br>
+ _raise_timeout()
<br>
+
<br>
</blockquote>
<br>
I was thinking it would be controlled by username i.e. 3 failed
attempts for the same username would block that username only.
<br>
<br>
</blockquote>
you are right, Just forget it <br>
<blockquote
cite="mid:e5e74c8c-afa1-a282-f227-5e3a18ee3517@linux.vnet.ibm.com"
type="cite">
<br>
<blockquote type="cite"> status = e.status
<br>
raise
<br>
finally:
<br>
diff --git a/ui/js/src/wok.login.js b/ui/js/src/wok.login.js
<br>
index fa2a98a..ba9ac23 100644
<br>
--- a/ui/js/src/wok.login.js
<br>
+++ b/ui/js/src/wok.login.js
<br>
@@ -1,7 +1,7 @@
<br>
/*
<br>
* Project Wok
<br>
*
<br>
- * Copyright IBM Corp, 2015-2016
<br>
+ * Copyright IBM Corp, 2015-2017
<br>
*
<br>
* Code derived from Project Kimchi
<br>
*
<br>
@@ -71,6 +71,7 @@ wok.login_main = function() {
<br>
wok.login(settings, function(data) {
<br>
var query = window.location.search;
<br>
var next = /.*next=(.*?)(&|$)/g.exec(query);
<br>
+
<br>
if (next) {
<br>
var next_url = decodeURIComponent(next[1]);
<br>
}
<br>
@@ -84,9 +85,17 @@ wok.login_main = function() {
<br>
if (jqXHR.responseText == "") {
<br>
$("#messUserPass").hide();
<br>
$("#missServer").show();
<br>
+ $("#timeoutError").hide();
<br>
+ } else if ((jqXHR.responseJSON != undefined)
&&
<br>
+ ! (jqXHR.responseJSON["reason"] ==
undefined)) {
<br>
+ $("#messUserPass").hide();
<br>
+ $("#missServer").hide();
<br>
+
$("#timeoutError").html(jqXHR.responseJSON["reason"]);
<br>
+ $("#timeoutError").show();
<br>
} else {
<br>
$("#missServer").hide();
<br>
$("#messUserPass").show();
<br>
+ $("#timeoutError").hide();
<br>
}
<br>
$("#messSession").hide();
<br>
$("#logging").hide();
<br>
diff --git a/ui/pages/login.html.tmpl b/ui/pages/login.html.tmpl
<br>
index f5a4b2d..d25910c 100644
<br>
--- a/ui/pages/login.html.tmpl
<br>
+++ b/ui/pages/login.html.tmpl
<br>
@@ -1,7 +1,7 @@
<br>
#*
<br>
* Project Wok
<br>
*
<br>
- * Copyright IBM Corp, 2014-2016
<br>
+ * Copyright IBM Corp, 2014-2017
<br>
*
<br>
* Code derived from Project Kimchi
<br>
*
<br>
@@ -107,6 +107,7 @@
<br>
<div id="messUserPass" class="alert
alert-danger" style="display: none;">$_("The username or
password you entered is incorrect. Please try
again.")</div>
<br>
<div id="messSession" class="alert
alert-danger" style="display: none;">$_("Session timeout,
please re-login.")</div>
<br>
<div id="missServer" class="alert
alert-danger" style="display: none;">$_("Server
unreachable.")</div>
<br>
+ <div id="timeoutError" class="alert
alert-danger" style="display: none;">$_("Timeout
error")</div>
<br>
</div>
<br>
<form id="form-login"
class="form-horizontal" method="post">
<br>
<div class="form-group">
<br>
<br>
</blockquote>
<br>
<br>
</blockquote>
<br>
<pre class="moz-signature" cols="72">--
Ramon Nunes Medeiros
Kimchi Developer
Linux Technology Center Brazil
IBM Systems & Technology Group
Phone : +55 19 2132 7878
<a class="moz-txt-link-abbreviated" href="mailto:ramonn@br.ibm.com">ramonn@br.ibm.com</a> </pre>
</body>
</html>