[Kimchi-devel] [PATCHv3 5/8] Split users and groups for permission query

Royce Lv lvroyce at linux.vnet.ibm.com
Thu Nov 13 07:46:03 UTC 2014


On 2014年11月12日 19:53, Aline Manera wrote:
>
> On 11/10/2014 05:09 AM, lvroyce at linux.vnet.ibm.com wrote:
>> From: Royce Lv <lvroyce at 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
>
> You need to adjust the docs/API.md to reflect those changes.
ACK
>
>>
>> Signed-off-by: Royce Lv <lvroyce at linux.vnet.ibm.com>
>> ---
>>   src/kimchi/control/auth.py |  42 ++++++++++++++
>>   src/kimchi/control/host.py |  14 -----
>>   src/kimchi/i18n.py         |   1 +
>>   src/kimchi/model/auth.py   | 136 
>> +++++++++++++++++++++++++++++++++++++++++++++
>>   src/kimchi/model/host.py   |  19 -------
>>   src/kimchi/model/vms.py    |   4 +-
>>   tests/test_rest.py         |   4 +-
>>   7 files changed, 183 insertions(+), 37 deletions(-)
>>   create mode 100644 src/kimchi/control/auth.py
>>   create mode 100644 src/kimchi/model/auth.py
>>
>> diff --git a/src/kimchi/control/auth.py b/src/kimchi/control/auth.py
>> new file mode 100644
>> index 0000000..ebc019e
>> --- /dev/null
>> +++ b/src/kimchi/control/auth.py
>
> Name it as users.py and groups.py
>
>> @@ -0,0 +1,42 @@
>> +#
>> +# 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
>> +
>
>> +
>> + at 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)
>> +
>> +
>> + at UrlSubNode('groups', True)
>> +class Groups(SimpleCollection):
>> +    def __init__(self, model):
>> +        super(Groups, self).__init__(model)
>> +        self.role_key = 'guests'
>
> Split it in 2 files: users.py and groups.py as we have done one URI 
> per file to make maintenance easier.
ACK
>
>> 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/i18n.py b/src/kimchi/i18n.py
>> index f789259..4e5a59b 100644
>> --- a/src/kimchi/i18n.py
>> +++ b/src/kimchi/i18n.py
>> @@ -39,6 +39,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."),
>>         "KCHDEVS0001E": _('Unknown "_cap" specified'),
>>       "KCHDEVS0002E": _('"_passthrough" should be "true" or "false"'),
>> diff --git a/src/kimchi/model/auth.py b/src/kimchi/model/auth.py
>> new file mode 100644
>> index 0000000..d52c919
>> --- /dev/null
>> +++ b/src/kimchi/model/auth.py
>> @@ -0,0 +1,136 @@
>> +#
>> +# 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 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})
>> +
>> +
>
> Same here. One URI per file.
ACK
>
>> +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 8cddcdc..009f448 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
>> @@ -457,20 +455,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/vms.py b/src/kimchi/model/vms.py
>> index f2e4ae3..8f14f9e 100644
>> --- a/src/kimchi/model/vms.py
>> +++ b/src/kimchi/model/vms.py
>> @@ -249,8 +249,8 @@ class VMModel(object):
>>           self.conn = kargs['conn']
>>           self.objstore = kargs['objstore']
>>           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.auth.UsersModel')(**kargs)
>> +        self.groups = 
>> import_class('kimchi.model.auth.GroupsModel')(**kargs)
>>         def update(self, name, params):
>>           dom = self.get_vm(name, self.conn)
>> diff --git a/tests/test_rest.py b/tests/test_rest.py
>> index 9bc930f..420bfd0 100644
>> --- a/tests/test_rest.py
>> +++ b/tests/test_rest.py
>> @@ -277,7 +277,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')
>> @@ -286,7 +286,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')
>




More information about the Kimchi-devel mailing list