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>
---
docs/API.md | 1 +
src/kimchi/auth.py | 111 +++++++++++++++++++++++++++++----------------
src/kimchi/model/config.py | 1 +
3 files changed, 73 insertions(+), 40 deletions(-)
diff --git a/docs/API.md b/docs/API.md
index 9b866f3..9bfbf4f 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -669,6 +669,7 @@ creation.
* repo_mngt_tool: 'deb', 'yum' or None - when the repository
management
tool is not identified
* federation: 'on' if federation feature is enabled, 'off'
otherwise.
+ * auth: authentication type, 'pam' and 'ldap' are supported.
* **POST**: *See Configuration Actions*
**Actions (POST):**
diff --git a/src/kimchi/auth.py b/src/kimchi/auth.py
index c8801a5..5986094 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
@@ -59,6 +60,22 @@ def debug(msg):
class User(object):
+ @classmethod
+ def get(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 +141,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,15 +247,15 @@ 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.get(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()
diff --git a/src/kimchi/model/config.py b/src/kimchi/model/config.py
index 7479050..6a7df41 100644
--- a/src/kimchi/model/config.py
+++ b/src/kimchi/model/config.py
@@ -115,6 +115,7 @@ class CapabilitiesModel(object):
'update_tool': update_tool,
'repo_mngt_tool': repo_mngt_tool,
'federation': kconfig.get("server",
"federation"),
+ 'auth': kconfig.get("authentication",
"method"),
'kernel_vfio': self.kernel_vfio,
}
--
1.8.3.2