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

lvroyce0210 at gmail.com lvroyce0210 at gmail.com
Tue Oct 28 13:37:40 UTC 2014


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")
     cherrypy.session[REFRESH] = time.time()
     cherrypy.session.release_lock()
     return user.get_user()
-- 
1.8.3.2




More information about the Kimchi-devel mailing list