代码之家  ›  专栏  ›  技术社区  ›  Brian MacKay

使用Python的集成Windows身份验证(NTLM)通过Exchange进行SMTP

  •  11
  • Brian MacKay  · 技术社区  · 14 年前

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

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

    非常类似的问题 Windows Authentication with Python and urllib2 .

    3 回复  |  直到 11 年前
        1
  •  13
  •   Brian MacKay    14 年前

    尽管下面的解决方案只使用了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):
        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)
    
        2
  •  4
  •   techmakin    13 年前

    很好的答案,但作为Python3.0的更新+

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

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

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

    这最终会将正确的响应发送回服务器,但是由于docmd()调用putcmd()的性质,它会预先挂起一个空间。

    SMTPLIP.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消息作为命令发送。

    code, response = smtp.docmd(ntlm_message)

    对上述答案的修正已提交,但谁知道何时审查/接受。