2010-05-26 15 views
10

Desidero utilizzare le credenziali dell'utente Windows connesso per autenticare una connessione SMTP a un server Exchange utilizzando NTLM.SMTP tramite Exchange utilizzando l'autenticazione Windows integrata (NTLM) utilizzando Python

Sono consapevole del modulo python-ntlm e la twopatches che abilitare l'autenticazione NTLM per SMTP, però voglio utilizzare token di protezione dell'utente corrente e non è necessario fornire un nome utente e una password.

Problema molto simile a Windows Authentication with Python and urllib2.

risposta

10

Anche se la soluzione seguente utilizza solo le estensioni Python Win32 (il codice di esempio sspi incluso con le estensioni Python Win32 era molto utile), le patch SMTP Python-ntlm IMAP & menzionate nella domanda servivano anche come guide utili.

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) 
+0

questo codice ha seriamente salvato il mio bacon! –

+0

@NoahYetter Sapresti come/dove ottenere 'sspi'? – gt6989b

+0

@ gt6989b è incluso con pywin32 –

3

Grande risposta, ma come un aggiornamento per Python 3.0+

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

Python 2.7.x non riuscirà a inviare il messaggio NTLM Tipo 3 a causa del cmd vuoto specificato:

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

Questo finisce per inviare la risposta corretta al server, tuttavia esso anticipa uno spazio a causa della natura di docmd() che chiama 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() 

che di conseguenza prende il percorso della condizione altro, inviando così str(' ' + ntlm_message + CRLF) che si traduce in (501, 'Syntax error in parameters or arguments').

Come tale la correzione è semplicemente per inviare il messaggio NTLM come il cmd.

code, response = smtp.docmd(ntlm_message)

Una correzione alla risposta di cui sopra è stata presentata, anche se chissà quando sarà rivisto/accettata.

Problemi correlati