@ -2,6 +2,7 @@ import os
import subprocess
from typing import List
import gssapi
from zope import component
from zope . interface import implementer
@ -10,20 +11,53 @@ from ceo_common.interfaces import IKerberosService, IConfig
@implementer ( IKerberosService )
class KerberosService :
def __init__ (
self ,
admin_principal : str ,
) :
def __init__ ( self ) :
cfg = component . getUtility ( IConfig )
self . admin_principal = admin_principal
self . realm = cfg . get ( ' ldap_sasl_realm ' )
# We don't need a credentials cache because the client forwards
# their credentials to us
# 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.
os . environ [ ' KRB5CCNAME ' ] = ' FILE:/dev/null '
def _run ( self , args : List [ str ] ) :
subprocess . run ( args , check = True )
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 ( )
def addprinc ( self , principal : str , password : str ) :
self . _run ( [