On 11/06/2014 04:16 AM, Royce Lv wrote:
On 2014年10月31日 01:09, Aline Manera wrote:
>
> On 10/28/2014 11:37 AM, lvroyce0210(a)gmail.com wrote:
>> From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
>>
>> Split PAM authentication implementation and abstract a common class.
>>
>> Signed-off-by: Royce Lv <lvroyce(a)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?
Yeap. Sounds good for me.
>
>> cherrypy.session[REFRESH] = time.time()
>> cherrypy.session.release_lock()
>> return user.get_user()
>
> _______________________________________________
> Kimchi-devel mailing list
> Kimchi-devel(a)ovirt.org
>
http://lists.ovirt.org/mailman/listinfo/kimchi-devel
>