From 784505e0dfaea9b4ac88c900734120bb947e7375 Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Fri, 27 Mar 2020 13:46:42 -0400 Subject: imap-dl: Fix failure when python3-gssapi isn't installed The type annotation of the SecurityContext in GSSAPI_helper causes python to actually use the gssapi object, which is None when python3-gssapi isn't present. Work around this by making the class definition contingent on the presence of python3-gssapi. Signed-off-by: Robbie Harwood --- imap-dl | 68 +++++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/imap-dl b/imap-dl index 5a8494c..a644549 100755 --- a/imap-dl +++ b/imap-dl @@ -95,39 +95,41 @@ def auth_builtin(username:str, imap:imaplib.IMAP4_SSL, if resp[0] != 'OK': raise Exception(f'login failed with {resp} as user {username} on {server}') -# imaplib auth methods need to be in the form of callables, and they all -# requre both additional parameters and storage beyond what the function -# interface provides. -class GSSAPI_handler(): - gss_vc:gssapi.SecurityContext - username:str - - def __init__(self, server:str, username:str) -> None: - name = gssapi.Name(f'imap@{server}', gssapi.NameType.hostbased_service) - self.gss_vc = gssapi.SecurityContext(usage="initiate", name=name) - self.username = username - - def __call__(self, token:Optional[bytes]) -> bytes: - if token == b"": - token = None - if not self.gss_vc.complete: - response = self.gss_vc.step(token) - return response if response else b"" # type: ignore - elif token is None: - return b"" - - response = self.gss_vc.unwrap(token) - - # Preserve the "length" of the message we received, and set the first - # byte to one. If username is provided, it's next. - reply:List[int] = [] - reply[0:4] = response.message[0:4] - reply[0] = 1 - if self.username: - reply[5:] = self.username.encode("utf-8") - - response = self.gss_vc.wrap(bytes(reply), response.encrypted) - return response.message if response.message else b"" # type: ignore +if gssapi: + # imaplib auth methods need to be in the form of callables, and they all + # requre both additional parameters and storage beyond what the function + # interface provides. + class GSSAPI_handler(): + gss_vc:gssapi.SecurityContext + username:str + + def __init__(self, server:str, username:str) -> None: + name = gssapi.Name(f'imap@{server}', + gssapi.NameType.hostbased_service) + self.gss_vc = gssapi.SecurityContext(usage="initiate", name=name) + self.username = username + + def __call__(self, token:Optional[bytes]) -> bytes: + if token == b"": + token = None + if not self.gss_vc.complete: + response = self.gss_vc.step(token) + return response if response else b"" # type: ignore + elif token is None: + return b"" + + response = self.gss_vc.unwrap(token) + + # Preserve the "length" of the message we received, and set the + # first byte to one. If username is provided, it's next. + reply:List[int] = [] + reply[0:4] = response.message[0:4] + reply[0] = 1 + if self.username: + reply[5:] = self.username.encode("utf-8") + + response = self.gss_vc.wrap(bytes(reply), response.encrypted) + return response.message if response.message else b"" # type: ignore def auth_gssapi(username:str, imap:imaplib.IMAP4_SSL, conf:configparser.ConfigParser, server:str) -> None: -- cgit v1.2.3