[Kimchi-devel] [PATCHv2 2/7] Split PAM and LDAP authentication

Royce Lv lvroyce at linux.vnet.ibm.com
Thu Nov 6 06:16:26 UTC 2014


On 2014年10月31日 01:09, Aline Manera wrote:
>
> On 10/28/2014 11:37 AM, lvroyce0210 at gmail.com wrote:
>> From: Royce Lv <lvroyce at linux.vnet.ibm.com>
>>
>> Split PAM authentication implementation and abstract a common class.
>>
>> Signed-off-by: Royce Lv <lvroyce at linux.vnet.ibm.com>
>> ---
>> src/kimchi/auth.py | 113 
>> ++++++++++++++++++++++++++++++++++-------------------
>> 1 file changed, 73 insertions(+), 40 deletions(-)
>>
>> diff --git a/src/kimchi/auth.py b/src/kimchi/auth.py
>> index c8801a5..ad3f3ac 100644
>> --- a/src/kimchi/auth.py
>> +++ b/src/kimchi/auth.py
>> @@ -31,6 +31,7 @@ import urllib2
>>
>>
>> from kimchi import template
>> +from kimchi.config import config
>> from kimchi.exception import InvalidOperation, OperationFailed
>> from kimchi.utils import get_all_tabs, run_command
>>
>> @@ -39,6 +40,7 @@ USER_NAME = 'username'
>> USER_GROUPS = 'groups'
>> USER_ROLES = 'roles'
>> REFRESH = 'robot-refresh'
>
>> +AUTH = 'auth_method'
>
>
>>
>> tabs = get_all_tabs()
>>
>> @@ -59,6 +61,22 @@ def debug(msg):
>>
>>
>> class User(object):
>> + @classmethod
>> + def create(cls, auth_args):
>> + auth_type = auth_args.pop('auth_type')
>> + for klass in cls.__subclasses__():
>> + if auth_type == klass.auth_type:
>> + try:
>> + if not klass.authenticate(**auth_args):
>> + debug("cannot verify user with the given password")
>> + return None
>> + except OperationFailed:
>> + raise
>> + return klass(auth_args['username'])
>> +
>> +
>> +class PAMUser(User):
>> + auth_type = "pam"
>>
>> def __init__(self, username):
>> self.user = {}
>> @@ -124,40 +142,54 @@ class User(object):
>> def get_user(self):
>> return self.user
>>
>> + @staticmethod
>> + def authenticate(username, password, service="passwd"):
>> + '''Returns True if authenticate is OK via PAM.'''
>> + def _pam_conv(auth, query_list, userData=None):
>> + resp = []
>> + for i in range(len(query_list)):
>> + query, qtype = query_list[i]
>> + if qtype == PAM.PAM_PROMPT_ECHO_ON:
>> + resp.append((username, 0))
>> + elif qtype == PAM.PAM_PROMPT_ECHO_OFF:
>> + resp.append((password, 0))
>> + elif qtype == PAM.PAM_PROMPT_ERROR_MSG:
>> + cherrypy.log.error_log.error(
>> + "PAM authenticate prompt error: %s" % query)
>> + resp.append(('', 0))
>> + elif qtype == PAM.PAM_PROMPT_TEXT_INFO:
>> + resp.append(('', 0))
>> + else:
>> + return None
>> + return resp
>> +
>> + auth = PAM.pam()
>> + auth.start(service)
>> + auth.set_item(PAM.PAM_USER, username)
>> + auth.set_item(PAM.PAM_CONV, _pam_conv)
>> + try:
>> + auth.authenticate()
>> + except PAM.error, (resp, code):
>> + msg_args = {'username': username, 'code': code}
>> + raise OperationFailed("KCHAUTH0001E", msg_args)
>>
>> -def authenticate(username, password, service="passwd"):
>> - '''Returns True if authenticate is OK via PAM.'''
>> - def _pam_conv(auth, query_list, userData=None):
>> - resp = []
>> - for i in range(len(query_list)):
>> - query, qtype = query_list[i]
>> - if qtype == PAM.PAM_PROMPT_ECHO_ON:
>> - resp.append((username, 0))
>> - elif qtype == PAM.PAM_PROMPT_ECHO_OFF:
>> - resp.append((password, 0))
>> - elif qtype == PAM.PAM_PROMPT_ERROR_MSG:
>> - cherrypy.log.error_log.error("PAM authenticate prompt error "
>> - "message: %s" % query)
>> - resp.append(('', 0))
>> - elif qtype == PAM.PAM_PROMPT_TEXT_INFO:
>> - resp.append(('', 0))
>> - else:
>> - return None
>> - return resp
>> -
>> - auth = PAM.pam()
>> - auth.start(service)
>> - auth.set_item(PAM.PAM_USER, username)
>> - auth.set_item(PAM.PAM_CONV, _pam_conv)
>> -
>> - try:
>> - auth.authenticate()
>> - except PAM.error:
>> - raise
>> -
>> - return True
>> + return True
>>
>>
>> +class LDAPUser(User):
>> + auth_type = "ldap"
>> + def __init__(self, username):
>> + self.user = {}
>> + self.user[USER_NAME] = username
>> + self.user[USER_GROUPS] = None
>> + # FIXME: user roles will be changed according roles assignment after
>> + # objstore is integrated
>> + self.user[USER_ROLES] = dict.fromkeys(tabs, 'user')
>> +
>> + @staticmethod
>> + def authenticate(username, password):
>> + return False
>> +
>> def from_browser():
>> # Enable Basic Authentication for REST tools.
>> # Ajax request sent from jQuery in browser will have "X-Requested-With"
>> @@ -216,21 +248,22 @@ def check_auth_httpba():
>>
>>
>> def login(username, password, **kwargs):
>> - try:
>> - if not authenticate(username, password):
>> - debug("User cannot be verified with the supplied password")
>> - return None
>> - except PAM.error, (resp, code):
>> - msg_args = {'username': username, 'code': code}
>> - raise OperationFailed("KCHAUTH0001E", msg_args)
>> -
>> - user = User(username)
>> + auth_args = {'auth_type': config.get("authentication", "method"),
>> + 'username': username,
>> + 'password': password}
>> +
>> + user = User.create(auth_args)
>> + if not user:
>> + debug("User cannot be verified with the supplied password")
>> + return None
>> +
>> debug("User verified, establishing session")
>> cherrypy.session.acquire_lock()
>> cherrypy.session.regenerate()
>> cherrypy.session[USER_NAME] = username
>> cherrypy.session[USER_GROUPS] = user.get_groups()
>> cherrypy.session[USER_ROLES] = user.get_roles()
>
>> + cherrypy.session[AUTH] = config.get("authentication", "method")
>
> Do we really need to store it on the session? It was not used in the 
> other patches.
As UI will be interested in what kind of authentication backend is using 
to choose display "pam" permission tagging or "ldap" permission tagging
After talked with YuXin, he suggested to move it to /host/capabilities 
rather than put it in cookie, because not every part of UI interested in 
authentication method,
do you agree?
>
>> cherrypy.session[REFRESH] = time.time()
>> cherrypy.session.release_lock()
>> return user.get_user()
>
> _______________________________________________
> Kimchi-devel mailing list
> Kimchi-devel at ovirt.org
> http://lists.ovirt.org/mailman/listinfo/kimchi-devel
>




More information about the Kimchi-devel mailing list