[PATCHv5 0/4] LDAP authorization

From: Royce Lv <lvroyce@linux.vnet.ibm.com> Royce Lv (4): Split users and groups for permission query Move validation to authorizaiton change vm permission tag Update test model to fix user/group listing docs/API.md | 19 ++++++---- src/kimchi/control/groups.py | 28 ++++++++++++++ src/kimchi/control/host.py | 14 ------- src/kimchi/control/users.py | 35 +++++++++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/model/groups.py | 68 +++++++++++++++++++++++++++++++++ src/kimchi/model/host.py | 19 ---------- src/kimchi/model/users.py | 90 ++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/model/vms.py | 62 +++++++++++++++++++++--------- tests/test_model.py | 3 +- tests/test_rest.py | 4 +- 11 files changed, 281 insertions(+), 62 deletions(-) create mode 100644 src/kimchi/control/groups.py create mode 100644 src/kimchi/control/users.py create mode 100644 src/kimchi/model/groups.py create mode 100644 src/kimchi/model/users.py -- 1.8.3.2

From: Royce Lv <lvroyce@linux.vnet.ibm.com> Put ldap validation in a single function to resue in authorization. Tested: 1. LDAP: GET /users?_user_id=a_valid_user_id GET /users?_user_id=invalid_user_id GET /groups 2. PAM: GET /users GET /groups Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- docs/API.md | 19 ++++++---- src/kimchi/control/groups.py | 28 ++++++++++++++ src/kimchi/control/host.py | 14 ------- src/kimchi/control/users.py | 35 +++++++++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/model/groups.py | 68 +++++++++++++++++++++++++++++++++ src/kimchi/model/host.py | 19 ---------- src/kimchi/model/users.py | 90 ++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/model/vms.py | 4 +- tests/test_rest.py | 4 +- 10 files changed, 237 insertions(+), 45 deletions(-) create mode 100644 src/kimchi/control/groups.py create mode 100644 src/kimchi/control/users.py create mode 100644 src/kimchi/model/groups.py create mode 100644 src/kimchi/model/users.py diff --git a/docs/API.md b/docs/API.md index 6c36bb1..2c6aa44 100644 --- a/docs/API.md +++ b/docs/API.md @@ -846,23 +846,26 @@ Contains information of host. * swupdate: Start the update of packages in background and return a Task resource * task resource. * See Resource: Task * -### Resource: Host users +### Resource: Users -**URI:** /host/users -List of system users in the host. +**URI:** /users +List of available users. **Methods:** -* **GET**: Retrieve list of system users in the host. +* **GET**: Retrieve list of available users. + * Parameters: + * _user_id: Validate whether user exists. + Essential for 'ldap' authentication. -### Resource: Host groups +### Resource: Groups -**URI:** /host/groups -List of system groups in the host. +**URI:** /groups +List of available groups. **Methods:** -* **GET**: Retrieve list of system groups in the host. +* **GET**: Retrieve list of available groups, only support 'pam' authentication. ### Resource: HostStats diff --git a/src/kimchi/control/groups.py b/src/kimchi/control/groups.py new file mode 100644 index 0000000..f18b2ab --- /dev/null +++ b/src/kimchi/control/groups.py @@ -0,0 +1,28 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# 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 + +from kimchi.control.base import SimpleCollection +from kimchi.control.utils import UrlSubNode + + +@UrlSubNode('groups', True) +class Groups(SimpleCollection): + def __init__(self, model): + super(Groups, self).__init__(model) + self.role_key = 'guests' diff --git a/src/kimchi/control/host.py b/src/kimchi/control/host.py index 4362da7..5a185e3 100644 --- a/src/kimchi/control/host.py +++ b/src/kimchi/control/host.py @@ -36,8 +36,6 @@ class Host(Resource): self.devices = Devices(self.model) self.packagesupdate = PackagesUpdate(self.model) self.repositories = Repositories(self.model) - self.users = Users(self.model) - self.groups = Groups(self.model) self.swupdate = self.generate_action_handler_task('swupdate') @property @@ -159,15 +157,3 @@ class Repository(Resource): @property def data(self): return self.info - - -class Users(SimpleCollection): - def __init__(self, model): - super(Users, self).__init__(model) - self.role_key = 'guests' - - -class Groups(SimpleCollection): - def __init__(self, model): - super(Groups, self).__init__(model) - self.role_key = 'guests' diff --git a/src/kimchi/control/users.py b/src/kimchi/control/users.py new file mode 100644 index 0000000..45603d0 --- /dev/null +++ b/src/kimchi/control/users.py @@ -0,0 +1,35 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# 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 + +from kimchi.control.base import SimpleCollection +from kimchi.control.utils import get_class_name, model_fn, UrlSubNode +from kimchi.template import render + + +@UrlSubNode('users', True) +class Users(SimpleCollection): + def __init__(self, model): + super(Users, self).__init__(model) + self.role_key = 'guests' + + def get(self, filter_params): + res_list = [] + get_list = getattr(self.model, model_fn(self, 'get_list')) + res_list = get_list(*self.model_args, **filter_params) + return render(get_class_name(self), res_list) diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py index 8f6b67e..3d925b3 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -40,6 +40,7 @@ messages = { "KCHAUTH0001E": _("Authentication failed for user '%(username)s'. [Error code: %(code)s]"), "KCHAUTH0002E": _("You are not authorized to access Kimchi"), "KCHAUTH0003E": _("Specify %(item)s to login into Kimchi"), + "KCHAUTH0004E": _("User %(user_id)s not found with given LDAP settings."), "KCHAUTH0005E": _("Invalid LDAP configuration: %(item)s : %(value)s"), "KCHDEVS0001E": _('Unknown "_cap" specified'), diff --git a/src/kimchi/model/groups.py b/src/kimchi/model/groups.py new file mode 100644 index 0000000..5c45b5e --- /dev/null +++ b/src/kimchi/model/groups.py @@ -0,0 +1,68 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# 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 grp +import pwd + +from kimchi.config import config + + +class GroupsModel(object): + def __init__(self, **args): + auth_type = config.get("authentication", "method") + for klass in GroupsModel.__subclasses__(): + if auth_type == klass.auth_type: + self.grp = klass(**args) + + + def get_list(self, **args): + if hasattr(self.grp, '_get_list'): + return self.grp._get_list(**args) + else: + return list() + + def validate(self, gid): + return self.grp._validate(gid) + + +class PAMGroupsModel(GroupsModel): + auth_type = 'pam' + + def __init__(self, **kargs): + pass + + def _get_list(self): + return [group.gr_name for group in grp.getgrall()] + + def _validate(self, gid): + try: + grp.getgrnam(gid) + except KeyError: + return False + return True + + +class LDAPGroupsModel(GroupsModel): + auth_type = 'ldap' + + def __init__(self, **kargs): + pass + + def _validate(self, gid): + return False diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py index 3b43b95..dff89cb 100644 --- a/src/kimchi/model/host.py +++ b/src/kimchi/model/host.py @@ -17,12 +17,10 @@ # 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 grp import libvirt import os import time import platform -import pwd from collections import defaultdict import psutil @@ -458,20 +456,3 @@ class RepositoryModel(object): raise InvalidOperation('KCHREPOS0014E') return self._repositories.removeRepository(repo_id) - - -class UsersModel(object): - def __init__(self, **kargs): - pass - - def get_list(self): - return [user.pw_name for user in pwd.getpwall() - if user.pw_shell.rsplit("/")[-1] not in ["nologin", "false"]] - - -class GroupsModel(object): - def __init__(self, **kargs): - pass - - def get_list(self): - return [group.gr_name for group in grp.getgrall()] diff --git a/src/kimchi/model/users.py b/src/kimchi/model/users.py new file mode 100644 index 0000000..1422bae --- /dev/null +++ b/src/kimchi/model/users.py @@ -0,0 +1,90 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# 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 ldap +import pwd + +from kimchi.config import config +from kimchi.exception import NotFoundError + + +class UsersModel(object): + def __init__(self, **args): + auth_type = config.get("authentication", "method") + for klass in UsersModel.__subclasses__(): + if auth_type == klass.auth_type: + self.user = klass(**args) + + def get_list(self, **args): + return self.user._get_list(**args) + + def validate(self, user): + return self.user._validate(user) + + +class PAMUsersModel(UsersModel): + auth_type = 'pam' + + def __init__(self, **kargs): + pass + + def _get_list(self): + return [user.pw_name for user in pwd.getpwall() + if user.pw_shell.rsplit("/")[-1] not in ["nologin", "false"]] + + def _validate(self, user): + try: + return user in self._get_list() + except: + return False + + +class LDAPUsersModel(UsersModel): + auth_type = 'ldap' + + def __init__(self, **kargs): + pass + + def _get_list(self, _user_id=''): + return self._get_user(_user_id) + + def _validate(self, user): + try: + self._get_user(user) + return True + except NotFoundError: + return False + + def _get_user(self, _user_id): + ldap_server = config.get("authentication", "ldap_server").strip('"') + ldap_search_base = config.get( + "authentication", "ldap_search_base").strip('"') + ldap_search_filter = config.get( + "authentication", "ldap_search_filter", + vars={"username": _user_id.encode("utf-8")}).strip('"') + + connect = ldap.open(ldap_server) + try: + result = connect.search_s( + ldap_search_base, ldap.SCOPE_SUBTREE, ldap_search_filter) + if len(result) == 0: + raise NotFoundError("KCHAUTH0004E", {'user_id': _user_id}) + return result[0][1] + except ldap.NO_SUCH_OBJECT: + raise NotFoundError("KCHAUTH0004E", {'user_id': _user_id}) diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index d861157..7ad5858 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -263,8 +263,8 @@ class VMModel(object): self.objstore = kargs['objstore'] self.caps = CapabilitiesModel(**kargs) self.vmscreenshot = VMScreenshotModel(**kargs) - self.users = import_class('kimchi.model.host.UsersModel')(**kargs) - self.groups = import_class('kimchi.model.host.GroupsModel')(**kargs) + self.users = import_class('kimchi.model.users.UsersModel')(**kargs) + self.groups = import_class('kimchi.model.groups.GroupsModel')(**kargs) self.vms = VMsModel(**kargs) self.task = TaskModel(**kargs) self.storagepool = model.storagepools.StoragePoolModel(**kargs) diff --git a/tests/test_rest.py b/tests/test_rest.py index 0f6cd6d..2e5cff1 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -282,7 +282,7 @@ class RestTests(unittest.TestCase): self.assertEquals(params[key], vm[key]) # change only VM users - groups are not changed (default is empty) - resp = self.request('/host/users', '{}', 'GET') + resp = self.request('/users', '{}', 'GET') users = json.loads(resp.read()) req = json.dumps({'users': users}) resp = self.request('/vms/∨м-црdαtеd', req, 'PUT') @@ -291,7 +291,7 @@ class RestTests(unittest.TestCase): self.assertEquals(users, info['users']) # change only VM groups - users are not changed (default is empty) - resp = self.request('/host/groups', '{}', 'GET') + resp = self.request('/groups', '{}', 'GET') groups = json.loads(resp.read()) req = json.dumps({'groups': groups}) resp = self.request('/vms/∨м-црdαtеd', req, 'PUT') -- 1.8.3.2

From: Royce Lv <lvroyce@linux.vnet.ibm.com> Put validation in user and group class instead of validate in metadata update, so that different type of authorization can use their own authentication to validate input value. Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- src/kimchi/model/vms.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index 7ad5858..eb8c831 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -581,16 +581,16 @@ class VMModel(object): users = groups = None if "users" in params: users = params["users"] - invalid_users = set(users) - set(self.users.get_list()) - if len(invalid_users) != 0: - raise InvalidParameter("KCHVM0027E", - {'users': ", ".join(invalid_users)}) + for user in users: + if not self.users.validate(user): + raise InvalidParameter("KCHVM0027E", + {'users': user}) if "groups" in params: groups = params["groups"] - invalid_groups = set(groups) - set(self.groups.get_list()) - if len(invalid_groups) != 0: - raise InvalidParameter("KCHVM0028E", - {'groups': ", ".join(invalid_groups)}) + for group in groups: + if not self.groups.validate(group): + raise InvalidParameter("KCHVM0028E", + {'groups': group}) if users is None and groups is None: return -- 1.8.3.2

From: Royce Lv <lvroyce@linux.vnet.ibm.com> Add authorization type to vm tag, and update set/retrieve access tag accordingly. So that we can switch between different types of authentication. Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- src/kimchi/model/vms.py | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index eb8c831..b375f8b 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -31,7 +31,7 @@ import libvirt from cherrypy.process.plugins import BackgroundTask from kimchi import model, vnc -from kimchi.config import READONLY_POOL_TYPE +from kimchi.config import READONLY_POOL_TYPE, config from kimchi.exception import InvalidOperation, InvalidParameter from kimchi.exception import NotFoundError, OperationFailed from kimchi.model.config import CapabilitiesModel @@ -46,6 +46,7 @@ from kimchi.utils import add_task, get_next_clone_name, import_class from kimchi.utils import kimchi_log, run_setfacl_set_attr from kimchi.utils import template_name_from_uri from kimchi.xmlutils.utils import xpath_get_text, xml_item_update +from kimchi.xmlutils.utils import dictize DOM_STATE_MAP = {0: 'nostate', @@ -568,17 +569,21 @@ class VMModel(object): 'err': e.message}) def _build_access_elem(self, users, groups): - access = E.access() + auth = config.get("authentication", "method") + auth_elem = E.auth(type=auth) for user in users: - access.append(E.user(user)) + auth_elem.append(E.user(user)) for group in groups: - access.append(E.group(group)) + auth_elem.append(E.group(group)) + access = E.access() + access.append(auth_elem) return access def _vm_update_access_metadata(self, dom, params): users = groups = None + old_users = old_groups = list() if "users" in params: users = params["users"] for user in users: @@ -598,8 +603,19 @@ class VMModel(object): access_xml = (get_metadata_node(dom, "access", self.caps.metadata_support) or """<access></access>""") - old_users = xpath_get_text(access_xml, "/access/user") - old_groups = xpath_get_text(access_xml, "/access/group") + auth = config.get("authentication", "method") + access_info = dictize(access_xml) + auth = config.get("authentication", "method") + if ('auth' in access_info['access'] and + ('type' in access_info['access']['auth'] or + len(access_info['access']['auth']) > 1)): + old_users = xpath_get_text(access_xml, "/access/auth[@type='%s']/user" % auth) + old_groups = xpath_get_text(access_xml, "/access/auth[@type='%s']/group" % auth) + elif auth == 'pam': + # Compatible to old permission tagging + old_users = xpath_get_text(access_xml, "/access/user") + old_groups = xpath_get_text(access_xml, "/access/group") + users = old_users if users is None else users groups = old_groups if groups is None else groups @@ -739,8 +755,18 @@ class VMModel(object): access_xml = (get_metadata_node(dom, "access", self.caps.metadata_support) or """<access></access>""") - users = xpath_get_text(access_xml, "/access/user") - groups = xpath_get_text(access_xml, "/access/group") + access_info = dictize(access_xml) + auth = config.get("authentication", "method") + users = groups = list() + if ('auth' in access_info['access'] and + ('type' in access_info['access']['auth'] or + len(access_info['access']['auth']) > 1)): + users = xpath_get_text(access_xml, "/access/auth[@type='%s']/user" % auth) + groups = xpath_get_text(access_xml, "/access/auth[@type='%s']/group" % auth) + elif auth == 'pam': + # Compatible to old permission tagging + users = xpath_get_text(access_xml, "/access/user") + groups = xpath_get_text(access_xml, "/access/group") return {'name': name, 'state': state, -- 1.8.3.2

On 11/18/2014 12:26 PM, lvroyce0210@gmail.com wrote:
From: Royce Lv <lvroyce@linux.vnet.ibm.com>
Add authorization type to vm tag, and update set/retrieve access tag accordingly. So that we can switch between different types of authentication.
Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- src/kimchi/model/vms.py | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-)
diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index eb8c831..b375f8b 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -31,7 +31,7 @@ import libvirt from cherrypy.process.plugins import BackgroundTask
from kimchi import model, vnc -from kimchi.config import READONLY_POOL_TYPE +from kimchi.config import READONLY_POOL_TYPE, config from kimchi.exception import InvalidOperation, InvalidParameter from kimchi.exception import NotFoundError, OperationFailed from kimchi.model.config import CapabilitiesModel @@ -46,6 +46,7 @@ from kimchi.utils import add_task, get_next_clone_name, import_class from kimchi.utils import kimchi_log, run_setfacl_set_attr from kimchi.utils import template_name_from_uri from kimchi.xmlutils.utils import xpath_get_text, xml_item_update +from kimchi.xmlutils.utils import dictize
DOM_STATE_MAP = {0: 'nostate', @@ -568,17 +569,21 @@ class VMModel(object): 'err': e.message})
def _build_access_elem(self, users, groups): - access = E.access() + auth = config.get("authentication", "method") + auth_elem = E.auth(type=auth) for user in users: - access.append(E.user(user)) + auth_elem.append(E.user(user))
for group in groups: - access.append(E.group(group)) + auth_elem.append(E.group(group))
+ access = E.access() + access.append(auth_elem) return access
def _vm_update_access_metadata(self, dom, params): users = groups = None + old_users = old_groups = list() if "users" in params: users = params["users"] for user in users: @@ -598,8 +603,19 @@ class VMModel(object): access_xml = (get_metadata_node(dom, "access", self.caps.metadata_support) or """<access></access>""")
- old_users = xpath_get_text(access_xml, "/access/user") - old_groups = xpath_get_text(access_xml, "/access/group") + auth = config.get("authentication", "method") + access_info = dictize(access_xml) + auth = config.get("authentication", "method") + if ('auth' in access_info['access'] and + ('type' in access_info['access']['auth'] or + len(access_info['access']['auth']) > 1)): + old_users = xpath_get_text(access_xml, "/access/auth[@type='%s']/user" % auth) + old_groups = xpath_get_text(access_xml, "/access/auth[@type='%s']/group" % auth) + elif auth == 'pam': + # Compatible to old permission tagging + old_users = xpath_get_text(access_xml, "/access/user") + old_groups = xpath_get_text(access_xml, "/access/group") + users = old_users if users is None else users groups = old_groups if groups is None else groups
@@ -739,8 +755,18 @@ class VMModel(object): access_xml = (get_metadata_node(dom, "access", self.caps.metadata_support) or """<access></access>""") - users = xpath_get_text(access_xml, "/access/user") - groups = xpath_get_text(access_xml, "/access/group") + access_info = dictize(access_xml) + auth = config.get("authentication", "method") + users = groups = list() + if ('auth' in access_info['access'] and + ('type' in access_info['access']['auth'] or + len(access_info['access']['auth']) > 1)): + users = xpath_get_text(access_xml, "/access/auth[@type='%s']/user" % auth) + groups = xpath_get_text(access_xml, "/access/auth[@type='%s']/group" % auth) + elif auth == 'pam': + # Compatible to old permission tagging + users = xpath_get_text(access_xml, "/access/user") + groups = xpath_get_text(access_xml, "/access/group")
Those 2 blocks of code are equals, right? Maybe a function is better to have a single point for maintenance.
return {'name': name, 'state': state,

On 2014年11月19日 03:20, Aline Manera wrote:
On 11/18/2014 12:26 PM, lvroyce0210@gmail.com wrote:
From: Royce Lv <lvroyce@linux.vnet.ibm.com>
Add authorization type to vm tag, and update set/retrieve access tag accordingly. So that we can switch between different types of authentication.
Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- src/kimchi/model/vms.py | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-)
diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index eb8c831..b375f8b 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -31,7 +31,7 @@ import libvirt from cherrypy.process.plugins import BackgroundTask
from kimchi import model, vnc -from kimchi.config import READONLY_POOL_TYPE +from kimchi.config import READONLY_POOL_TYPE, config from kimchi.exception import InvalidOperation, InvalidParameter from kimchi.exception import NotFoundError, OperationFailed from kimchi.model.config import CapabilitiesModel @@ -46,6 +46,7 @@ from kimchi.utils import add_task, get_next_clone_name, import_class from kimchi.utils import kimchi_log, run_setfacl_set_attr from kimchi.utils import template_name_from_uri from kimchi.xmlutils.utils import xpath_get_text, xml_item_update +from kimchi.xmlutils.utils import dictize
DOM_STATE_MAP = {0: 'nostate', @@ -568,17 +569,21 @@ class VMModel(object): 'err': e.message})
def _build_access_elem(self, users, groups): - access = E.access() + auth = config.get("authentication", "method") + auth_elem = E.auth(type=auth) for user in users: - access.append(E.user(user)) + auth_elem.append(E.user(user))
for group in groups: - access.append(E.group(group)) + auth_elem.append(E.group(group))
+ access = E.access() + access.append(auth_elem) return access
def _vm_update_access_metadata(self, dom, params): users = groups = None + old_users = old_groups = list() if "users" in params: users = params["users"] for user in users: @@ -598,8 +603,19 @@ class VMModel(object): access_xml = (get_metadata_node(dom, "access", self.caps.metadata_support) or """<access></access>""")
- old_users = xpath_get_text(access_xml, "/access/user") - old_groups = xpath_get_text(access_xml, "/access/group") + auth = config.get("authentication", "method") + access_info = dictize(access_xml) + auth = config.get("authentication", "method") + if ('auth' in access_info['access'] and + ('type' in access_info['access']['auth'] or + len(access_info['access']['auth']) > 1)): + old_users = xpath_get_text(access_xml, "/access/auth[@type='%s']/user" % auth) + old_groups = xpath_get_text(access_xml, "/access/auth[@type='%s']/group" % auth) + elif auth == 'pam': + # Compatible to old permission tagging + old_users = xpath_get_text(access_xml, "/access/user") + old_groups = xpath_get_text(access_xml, "/access/group") + users = old_users if users is None else users groups = old_groups if groups is None else groups
@@ -739,8 +755,18 @@ class VMModel(object): access_xml = (get_metadata_node(dom, "access", self.caps.metadata_support) or """<access></access>""") - users = xpath_get_text(access_xml, "/access/user") - groups = xpath_get_text(access_xml, "/access/group") + access_info = dictize(access_xml) + auth = config.get("authentication", "method") + users = groups = list() + if ('auth' in access_info['access'] and + ('type' in access_info['access']['auth'] or + len(access_info['access']['auth']) > 1)): + users = xpath_get_text(access_xml, "/access/auth[@type='%s']/user" % auth) + groups = xpath_get_text(access_xml, "/access/auth[@type='%s']/group" % auth) + elif auth == 'pam': + # Compatible to old permission tagging + users = xpath_get_text(access_xml, "/access/user") + groups = xpath_get_text(access_xml, "/access/group")
Those 2 blocks of code are equals, right? Maybe a function is better to have a single point for maintenance.
ACK
return {'name': name, 'state': state,
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel

From: Royce Lv <lvroyce@linux.vnet.ibm.com> As test model includes test against pam user/group listing, using pam authentication instead of fake authentication. Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- tests/test_model.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_model.py b/tests/test_model.py index c68b01f..0b91edc 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -38,7 +38,7 @@ import iso_gen import kimchi.objectstore import utils from kimchi import netinfo -from kimchi.config import paths +from kimchi.config import config, paths from kimchi.exception import ImageFormatError, InvalidOperation from kimchi.exception import InvalidParameter, NotFoundError, OperationFailed from kimchi.iscsi import TargetClient @@ -934,6 +934,7 @@ class ModelTests(unittest.TestCase): 'new-test', params) def test_vm_edit(self): + config.set("authentication", "method", "pam") inst = model.Model(None, objstore_loc=self.tmp_store) -- 1.8.3.2
participants (3)
-
Aline Manera
-
lvroyce0210@gmail.com
-
Royce Lv