[PATCH] [Wok] Add Documentation for systemd service
by Lucio Correia
Debian's lintian tool generates a warning when this field
is not set.
Signed-off-by: Lucio Correia <luciojhc(a)linux.vnet.ibm.com>
---
contrib/wokd.service.systemd | 1 +
1 file changed, 1 insertion(+)
diff --git a/contrib/wokd.service.systemd b/contrib/wokd.service.systemd
index 61673a5..040f94e 100644
--- a/contrib/wokd.service.systemd
+++ b/contrib/wokd.service.systemd
@@ -1,5 +1,6 @@
[Unit]
Description=Wok - Webserver Originated from Kimchi
+Documentation=https://github.com/kimchi-project/wok/wiki
Wants=nginx.service
After=nginx.service
--
2.7.4
7 years, 9 months
[PATCH v2][Wok] Bug fix #147: Block authentication request after too many failures
by Ramon Medeiros
To prevent brute force attack, creates a mechanism to allow 3 tries
first. After that, a timeout will start and will be added 30 seconds for
each failed try in a row.
Signed-off-by: Ramon Medeiros <ramonn(a)linux.vnet.ibm.com>
---
Changes:
v2:
fix pep8 issues
src/wok/i18n.py | 1 +
src/wok/root.py | 37 ++++++++++++++++++++++++++++++++++---
ui/js/src/wok.login.js | 11 ++++++++++-
ui/pages/login.html.tmpl | 3 ++-
4 files changed, 47 insertions(+), 5 deletions(-)
diff --git a/src/wok/i18n.py b/src/wok/i18n.py
index e454e31..21cc4ea 100644
--- a/src/wok/i18n.py
+++ b/src/wok/i18n.py
@@ -41,6 +41,7 @@ messages = {
"WOKAUTH0001E": _("Authentication failed for user '%(username)s'. [Error code: %(code)s]"),
"WOKAUTH0002E": _("You are not authorized to access Wok. Please, login first."),
"WOKAUTH0003E": _("Specify %(item)s to login into Wok."),
+ "WOKAUTH0004E": _("You have failed to login in too much attempts. Please, wait for %(seconds)s seconds to try again."),
"WOKAUTH0005E": _("Invalid LDAP configuration: %(item)s : %(value)s"),
"WOKLOG0001E": _("Invalid filter parameter. Filter parameters allowed: %(filters)s"),
diff --git a/src/wok/root.py b/src/wok/root.py
index 080b7f0..65226fb 100644
--- a/src/wok/root.py
+++ b/src/wok/root.py
@@ -1,7 +1,7 @@
#
# Project Wok
#
-# Copyright IBM Corp, 2015-2016
+# Copyright IBM Corp, 2015-2017
#
# Code derived from Project Kimchi
#
@@ -22,6 +22,7 @@
import cherrypy
import json
import os
+import time
from distutils.version import LooseVersion
from wok import auth
@@ -31,7 +32,7 @@ from wok.config import paths as wok_paths
from wok.control import sub_nodes
from wok.control.base import Resource
from wok.control.utils import parse_request
-from wok.exception import MissingParameter
+from wok.exception import MissingParameter, UnauthorizedError
from wok.reqlogger import log_request
@@ -48,7 +49,8 @@ class Root(Resource):
super(Root, self).__init__(model)
self._handled_error = ['error_page.400', 'error_page.404',
'error_page.405', 'error_page.406',
- 'error_page.415', 'error_page.500']
+ 'error_page.415', 'error_page.500',
+ 'error_page.403']
if not dev_env:
self._cp_config = dict([(key, self.error_production_handler)
@@ -146,6 +148,8 @@ class WokRoot(Root):
self.domain = 'wok'
self.messages = messages
self.extends = None
+ self.failed_logins = []
+ self.fail_timeout = 30
# set user log messages and make sure all parameters are present
self.log_map = ROOT_REQUESTS
@@ -153,6 +157,12 @@ class WokRoot(Root):
@cherrypy.expose
def login(self, *args):
+ def _raise_timeout():
+ details = e = UnauthorizedError("WOKAUTH0004E",
+ {"seconds": self.fail_timeout})
+ log_request(code, params, details, method, 403)
+ raise cherrypy.HTTPError(403, e.message)
+
details = None
method = 'POST'
code = self.getRequestMessage(method, 'login')
@@ -166,10 +176,31 @@ class WokRoot(Root):
log_request(code, params, details, method, 400)
raise cherrypy.HTTPError(400, e.message)
+ # check for repetly
+ l = len(self.failed_logins)
+ if l >= 3:
+
+ # verify if timeout is still valid
+ last_try = self.failed_logins[l - 1]
+ if time.time() < (last_try["time"] + self.fail_timeout):
+ _raise_timeout()
try:
status = 200
user_info = auth.login(username, password)
+
+ # user logged sucessfuly: reset counters
+ self.failed_logins = []
+ self.timeout = 30
except cherrypy.HTTPError, e:
+ # store time and prevent too much tries
+ self.failed_logins.append({"user": username,
+ "time": time.time()})
+
+ # more than 3 fails: raise error
+ if len(self.failed_logins) > 3:
+ self.fail_timeout += (len(self.failed_logins) - 3) * 30
+ _raise_timeout()
+
status = e.status
raise
finally:
diff --git a/ui/js/src/wok.login.js b/ui/js/src/wok.login.js
index fa2a98a..ba9ac23 100644
--- a/ui/js/src/wok.login.js
+++ b/ui/js/src/wok.login.js
@@ -1,7 +1,7 @@
/*
* Project Wok
*
- * Copyright IBM Corp, 2015-2016
+ * Copyright IBM Corp, 2015-2017
*
* Code derived from Project Kimchi
*
@@ -71,6 +71,7 @@ wok.login_main = function() {
wok.login(settings, function(data) {
var query = window.location.search;
var next = /.*next=(.*?)(&|$)/g.exec(query);
+
if (next) {
var next_url = decodeURIComponent(next[1]);
}
@@ -84,9 +85,17 @@ wok.login_main = function() {
if (jqXHR.responseText == "") {
$("#messUserPass").hide();
$("#missServer").show();
+ $("#timeoutError").hide();
+ } else if ((jqXHR.responseJSON != undefined) &&
+ ! (jqXHR.responseJSON["reason"] == undefined)) {
+ $("#messUserPass").hide();
+ $("#missServer").hide();
+ $("#timeoutError").html(jqXHR.responseJSON["reason"]);
+ $("#timeoutError").show();
} else {
$("#missServer").hide();
$("#messUserPass").show();
+ $("#timeoutError").hide();
}
$("#messSession").hide();
$("#logging").hide();
diff --git a/ui/pages/login.html.tmpl b/ui/pages/login.html.tmpl
index f5a4b2d..d25910c 100644
--- a/ui/pages/login.html.tmpl
+++ b/ui/pages/login.html.tmpl
@@ -1,7 +1,7 @@
#*
* Project Wok
*
- * Copyright IBM Corp, 2014-2016
+ * Copyright IBM Corp, 2014-2017
*
* Code derived from Project Kimchi
*
@@ -107,6 +107,7 @@
<div id="messUserPass" class="alert alert-danger" style="display: none;">$_("The username or password you entered is incorrect. Please try again.")</div>
<div id="messSession" class="alert alert-danger" style="display: none;">$_("Session timeout, please re-login.")</div>
<div id="missServer" class="alert alert-danger" style="display: none;">$_("Server unreachable.")</div>
+ <div id="timeoutError" class="alert alert-danger" style="display: none;">$_("Timeout error")</div>
</div>
<form id="form-login" class="form-horizontal" method="post">
<div class="form-group">
--
2.7.4
7 years, 9 months
[PATCH] [Wok 0/6] Update man page content
by Aline Manera
Aline Manera (6):
Remove --access-log and --error-log options from wokd command
Use underscore in all wokd command options
Update AUTHORS content according to git-log command
Update COPYING file to reflect all the imported code
Update man page document
Fix typo in license header
AUTHORS | 67 ++++++++++++++++---
COPYING | 114 +++++++++++++++++++++++++++++---
docs/wokd.8.in | 149 +++++++++++++++++++++++-------------------
src/wokd.in | 20 +++---
tests/test_exception.py | 4 +-
tests/test_objectstore.py | 4 +-
tests/test_plugin.py | 4 +-
tests/test_rollbackcontext.py | 4 +-
tests/test_server.py | 6 +-
tests/test_utils.py | 4 +-
tests/utils.py | 4 +-
11 files changed, 268 insertions(+), 112 deletions(-)
--
2.7.4
7 years, 9 months
[PATCH v2][Wok] Issue #160: Fedora 25: Make check breaks on wok
by Ramon Medeiros
Threading identifier was not given a unique name. So, a name will be
passed to force it. This behaviour is described at threading docs:
https://docs.python.org/2/library/threading.html#threading.Thread.ident
Thread identifiers may be recycled when a thread exits and another
thread is created. The identifier is available even after the thread has
exited.
Signed-off-by: Ramon Medeiros <ramonn(a)linux.vnet.ibm.com>
---
Changes:
v2:
More verbose commit message
src/wok/objectstore.py | 4 ++--
tests/test_objectstore.py | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/wok/objectstore.py b/src/wok/objectstore.py
index 817f60c..a571e5f 100644
--- a/src/wok/objectstore.py
+++ b/src/wok/objectstore.py
@@ -1,6 +1,6 @@
# Project Wok
#
-# Copyright IBM Corp, 2015-2016
+# Copyright IBM Corp, 2015-2017
#
# Code derived from Project Kimchi
#
@@ -115,7 +115,7 @@ class ObjectStore(object):
return
def _get_conn(self):
- ident = threading.currentThread().ident
+ ident = threading.currentThread().name
try:
return self._connections[ident]
except KeyError:
diff --git a/tests/test_objectstore.py b/tests/test_objectstore.py
index 3ea7b70..96bcf13 100644
--- a/tests/test_objectstore.py
+++ b/tests/test_objectstore.py
@@ -2,7 +2,7 @@
#
# Project Wok
#
-# Copyright IBM Corp, 2015-2016
+# Copyright IBM Corp, 2015-2017
#
# Code delivered from Project Kimchi
#
@@ -91,7 +91,7 @@ class ObjectStoreTests(unittest.TestCase):
threads = []
for i in xrange(50):
- t = threading.Thread(target=worker, args=(i,))
+ t = threading.Thread(target=worker, args=(i,), name=str(i))
t.setDaemon(True)
t.start()
threads.append(t)
--
2.7.4
7 years, 9 months
[PATCH][Kimchi] VEPA interface not listed with VM running
by Ramon Medeiros
UI was filtering interfaces. Just removed it.
Signed-off-by: Ramon Medeiros <ramonn(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.guest_edit_main.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index bb82077..16241cc 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -458,8 +458,7 @@ kimchi.guest_edit_main = function() {
data[i].viewMode = "";
data[i].editMode = "hide";
data[i].id = i;
- if (data[i].type == 'network')
- addItem(data[i]);
+ addItem(data[i]);
}
});
}
--
2.7.4
7 years, 9 months
[PATCH][Wok] Bug fix #147: Block authentication request after too many failures
by Ramon Medeiros
To prevent brute force attack, creates a mechanism to allow 3 tries
first. After that, a timeout will start and will be added 30 seconds for
each failed try in a row.
Signed-off-by: Ramon Medeiros <ramonn(a)linux.vnet.ibm.com>
---
src/wok/i18n.py | 3 ++-
src/wok/root.py | 37 ++++++++++++++++++++++++++++++++++---
ui/js/src/wok.login.js | 11 ++++++++++-
ui/pages/login.html.tmpl | 3 ++-
4 files changed, 48 insertions(+), 6 deletions(-)
diff --git a/src/wok/i18n.py b/src/wok/i18n.py
index cbc37cf..c594ae1 100644
--- a/src/wok/i18n.py
+++ b/src/wok/i18n.py
@@ -1,7 +1,7 @@
#
# Project Wok
#
-# Copyright IBM Corp, 2015-2016
+# Copyright IBM Corp, 2015-2017
#
# Code derived from Project Kimchi
#
@@ -41,6 +41,7 @@ messages = {
"WOKAUTH0001E": _("Authentication failed for user '%(username)s'. [Error code: %(code)s]"),
"WOKAUTH0002E": _("You are not authorized to access Kimchi"),
"WOKAUTH0003E": _("Specify %(item)s to login into Kimchi"),
+ "WOKAUTH0004E": _("You have failed to login in too much attempts. Please, wait for %(seconds)s seconds to try again."),
"WOKAUTH0005E": _("Invalid LDAP configuration: %(item)s : %(value)s"),
"WOKLOG0001E": _("Invalid filter parameter. Filter parameters allowed: %(filters)s"),
diff --git a/src/wok/root.py b/src/wok/root.py
index 080b7f0..44e7adb 100644
--- a/src/wok/root.py
+++ b/src/wok/root.py
@@ -1,7 +1,7 @@
#
# Project Wok
#
-# Copyright IBM Corp, 2015-2016
+# Copyright IBM Corp, 2015-2017
#
# Code derived from Project Kimchi
#
@@ -22,6 +22,7 @@
import cherrypy
import json
import os
+import time
from distutils.version import LooseVersion
from wok import auth
@@ -31,7 +32,7 @@ from wok.config import paths as wok_paths
from wok.control import sub_nodes
from wok.control.base import Resource
from wok.control.utils import parse_request
-from wok.exception import MissingParameter
+from wok.exception import MissingParameter, UnauthorizedError
from wok.reqlogger import log_request
@@ -48,7 +49,8 @@ class Root(Resource):
super(Root, self).__init__(model)
self._handled_error = ['error_page.400', 'error_page.404',
'error_page.405', 'error_page.406',
- 'error_page.415', 'error_page.500']
+ 'error_page.415', 'error_page.500',
+ 'error_page.403']
if not dev_env:
self._cp_config = dict([(key, self.error_production_handler)
@@ -146,6 +148,8 @@ class WokRoot(Root):
self.domain = 'wok'
self.messages = messages
self.extends = None
+ self.failed_logins = []
+ self.fail_timeout = 30
# set user log messages and make sure all parameters are present
self.log_map = ROOT_REQUESTS
@@ -153,6 +157,12 @@ class WokRoot(Root):
@cherrypy.expose
def login(self, *args):
+ def _raise_timeout():
+ details = e = UnauthorizedError("WOKAUTH0004E",
+ {"seconds": self.fail_timeout})
+ log_request(code, params, details, method, 403)
+ raise cherrypy.HTTPError(403, e.message)
+
details = None
method = 'POST'
code = self.getRequestMessage(method, 'login')
@@ -166,10 +176,31 @@ class WokRoot(Root):
log_request(code, params, details, method, 400)
raise cherrypy.HTTPError(400, e.message)
+ # check for repetly
+ l = len(self.failed_logins)
+ if l >= 3:
+
+ # verify if timeout is still valid
+ last_try = self.failed_logins[l - 1]
+ if time.time() < (last_try["time"] + self.fail_timeout):
+ _raise_timeout()
try:
status = 200
user_info = auth.login(username, password)
+
+ # user logged sucessfuly: reset counters
+ self.failed_logins = []
+ self.timeout = 30
except cherrypy.HTTPError, e:
+ # store time and prevent too much tries
+ self.failed_logins.append({"user": username,
+ "time": time.time()})
+
+ # more than 3 fails: raise error
+ if len(self.failed_logins) > 3:
+ self.fail_timeout += (len(self.failed_logins) - 3) * 30
+ _raise_timeout()
+
status = e.status
raise
finally:
diff --git a/ui/js/src/wok.login.js b/ui/js/src/wok.login.js
index fa2a98a..ba9ac23 100644
--- a/ui/js/src/wok.login.js
+++ b/ui/js/src/wok.login.js
@@ -1,7 +1,7 @@
/*
* Project Wok
*
- * Copyright IBM Corp, 2015-2016
+ * Copyright IBM Corp, 2015-2017
*
* Code derived from Project Kimchi
*
@@ -71,6 +71,7 @@ wok.login_main = function() {
wok.login(settings, function(data) {
var query = window.location.search;
var next = /.*next=(.*?)(&|$)/g.exec(query);
+
if (next) {
var next_url = decodeURIComponent(next[1]);
}
@@ -84,9 +85,17 @@ wok.login_main = function() {
if (jqXHR.responseText == "") {
$("#messUserPass").hide();
$("#missServer").show();
+ $("#timeoutError").hide();
+ } else if ((jqXHR.responseJSON != undefined) &&
+ ! (jqXHR.responseJSON["reason"] == undefined)) {
+ $("#messUserPass").hide();
+ $("#missServer").hide();
+ $("#timeoutError").html(jqXHR.responseJSON["reason"]);
+ $("#timeoutError").show();
} else {
$("#missServer").hide();
$("#messUserPass").show();
+ $("#timeoutError").hide();
}
$("#messSession").hide();
$("#logging").hide();
diff --git a/ui/pages/login.html.tmpl b/ui/pages/login.html.tmpl
index f5a4b2d..d25910c 100644
--- a/ui/pages/login.html.tmpl
+++ b/ui/pages/login.html.tmpl
@@ -1,7 +1,7 @@
#*
* Project Wok
*
- * Copyright IBM Corp, 2014-2016
+ * Copyright IBM Corp, 2014-2017
*
* Code derived from Project Kimchi
*
@@ -107,6 +107,7 @@
<div id="messUserPass" class="alert alert-danger" style="display: none;">$_("The username or password you entered is incorrect. Please try again.")</div>
<div id="messSession" class="alert alert-danger" style="display: none;">$_("Session timeout, please re-login.")</div>
<div id="missServer" class="alert alert-danger" style="display: none;">$_("Server unreachable.")</div>
+ <div id="timeoutError" class="alert alert-danger" style="display: none;">$_("Timeout error")</div>
</div>
<form id="form-login" class="form-horizontal" method="post">
<div class="form-group">
--
2.7.4
7 years, 9 months
[PATCH v2] [WoK 0/4] 'reload' API implementation
by dhbarboza82@gmail.com
From: Daniel Henrique Barboza <danielhb(a)linux.vnet.ibm.com>
v2:
- changed API name to 'reload'
- added test_api tests
This patch set implements a new WOK API called 'reload' under
/config/reload.
To test it:
$ curl -k -u danielhb -H "Content-Type: application/json" -H "Accept: application/json" -X POST 'https://localhost:8001/config/reload' -d'{}'
Enter host password for user 'danielhb':
{
"proxy_port":"8001",
"websockets_port":"64667",
"version":"2.3.0-55.git5c9127b",
"auth":"pam",
"server_root":""
}
This will reload WoK and all its plug-ins.
Daniel Henrique Barboza (4):
reload API: doc changes
reload API: control and model changes
reload API: new file tests/test_config_model.py
reload API: added rest API tests
docs/API/config.md | 2 +-
src/wok/control/config.py | 4 +++-
src/wok/model/config.py | 7 ++++++-
tests/test_api.py | 9 ++++++++-
tests/test_config_model.py | 41 +++++++++++++++++++++++++++++++++++++++++
5 files changed, 59 insertions(+), 4 deletions(-)
create mode 100644 tests/test_config_model.py
--
2.7.4
7 years, 9 months
[PATCH] [WoK 0/3] 'restart' API implementation
by dhbarboza82@gmail.com
From: Daniel Henrique Barboza <danielhb(a)linux.vnet.ibm.com>
This patch set implements a new WOK API called 'restart' under
/config/restart.
Daniel Henrique Barboza (3):
restart API: doc changes
restart API: control and model changes
restart API: new file tests/test_config_model.py
docs/API/config.md | 2 +-
src/wok/control/config.py | 4 +++-
src/wok/model/config.py | 7 ++++++-
tests/test_config_model.py | 41 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 51 insertions(+), 3 deletions(-)
create mode 100644 tests/test_config_model.py
--
2.7.4
7 years, 9 months
[Wok][RFC] #160: Fedora 25: Make check breaks on wok
by Ramon Medeiros
Issue:
make check on Fedora 25 returns error:
======================================================================
FAIL: test_object_store_threaded (test_objectstore.ObjectStoreTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_objectstore.py", line 105, in test_object_store_threaded
self.assertEquals(10, len(store._connections.keys()))
AssertionError: 10 != 2
Error:
tests/test_objectstore isn't able to deal with function session.store
Propose:
As i saw, the issue is in this function:
def test_object_store_threaded(self):
def worker(ident):
with store as session:
session.store('foo', ident, {})
store = objectstore.ObjectStore(tmpfile)
threads = []
for i in range(50):
t = threading.Thread(target=worker, args=(i,))
t.setDaemon(True)
t.start()
threads.append(t)
for t in threads:
t.join(0)
with store as session:
self.assertEquals(50, len(session.get_list('foo')))
self.assertEquals(10, len(store._connections.keys()))
If a time.sleep is added to worker(), the issue is solved. So, store
cannot handle too much tries, what happens at the first looping. As
using sleep is too ugly, how can i improve the bug fix?
--
Ramon Nunes Medeiros
Kimchi Developer
Linux Technology Center Brazil
IBM Systems & Technology Group
Phone : +55 19 2132 7878
ramonn(a)br.ibm.com
7 years, 9 months
[PATCH][Wok] Issue #160: Fedora 25: Make check breaks on wok
by Ramon Medeiros
Threading identifier was not given a unique name. So, a name will be
passed to force it
Signed-off-by: Ramon Medeiros <ramonn(a)linux.vnet.ibm.com>
---
src/wok/objectstore.py | 4 ++--
tests/test_objectstore.py | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/wok/objectstore.py b/src/wok/objectstore.py
index 817f60c..a571e5f 100644
--- a/src/wok/objectstore.py
+++ b/src/wok/objectstore.py
@@ -1,6 +1,6 @@
# Project Wok
#
-# Copyright IBM Corp, 2015-2016
+# Copyright IBM Corp, 2015-2017
#
# Code derived from Project Kimchi
#
@@ -115,7 +115,7 @@ class ObjectStore(object):
return
def _get_conn(self):
- ident = threading.currentThread().ident
+ ident = threading.currentThread().name
try:
return self._connections[ident]
except KeyError:
diff --git a/tests/test_objectstore.py b/tests/test_objectstore.py
index 3ea7b70..96bcf13 100644
--- a/tests/test_objectstore.py
+++ b/tests/test_objectstore.py
@@ -2,7 +2,7 @@
#
# Project Wok
#
-# Copyright IBM Corp, 2015-2016
+# Copyright IBM Corp, 2015-2017
#
# Code delivered from Project Kimchi
#
@@ -91,7 +91,7 @@ class ObjectStoreTests(unittest.TestCase):
threads = []
for i in xrange(50):
- t = threading.Thread(target=worker, args=(i,))
+ t = threading.Thread(target=worker, args=(i,), name=str(i))
t.setDaemon(True)
t.start()
threads.append(t)
--
2.7.4
7 years, 9 months