ログインしたWindowsユーザーの資格情報を使用して、NTLMを使用してExchangeサーバーへのSMTP接続を認証したいと思います。
python-ntlmモジュールとSMTPのNTLM認証を有効にする2つの パッチを知っていますが、現在のユーザーのセキュリティトークンを使用したいので、ユーザー名とパスワードを指定する必要はありません。
Pythonとurllib2を使用したWindows認証と非常によく似た問題。
ログインしたWindowsユーザーの資格情報を使用して、NTLMを使用してExchangeサーバーへのSMTP接続を認証したいと思います。
python-ntlmモジュールとSMTPのNTLM認証を有効にする2つの パッチを知っていますが、現在のユーザーのセキュリティトークンを使用したいので、ユーザー名とパスワードを指定する必要はありません。
Pythonとurllib2を使用したWindows認証と非常によく似た問題。
以下のソリューションはPythonWin32拡張機能のみを使用していますが(Python Win32拡張機能に含まれているsspiサンプルコードは非常に役立ちました)、質問で言及されているpython-ntlmIMAPおよび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):
# encoding the message then convert to string
return base64.b64encode(msg).decode("utf-8")
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.decodebytes(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)
素晴らしい答えですが、Python3のアップデートとして
def asbase64(msg):
# encoding the message then convert to string
return base64.b64encode(msg).decode("utf-8")
Python 2.7.xは、指定された空白のcmdが原因で、NTLMType3メッセージの送信に失敗します。
code, response = smtp.docmd("", ntlm_message)
これにより、正しい応答がサーバーに返送されますが、putcmd()を呼び出すdocmd()の性質上、スペースがプリペンドされます。
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')
。
そのため、修正は単にcmdとしてNTLMメッセージを送信することです。
code, response = smtp.docmd(ntlm_message)
上記の回答に対する修正が提出されましたが、いつレビュー/承認されるかは誰にもわかりません。