SMTP a través de Exchange usando la autenticación de Windows integrada (NTLM) usando Python

Quiero usar las credenciales del usuario de Windows que inició sesión para autenticar una conexión SMTP a un servidor de Exchange mediante NTLM.

Soy consciente del módulo python-ntlm y de los dos parches que habilitan la autenticación NTLM para SMTP; sin embargo, quiero usar el token de seguridad del usuario actual y no tener que proporcionar un nombre de usuario y contraseña.

Problema muy similar a la autenticación de Windows con Python y urllib2 .

Aunque la solución a continuación solo usa las extensiones Python Win32 (el código de ejemplo sspi incluido con las extensiones Python Win32 fue muy útil), los parches IMAP y SMTP de python-ntlm mencionados en la pregunta también sirvieron como guías útiles.

from smtplib import SMTPException, SMTPAuthenticationError import string import base64 import sspi # NTLM Guide -- http://curl.haxx.se/rfc/ntlm.html SMTP_EHLO_OKAY = 250 SMTP_AUTH_CHALLENGE = 334 SMTP_AUTH_OKAY = 235 def asbase64(msg): return string.replace(base64.encodestring(msg), '\n', '') def connect_to_exchange_as_current_user(smtp): """Example: >>> import smtplib >>> smtp = smtplib.SMTP("my.smtp.server") >>> connect_to_exchange_as_current_user(smtp) """ # Send the SMTP EHLO command code, response = smtp.ehlo() if code != SMTP_EHLO_OKAY: raise SMTPException("Server did not respond as expected to EHLO command") sspiclient = sspi.ClientAuth('NTLM') # Generate the NTLM Type 1 message sec_buffer=None err, sec_buffer = sspiclient.authorize(sec_buffer) ntlm_message = asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 1 message -- Authentication Request code, response = smtp.docmd("AUTH", "NTLM " + ntlm_message) # Verify the NTLM Type 2 response -- Challenge Message if code != SMTP_AUTH_CHALLENGE: raise SMTPException("Server did not respond as expected to NTLM negotiate message") # Generate the NTLM Type 3 message err, sec_buffer = sspiclient.authorize(base64.decodestring(response)) ntlm_message = asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 3 message -- Response Message code, response = smtp.docmd("", ntlm_message) if code != SMTP_AUTH_OKAY: raise SMTPAuthenticationError(code, response) 

Gran respuesta pero como una actualización para Python 3.0+

 def asbase64(msg): # encoding the message then convert to string return((base64.b64encode(msg)).decode("utf-8")) 

Python 2.7.x fallará al enviar el mensaje de NTLM Tipo 3 debido al cmd en blanco especificado:

code, response = smtp.docmd("", ntlm_message)

Esto termina enviando la respuesta correcta de nuevo al servidor, sin embargo, antepone un espacio debido a la naturaleza de docmd () que llama a putcmd ().

smtplib.py:

 def putcmd(self, cmd, args=""): """Send a command to the server.""" if args == "": str = '%s%s' % (cmd, CRLF) else: str = '%s %s%s' % (cmd, args, CRLF) self.send(str) # ... def docmd(self, cmd, args=""): """Send a command, and return its response code.""" self.putcmd(cmd, args) return self.getreply() 

que como resultado toma la ruta de la condición else, enviando así str(' ' + ntlm_message + CRLF) que resulta en (501, 'Syntax error in parameters or arguments') .

Como tal, la solución es simplemente enviar el mensaje NTLM como cmd.

code, response = smtp.docmd(ntlm_message)

Se envió una solución a la respuesta anterior, aunque quién sabe cuándo se revisará / aceptará.