diff --git a/ocflib/account/utils.py b/ocflib/account/utils.py index 90f9de60..56824860 100644 --- a/ocflib/account/utils.py +++ b/ocflib/account/utils.py @@ -2,11 +2,15 @@ import grp import os.path import re +import subprocess import pexpect import ocflib.account.validators as validators from ocflib.infra.ldap import OCF_LDAP_PEOPLE +import ocflib.misc.krb5 + +LDAP_MAIL_ATTR = 'mail' def password_matches(username, password): @@ -91,3 +95,31 @@ def dn_for_username(username): user=username, base_people=OCF_LDAP_PEOPLE, ) + + +def get_email(username, have_ticket=True, operatorname=""): + """Returns current email, or None.""" + """Assume a ticket is created already, otherwise this'd require username and help you do that""" + + if not have_ticket: + if operatorname == "": + # Or do you want this to just automatically be current user? + raise ValueError("Operator username must not be empty.") + ocflib.misc.krb5.kerberos_init(operatorname) + + # Since the mail attribute is private, and we can't get the attribute's + # value without authenticating, we have to use ldapsearch here instead of + # something like ldap3. + output = subprocess.check_output( + ('ldapsearch', '-LLL', 'uid={}'.format(username), LDAP_MAIL_ATTR), + stderr=subprocess.DEVNULL, + ).decode('utf-8').split('\n') + + if not have_ticket: + ocflib.misc.krb5.kerberos_destroy() + + mail_attr = [attr for attr in output if attr.startswith(LDAP_MAIL_ATTR + ': ')] + + if mail_attr: + # Strip the '{LDAP_MAIL_ATTR}: ' from the beginning of the string + return mail_attr[0][len(LDAP_MAIL_ATTR) + 2:].strip() diff --git a/ocflib/misc/krb5.py b/ocflib/misc/krb5.py new file mode 100644 index 00000000..dbb92124 --- /dev/null +++ b/ocflib/misc/krb5.py @@ -0,0 +1,25 @@ +"""Some utilities for shelling out and do kerberos stuff. +This should be considered temporary and find a non-shell out solution for our happiness""" +import json +import subprocess + +# Initiates a kerberos ticket for current user +# Returns True when a new ticket is created via kinit so that we destroy it afterwards +# Raises OSError is kinit screwed up + + +def kerberos_init(username): + klist = subprocess.run(['sudo', '-u', username, 'klist', '--json'], stdout=subprocess.PIPE) + if klist.returncode == 0: + cache_info = json.loads(klist.stdout.decode()) + if cache_info.get('principal') == '{}/admin@OCF.BERKELEY.EDU'.format(username): + return False + if (subprocess.call(['kinit', '{}/admin'.format(username)]) != 0): + # Or some other kinds of Exception + raise OSError('Kinit failed.') + else: + return True + + +def kerberos_destroy(): + return subprocess.call(['kdestroy'])