<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">&lt;ramonn@linux.vnet.ibm.com&gt;</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 &gt;= 3:
        <br>
        +
        <br>
        +            # verify if timeout is still valid
        <br>
        +            last_try = self.failed_logins[l - 1]
        <br>
        +            if time.time() &lt; (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) &gt; 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=(.*?)(&amp;|$)/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)
        &amp;&amp;
        <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>
                             &lt;div id="messUserPass" class="alert
        alert-danger" style="display: none;"&gt;$_("The username or
        password you entered is incorrect. Please try
        again.")&lt;/div&gt;
        <br>
                             &lt;div id="messSession" class="alert
        alert-danger" style="display: none;"&gt;$_("Session timeout,
        please re-login.")&lt;/div&gt;
        <br>
                             &lt;div id="missServer" class="alert
        alert-danger" style="display: none;"&gt;$_("Server
        unreachable.")&lt;/div&gt;
        <br>
        +                    &lt;div id="timeoutError" class="alert
        alert-danger" style="display: none;"&gt;$_("Timeout
        error")&lt;/div&gt;
        <br>
                         &lt;/div&gt;
        <br>
                         &lt;form id="form-login"
        class="form-horizontal" method="post"&gt;
        <br>
                             &lt;div class="form-group"&gt;
        <br>
        <br>
      </blockquote>
      <br>
      <br>
    </blockquote>
    <br>
    <pre class="moz-signature" cols="72">-- 

Ramon Nunes Medeiros
Kimchi Developer
Linux Technology Center Brazil
IBM Systems &amp; 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>