SMTP через Exchange с использованием встроенной аутентификации Windows (NTLM) с использованием Python - PullRequest
11 голосов
/ 27 мая 2010

Я хочу использовать учетные данные вошедшего в систему пользователя Windows для проверки подлинности SMTP-подключения к серверу Exchange с использованием NTLM.

Мне известны модуль python-ntlm и два патча , которые включают проверку подлинности NTLM для SMTP, однако я хочу использовать текущего пользователя токен безопасности и не нужно указывать имя пользователя и пароль.

Очень похожая проблема на Аутентификация Windows с Python и urllib2 .

Ответы [ 3 ]

13 голосов
/ 27 мая 2010

Хотя в приведенном ниже решении используются только расширения Python Win32 (пример кода sspi, включенный в расширения Python Win32, был очень полезен), патчи python-ntlm IMAP и SMTP, упомянутые в вопросе, также послужили полезными руководствами.

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)
4 голосов
/ 29 февраля 2012

Отличный ответ, но как обновление для python 3.0 +

def asbase64(msg):
    # encoding the message then convert to string
    return((base64.b64encode(msg)).decode("utf-8"))
2 голосов
/ 08 июля 2013

Python 2.7.x не сможет отправить сообщение NTLM Type 3 из-за пустого указанного cmd:

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

Это приводит к отправке правильного ответа обратно на сервер, однако он ожидает пробел из-за характера docmd (), вызывающего 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()

, который в результате выбирает путь к условию else, тем самым отправляя str(' ' + ntlm_message + CRLF), что приводит к (501, 'Syntax error in parameters or arguments').

Таким образом, исправление заключается в простой отправке сообщения NTLM в виде cmd.

code, response = smtp.docmd(ntlm_message)

Исправление к вышеуказанному ответу было представлено, хотя кто знает, когда он будет рассмотрен / принят.

...