pyceo/ceod/model/KerberosService.py

90 lines
3.0 KiB
Python
Raw Normal View History

2021-07-19 01:47:39 -04:00
import os
import subprocess
2021-08-22 00:36:19 -04:00
from typing import List
2021-07-19 01:47:39 -04:00
import gssapi
2021-08-17 21:59:24 -04:00
from zope import component
2021-07-19 01:47:39 -04:00
from zope.interface import implementer
2021-08-17 21:59:24 -04:00
from ceo_common.interfaces import IKerberosService, IConfig
2021-07-19 01:47:39 -04:00
@implementer(IKerberosService)
class KerberosService:
def __init__(self):
2021-08-17 21:59:24 -04:00
cfg = component.getUtility(IConfig)
# For creating new members and renewing memberships, we use the
# admin credentials
self.admin_principal = cfg.get('ldap_admin_principal')
self.admin_principal_name = gssapi.Name(self.admin_principal)
ccache_file = cfg.get('ldap_admin_principal_ccache')
self.admin_principal_ccache = 'FILE:' + ccache_file
self.admin_principal_store = {'ccache': self.admin_principal_ccache}
# For everything else, the clients forwards (delegates) their
# credentials to us. Set KRB5CCNAME to /dev/null to mitigate the
# risk of the admin creds getting accidentally used instead.
2021-08-25 22:19:18 -04:00
os.environ['KRB5CCNAME'] = 'FILE:/dev/null'
2021-07-19 01:47:39 -04:00
def _run(self, args: List[str], **kwargs):
subprocess.run(args, check=True, **kwargs)
def _kinit_admin_creds(self):
env = {'KRB5CCNAME': self.admin_principal_ccache}
self._run([
'kinit', '-k', '-p', self.admin_principal
], env=env)
def _get_admin_creds_token_impl(self) -> bytes:
creds = gssapi.Credentials(
usage='initiate', name=self.admin_principal_name,
store=self.admin_principal_store)
# this will raise a gssapi.raw.exceptions.ExpiredCredentialsError
# if the ticket has expired
creds.inquire()
return creds.export()
def get_admin_creds_token(self) -> bytes:
"""
Returns a serialized GSSAPI credential which can be used to
authenticate to the CSC LDAP server with administrative privileges.
"""
try:
return self._get_admin_creds_token_impl()
except gssapi.raw.misc.GSSError:
# Either the ccache file does not exist, or the ticket has
# expired.
# Run kinit again.
self._kinit_admin_creds()
# This time should work
return self._get_admin_creds_token_impl()
2021-08-22 00:36:19 -04:00
2021-07-19 01:47:39 -04:00
def addprinc(self, principal: str, password: str):
2021-08-22 00:36:19 -04:00
self._run([
2021-07-19 01:47:39 -04:00
'kadmin', '-k', '-p', self.admin_principal, 'addprinc',
'-pw', password,
'-policy', 'default',
'+needchange',
2021-08-13 20:11:56 -04:00
'+requires_preauth',
2021-07-19 01:47:39 -04:00
principal
2021-08-22 00:36:19 -04:00
])
2021-07-19 01:47:39 -04:00
2021-07-24 17:09:10 -04:00
def delprinc(self, principal: str):
2021-08-22 00:36:19 -04:00
self._run([
2021-07-24 17:09:10 -04:00
'kadmin', '-k', '-p', self.admin_principal, 'delprinc',
'-force',
principal
2021-08-22 00:36:19 -04:00
])
2021-07-24 17:09:10 -04:00
2021-07-19 01:47:39 -04:00
def change_password(self, principal: str, password: str):
2021-08-22 00:36:19 -04:00
self._run([
2021-07-19 01:47:39 -04:00
'kadmin', '-k', '-p', self.admin_principal, 'cpw',
'-pw', password,
principal
2021-08-22 00:36:19 -04:00
])
self._run([
2021-07-19 01:47:39 -04:00
'kadmin', '-k', '-p', self.admin_principal, 'modprinc',
'+needchange',
principal
2021-08-22 00:36:19 -04:00
])