
On 02/10/2014 12:32 AM, Leonardo Garcia wrote:
From: Leonardo Garcia <lagarcia@br.ibm.com>
When the /login REST API is called with a valid username and password, Kimchi will find out the user groups and sudo status, store these values in sessions variables, and return them in a JSON message with the following format:
{"sudo": true | false, "userid": "<username>", "groups": [<list of groups>]}
For example:
{"sudo": false, "userid": "guest", "groups": ["guest", "foo"]}
This JSON return message can be used by the UI to figure out which tabs/options should be shown in the web interface according to the user rights.
It is important to notice that sudo configuration for a given user is not as simple as an on/off key. Sudo permits various levels of access controls. For instance, it is possible to specify which executables a user can run with sudo. For the purpose of this implementation, we only consider a user to have sudo rights if this user can run any command in the system with sudo (which is equivalent to have root rights).
Signed-off-by: Leonardo Garcia <lagarcia@br.ibm.com> --- src/kimchi/auth.py | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++---- src/kimchi/root.py | 4 ++-- 2 files changed, 58 insertions(+), 6 deletions(-)
diff --git a/src/kimchi/auth.py b/src/kimchi/auth.py index f9873ca..3ffe4b1 100644 --- a/src/kimchi/auth.py +++ b/src/kimchi/auth.py @@ -30,9 +30,12 @@ import re
from kimchi import template from kimchi.exception import OperationFailed +from kimchi.utils import run_command, parse_cmd_output
-SESSION_USER = 'userid' +USER_ID = 'userid' +USER_GROUPS = 'groups' +USER_SUDO = 'sudo'
def debug(msg): @@ -40,6 +43,52 @@ def debug(msg): # cherrypy.log.error(msg)
+class User(object): + + def __init__(self, userid): + self.user = {} + self.user[USER_ID] = userid + self.user[USER_GROUPS] = [] + self.user[USER_SUDO] = False +
+ def get_groups(self): + out, err, exit = run_command(['groups', self.user[USER_ID]]) + # the output of the groups command is of the form: + # <userid> : <list of groups separated by space> + if exit == 0: + out = parse_cmd_output(out, ['userid', 'groups'], ':') + self.user[USER_GROUPS] = out[0]['groups'].split() + debug("Groups for %s: %s" % (self.user[USER_ID], + self.user[USER_GROUPS])) + return self.user[USER_GROUPS]
You can use grp module here. http://stackoverflow.com/questions/9323834/python-how-to-get-group-ids-of-on...
+ + def has_sudo(self): + out, err, exit = run_command(['sudo', '-l', '-U', self.user[USER_ID], + 'sudo']) + if exit == 0: + debug("User %s is allowed to run sudo" % self.user[USER_ID]) + # sudo allows a wide range of configurations, such as controlling + # which binaries the user can execute with sudo. + # For now, we will just check whether the user is allowed to run any + # command with sudo. + out, err, exit = run_command(['sudo', '-l', '-U', + self.user[USER_ID]]) + for line in out.split('\n'): + if line and re.search("(ALL)", line): + self.user[USER_SUDO] = True + debug("User %s can run any command with sudo" % + self.user[USER_ID]) + return self.user[USER_SUDO] + debug("User %s can only run some commands with sudo" % + self.user[USER_ID]) + else: + debug("User %s is not allowed to run sudo" % self.user[USER_ID]) + return self.user[USER_SUDO] + + def get_user(self): + return self.user + + def authenticate(username, password, service="passwd"): '''Returns True if authenticate is OK via PAM.''' def _pam_conv(auth, query_list, userData=None): @@ -122,13 +171,16 @@ def check_auth_httpba(): def login(userid, password): if not authenticate(userid, password): debug("User cannot be verified with the supplied password") - return False + return None + user = User(userid) debug("User verified, establishing session") cherrypy.session.acquire_lock() cherrypy.session.regenerate() - cherrypy.session[SESSION_USER] = cherrypy.request.login = userid + cherrypy.session[USER_ID] = userid + cherrypy.session[USER_GROUPS] = user.get_groups() + cherrypy.session[USER_SUDO] = user.has_sudo() cherrypy.session.release_lock() - return True + return user.get_user()
def logout(): diff --git a/src/kimchi/root.py b/src/kimchi/root.py index ce4a49c..8e90b7f 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -106,11 +106,11 @@ class KimchiRoot(Root): raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % key)
try: - auth.login(userid, password) + user_info = auth.login(userid, password) except OperationFailed: raise cherrypy.HTTPError(401)
- return '{}' + return json.dumps(user_info)
@cherrypy.expose def logout(self):