【问题标题】:SMTP through Exchange using Integrated Windows Authentication (NTLM) using PythonSMTP 通过 Exchange 使用 Python 集成 Windows 身份验证 (NTLM)
【发布时间】:2011-02-24 09:00:27
【问题描述】:

我想使用已登录 Windows 用户的凭据来验证与使用 NTLM 的 Exchange 服务器的 SMTP 连接。

我知道 python-ntlm 模块和 two patches 启用了 SMTP 的 NTLM 身份验证,但是我想使用当前用户的安全令牌,而不必提供用户名和密码。

Windows Authentication with Python and urllib2非常相似的问题。

【问题讨论】:

    标签: python smtp ntlm pywin32


    【解决方案1】:

    虽然下面的解决方案只使用了 Python Win32 扩展(Python Win32 扩展中包含的 sspi 示例代码非常有用),但问题中提到的 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):
        # 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)
    

    【讨论】:

    • @NoahYetter 你知道如何/从哪里得到sspi吗?
    • @gt6989b 它包含在 pywin32 中
    • @NoahYetter 非常感谢,这很有帮助——我在网上找遍了所有地方都找不到。
    【解决方案2】:

    很好的答案,但作为 python 3 的更新

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

    【讨论】:

    • 多余的括号:base64.b64encode(msg).decode('utf-8')
    【解决方案3】:

    由于指定了空白 cmd,Python 2.7.x 将无法发送 NTLM 类型 3 消息:

    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)

    已提交对上述答案的修复,但谁知道它何时会被审核/接受。

    【讨论】:

      猜你喜欢
      • 2018-09-28
      • 2011-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多