[Kimchi-devel] [PATCH] Block access for non-root users
Daniel H Barboza
danielhb at linux.vnet.ibm.com
Tue Feb 18 21:03:14 UTC 2014
Reviewed-by: Daniel Barboza <danielhb at linux.vnet.ibm.com>
On 02/18/2014 03:23 PM, Aline Manera wrote:
> From: Aline Manera <alinefm at br.ibm.com>
>
> Non-root users must have restricted access to Kimchi.
> This patch block non-root urser to:
> - get or create debug reports;
> - reboot or shutdown host system;
> - create, activate/deactivate or delete networks;
> - create, activate/deactivate or delete storage pools;
> - update or delete templates;
> - create, start/stop/connect or delete vms.
>
> It also updates the tests cases to always run as a root user.
> And add authorization tests to make sure non-root users have restricted
> access to kimchi.
>
> Signed-off-by: Aline Manera <alinefm at br.ibm.com>
> ---
> src/kimchi/control/debugreports.py | 2 +-
> src/kimchi/control/host.py | 2 +-
> src/kimchi/control/networks.py | 2 +-
> src/kimchi/control/storagepools.py | 2 +-
> src/kimchi/control/templates.py | 2 +-
> src/kimchi/control/vms.py | 2 +-
> tests/Makefile.am | 1 +
> tests/test_authorization.py | 124 ++++++++++++++++++++++++++++++++++++
> tests/utils.py | 23 ++++++-
> 9 files changed, 153 insertions(+), 7 deletions(-)
> create mode 100644 tests/test_authorization.py
>
> diff --git a/src/kimchi/control/debugreports.py b/src/kimchi/control/debugreports.py
> index 324d826..57dc0f3 100644
> --- a/src/kimchi/control/debugreports.py
> +++ b/src/kimchi/control/debugreports.py
> @@ -26,7 +26,7 @@ from kimchi.control.utils import internal_redirect
> from kimchi.control.utils import UrlSubNode
>
>
> - at UrlSubNode("debugreports", True)
> + at UrlSubNode("debugreports", True, ['GET', 'POST'])
> class DebugReports(AsyncCollection):
> def __init__(self, model):
> super(DebugReports, self).__init__(model)
> diff --git a/src/kimchi/control/host.py b/src/kimchi/control/host.py
> index 0852bd0..41e0040 100644
> --- a/src/kimchi/control/host.py
> +++ b/src/kimchi/control/host.py
> @@ -31,7 +31,7 @@ from kimchi.exception import OperationFailed
> from kimchi.template import render
>
>
> - at UrlSubNode("host", True)
> + at UrlSubNode("host", True, ['POST'])
> class Host(Resource):
> def __init__(self, model, id=None):
> super(Host, self).__init__(model, id)
> diff --git a/src/kimchi/control/networks.py b/src/kimchi/control/networks.py
> index 8510e49..3a02f60 100644
> --- a/src/kimchi/control/networks.py
> +++ b/src/kimchi/control/networks.py
> @@ -25,7 +25,7 @@ from kimchi.control.base import Collection, Resource
> from kimchi.control.utils import UrlSubNode
>
>
> - at UrlSubNode("networks", True)
> + at UrlSubNode("networks", True, ['POST', 'DELETE'])
> class Networks(Collection):
> def __init__(self, model):
> super(Networks, self).__init__(model)
> diff --git a/src/kimchi/control/storagepools.py b/src/kimchi/control/storagepools.py
> index ea19609..7e6bdd7 100644
> --- a/src/kimchi/control/storagepools.py
> +++ b/src/kimchi/control/storagepools.py
> @@ -34,7 +34,7 @@ from kimchi.model.storagepools import ISO_POOL_NAME
> from kimchi.control.utils import UrlSubNode
>
>
> - at UrlSubNode("storagepools", True)
> + at UrlSubNode("storagepools", True, ['POST', 'DELETE'])
> class StoragePools(Collection):
> def __init__(self, model):
> super(StoragePools, self).__init__(model)
> diff --git a/src/kimchi/control/templates.py b/src/kimchi/control/templates.py
> index 58dafcc..8135e32 100644
> --- a/src/kimchi/control/templates.py
> +++ b/src/kimchi/control/templates.py
> @@ -25,7 +25,7 @@ from kimchi.control.base import Collection, Resource
> from kimchi.control.utils import UrlSubNode
>
>
> - at UrlSubNode("templates", True)
> + at UrlSubNode("templates", True, ['PUT', 'DELETE'])
> class Templates(Collection):
> def __init__(self, model):
> super(Templates, self).__init__(model)
> diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py
> index 60fc8ff..a74ce27 100644
> --- a/src/kimchi/control/vms.py
> +++ b/src/kimchi/control/vms.py
> @@ -27,7 +27,7 @@ from kimchi.control.utils import internal_redirect, UrlSubNode
> from kimchi.control.vm import sub_nodes
>
>
> - at UrlSubNode("vms", True)
> + at UrlSubNode("vms", True, ['POST', 'PUT', 'DELETE'])
> class VMs(Collection):
> def __init__(self, model):
> super(VMs, self).__init__(model)
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index 0487ffc..e8db05c 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -24,6 +24,7 @@ EXTRA_DIST = \
> Makefile.am \
> run_tests.sh.in \
> iso_gen.py \
> + test_authorization.py \
> test_config.py.in \
> test_exception.py \
> test_mockmodel.py \
> diff --git a/tests/test_authorization.py b/tests/test_authorization.py
> new file mode 100644
> index 0000000..7f939a8
> --- /dev/null
> +++ b/tests/test_authorization.py
> @@ -0,0 +1,124 @@
> +#
> +# Project Kimchi
> +#
> +# Copyright IBM, Corp. 2013
> +#
> +# Authors:
> +# Aline Manera <alinefm at linux.vnet.ibm.com>
> +#
> +# This library is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU Lesser General Public
> +# License as published by the Free Software Foundation; either
> +# version 2.1 of the License, or (at your option) any later version.
> +#
> +# This library is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> +# Lesser General Public License for more details.
> +#
> +# You should have received a copy of the GNU Lesser General Public
> +# License along with this library; if not, write to the Free Software
> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> +
> +import json
> +import os
> +import unittest
> +
> +
> +from functools import partial
> +
> +
> +import kimchi.mockmodel
> +from utils import get_free_port, patch_auth, request
> +from utils import run_server
> +
> +
> +test_server = None
> +model = None
> +host = None
> +port = None
> +ssl_port = None
> +
> +
> +def setUpModule():
> + global test_server, model, host, port, ssl_port
> +
> + patch_auth(sudo = False)
> + model = kimchi.mockmodel.MockModel('/tmp/obj-store-test')
> + host = '127.0.0.1'
> + port = get_free_port('http')
> + test_server = run_server(host, port, None, test_mode=True, model=model)
> +
> +
> +def tearDownModule():
> + test_server.stop()
> + os.unlink('/tmp/obj-store-test')
> +
> +
> +class AuthorizationTests(unittest.TestCase):
> + def setUp(self):
> + self.request = partial(request, host, port)
> + model.reset()
> +
> + def test_nonroot_access(self):
> + # Non-root users can access static host information
> + resp = self.request('/host', '{}', 'GET')
> + self.assertEquals(200, resp.status)
> +
> + # Non-root users can access host stats
> + resp = self.request('/host/stats', '{}', 'GET')
> + self.assertEquals(200, resp.status)
> +
> + # Non-root users can not reboot/shutdown host system
> + resp = self.request('/host/reboot', '{}', 'POST')
> + self.assertEquals(401, resp.status)
> + resp = self.request('/host/shutdown', '{}', 'POST')
> + self.assertEquals(401, resp.status)
> +
> + # Non-root users can not get or debug reports
> + resp = self.request('/debugreports', '{}', 'GET')
> + self.assertEquals(401, resp.status)
> + resp = self.request('/debugreports', '{}', 'POST')
> + self.assertEquals(401, resp.status)
> +
> + # Non-root users can not create or delete network (only get)
> + resp = self.request('/networks', '{}', 'GET')
> + self.assertEquals(200, resp.status)
> + resp = self.request('/networks', '{}', 'POST')
> + self.assertEquals(401, resp.status)
> + resp = self.request('/networks/default/activate', '{}', 'POST')
> + self.assertEquals(401, resp.status)
> + resp = self.request('/networks/default', '{}', 'DELETE')
> + self.assertEquals(401, resp.status)
> +
> + # Non-root users can not create or delete storage pool (only get)
> + resp = self.request('/storagepools', '{}', 'GET')
> + self.assertEquals(200, resp.status)
> + resp = self.request('/storagepools', '{}', 'POST')
> + self.assertEquals(401, resp.status)
> + resp = self.request('/storagepools/default/activate', '{}', 'POST')
> + self.assertEquals(401, resp.status)
> + resp = self.request('/storagepools/default', '{}', 'DELETE')
> + self.assertEquals(401, resp.status)
> +
> + # Non-root users can not update or delete a template
> + # but he can get and create a new one
> + resp = self.request('/templates', '{}', 'GET')
> + self.assertEquals(200, resp.status)
> + req = json.dumps({'name': 'test', 'cdrom': '/nonexistent.iso'})
> + resp = self.request('/templates', req, 'POST')
> + self.assertEquals(201, resp.status)
> + resp = self.request('/templates/test', '{}', 'PUT')
> + self.assertEquals(401, resp.status)
> + resp = self.request('/templates/test', '{}', 'DELETE')
> + self.assertEquals(401, resp.status)
> +
> + # Non-root users can only get vms
> + resp = self.request('/vms', '{}', 'GET')
> + self.assertEquals(200, resp.status)
> + resp = self.request('/vms', req, 'POST')
> + self.assertEquals(401, resp.status)
> + resp = self.request('/vms', '{}', 'PUT')
> + self.assertEquals(401, resp.status)
> + resp = self.request('/vms', '{}', 'DELETE')
> + self.assertEquals(401, resp.status)
> diff --git a/tests/utils.py b/tests/utils.py
> index 14c57d4..18b707c 100644
> --- a/tests/utils.py
> +++ b/tests/utils.py
> @@ -147,11 +147,31 @@ def https_request(host, port, path, data=None, method='GET', headers=None):
> return _request(conn, path, data, method, headers)
>
>
> -def patch_auth():
> +def patch_auth(sudo=True):
> """
> Override the authenticate function with a simple test against an
> internal dict of users and passwords.
> """
> + USER_ID = 'userid'
> + USER_GROUPS = 'groups'
> + USER_SUDO = 'sudo'
> +
> + class _User(object):
> + def __init__(self, userid):
> + self.user = {}
> + self.user[USER_ID] = userid
> + self.user[USER_GROUPS] = None
> + self.user[USER_SUDO] = sudo
> +
> + def get_groups(self):
> + return self.user[USER_GROUPS]
> +
> + def has_sudo(self):
> + return self.user[USER_SUDO]
> +
> + def get_user(self):
> + return self.user
> +
> def _authenticate(username, password, service="passwd"):
> try:
> return fake_user[username] == password
> @@ -161,6 +181,7 @@ def patch_auth():
>
> import kimchi.auth
> kimchi.auth.authenticate = _authenticate
> + kimchi.auth.User = _User
>
>
> def normalize_xml(xml_str):
More information about the Kimchi-devel
mailing list