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

Aline Manera alinefm at linux.vnet.ibm.com
Thu Oct 30 17:09:12 UTC 2014


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.

>       cherrypy.session[REFRESH] = time.time()
>       cherrypy.session.release_lock()
>       return user.get_user()




More information about the Kimchi-devel mailing list