[Kimchi-devel] [PATCH 3/9] authorization: Restrict access to Resource instance

alinefm at linux.vnet.ibm.com alinefm at linux.vnet.ibm.com
Wed Jul 23 20:39:14 UTC 2014


From: Aline Manera <alinefm at linux.vnet.ibm.com>

An user only can perform actions to a Resource if it is not protected or
if the logged user is listed in the resource users and groups parameters.
Also update the tests to reflect those changes.

Signed-off-by: Aline Manera <alinefm at linux.vnet.ibm.com>
---
 src/kimchi/control/base.py  | 28 ++++++++++++++++++++++------
 src/kimchi/control/host.py  |  2 +-
 src/kimchi/exception.py     |  4 ++++
 src/kimchi/i18n.py          |  1 +
 tests/test_authorization.py | 12 ++++++++++--
 tests/test_rest.py          |  2 +-
 6 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/src/kimchi/control/base.py b/src/kimchi/control/base.py
index 674c13b..ac24b3f 100644
--- a/src/kimchi/control/base.py
+++ b/src/kimchi/control/base.py
@@ -27,8 +27,8 @@
 from kimchi.control.utils import parse_request, validate_method
 from kimchi.control.utils import validate_params
 from kimchi.exception import InvalidOperation, InvalidParameter
-from kimchi.exception import KimchiException
-from kimchi.exception import MissingParameter, NotFoundError,  OperationFailed
+from kimchi.exception import KimchiException, MissingParameter, NotFoundError
+from kimchi.exception import OperationFailed, UnauthorizedError
 
 
 class Resource(object):
@@ -65,8 +65,14 @@ def _redirect(self, ident, code=303):
 
     def generate_action_handler(self, action_name, action_args=None):
         def wrapper(*args, **kwargs):
-            validate_method(('POST'))
+            method = validate_method(('POST'),
+                                     self.role_key, self.admin_methods)
+
             try:
+                self.lookup()
+                if not self.is_authorized():
+                    raise UnauthorizedError('KCHAPI0009E')
+
                 model_args = list(self.model_args)
                 if action_args is not None:
                     request = parse_request()
@@ -87,10 +93,12 @@ def wrapper(*args, **kwargs):
                 raise cherrypy.HTTPError(400, e.message)
             except InvalidOperation, e:
                 raise cherrypy.HTTPError(400, e.message)
-            except OperationFailed, e:
-                raise cherrypy.HTTPError(500, e.message)
+            except UnauthorizedError, e:
+                raise cherrypy.HTTPError(403, e.message)
             except NotFoundError, e:
                 raise cherrypy.HTTPError(404, e.message)
+            except OperationFailed, e:
+                raise cherrypy.HTTPError(500, e.message)
             except KimchiException, e:
                 raise cherrypy.HTTPError(500, e.message)
 
@@ -121,8 +129,14 @@ def delete(self):
 
     @cherrypy.expose
     def index(self):
-        method = validate_method(('GET', 'DELETE', 'PUT'))
+        method = validate_method(('GET', 'DELETE', 'PUT'),
+                                 self.role_key, self.admin_methods)
+
         try:
+            self.lookup()
+            if not self.is_authorized():
+                raise UnauthorizedError('KCHAPI0009E')
+
             return {'GET': self.get,
                     'DELETE': self.delete,
                     'PUT': self.update}[method]()
@@ -130,6 +144,8 @@ def index(self):
             raise cherrypy.HTTPError(400, e.message)
         except InvalidParameter, e:
             raise cherrypy.HTTPError(400, e.message)
+        except UnauthorizedError, e:
+            raise cherrypy.HTTPError(403, e.message)
         except NotFoundError, e:
             raise cherrypy.HTTPError(404, e.message)
         except OperationFailed, e:
diff --git a/src/kimchi/control/host.py b/src/kimchi/control/host.py
index e1971cc..c962472 100644
--- a/src/kimchi/control/host.py
+++ b/src/kimchi/control/host.py
@@ -42,7 +42,7 @@ def __init__(self, model, id=None):
 
     @cherrypy.expose
     def swupdate(self):
-        validate_method(('POST'))
+        validate_method(('POST'), self.role_key, self.admin_methods)
         try:
             task = self.model.host_swupdate()
             cherrypy.response.status = 202
diff --git a/src/kimchi/exception.py b/src/kimchi/exception.py
index d84ddb9..9828223 100644
--- a/src/kimchi/exception.py
+++ b/src/kimchi/exception.py
@@ -92,3 +92,7 @@ class IsoFormatError(KimchiException):
 
 class TimeoutExpired(KimchiException):
     pass
+
+
+class UnauthorizedError(KimchiException):
+    pass
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 0c76145..be6c532 100644
--- a/src/kimchi/i18n.py
+++ b/src/kimchi/i18n.py
@@ -31,6 +31,7 @@
     "KCHAPI0006E": _("Unable to parse JSON request"),
     "KCHAPI0007E": _("This API only supports JSON"),
     "KCHAPI0008E": _("Parameters does not match requirement in schema: %(err)s"),
+    "KCHAPI0009E": _("You don't have permission to perform this operation."),
 
     "KCHASYNC0001E": _("Datastore is not initiated in the model object."),
     "KCHASYNC0002E": _("Unable to start task due error: %(err)s"),
diff --git a/tests/test_authorization.py b/tests/test_authorization.py
index 03f8a88..3d0b357 100644
--- a/tests/test_authorization.py
+++ b/tests/test_authorization.py
@@ -116,7 +116,15 @@ def test_nonroot_access(self):
         self.assertEquals(200, resp.status)
         resp = self.request('/vms', req, 'POST')
         self.assertEquals(403, resp.status)
-        resp = self.request('/vms', '{}', 'PUT')
+
+        # Create a vm using mockmodel directly to test Resource access
+        model.templates_create({'name': 'test', 'cdrom': '/nonexistent.iso'})
+        model.vms_create({'name': 'test', 'template': '/templates/test'})
+
+        resp = self.request('/vms/test', '{}', 'PUT')
         self.assertEquals(403, resp.status)
-        resp = self.request('/vms', '{}', 'DELETE')
+        resp = self.request('/vms/test', '{}', 'DELETE')
         self.assertEquals(403, resp.status)
+
+        model.template_delete('test')
+        model.vm_delete('test')
diff --git a/tests/test_rest.py b/tests/test_rest.py
index 54209ef..3c8c537 100644
--- a/tests/test_rest.py
+++ b/tests/test_rest.py
@@ -1207,7 +1207,7 @@ def verify_template(t, res):
         # Test nonexistent fields, specify a field 'foo' isn't in the Template
         t['foo'] = "bar"
         req = json.dumps(t)
-        resp = self.request('/templates/%s' % oldname, req, 'PUT')
+        resp = self.request('/templates/%s' % tmpl_name, req, 'PUT')
         self.assertEquals(400, resp.status)
 
         # Delete the template
-- 
1.9.3




More information about the Kimchi-devel mailing list