【问题标题】:JAVAMAIL : AUTH NTLM failedJAVAMAIL:AUTH NTLM 失败
【发布时间】:2013-10-05 06:09:45
【问题描述】:

我尝试使用 microsoft exchange server 在本地网络中使用 java 发送电子邮件

这是我的代码:

import java.io.UnsupportedEncodingException;
import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;


public class Main {


        public static void main(String[] args) {

            final String username = "username@MyDomain.com";
            final String password = "password";

            Properties props = new Properties();
            props.put("mail.smtp.auth", "true");
            props.put("mail.debug", "true");
            props.put("mail.smtp.host", "exchange_host.MyDomain.com");
            props.put("mail.smtp.port", "25");
            props.put("mail.smtp.auth.mechanisms","NTLM");
            props.put("mail.smtp.auth.ntlm.domain","MyDomain");


            Session session = Session.getInstance(props,new MyAuthenticator(username,password));

            try {

                Message message = new MimeMessage(session);
                message.setFrom(new InternetAddress("from_adress@MyDomain.com"));
                message.setRecipients(Message.RecipientType.TO,
                    InternetAddress.parse("recipent_adresse"));
                message.setSubject("Testing Subject");
                message.setText("Dear Mail Crawler,"
                    + "\n\n No spam to my email, please!");

                Transport.send(message);

                System.out.println("Done");

            } catch (MessagingException e) {
                throw new RuntimeException(e);
            }
        }
    }

这是我的身份验证器类:

import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;

public class MyAuthenticator extends Authenticator {

     String user;
     String pw;
     public MyAuthenticator (String username, String password)
     {
        super();
        this.user = username;
        this.pw = password;
     }
    public PasswordAuthentication getPasswordAuthentication()
    {
       return new PasswordAuthentication(user, pw);
    }

}

我使用 NTLM 机制,但出现此错误:

DEBUG: JavaMail version 1.4.7
DEBUG: successfully loaded resource: /META-INF/javamail.default.providers
DEBUG: Tables of loaded providers
DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], com.sun.mail.smtp.SMTPTransport=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle], com.sun.mail.imap.IMAPSSLStore=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], com.sun.mail.pop3.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], com.sun.mail.imap.IMAPStore=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle]}
DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], smtps=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]}
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "echange_server.MyDomain.com", port 25, isSSL false
220 echange_server.MyDomain.com Microsoft ESMTP MAIL Service ready at Mon, 30 Sep 2013 09:01:08 +0100
DEBUG SMTP: connected to host "echange_server.MyDomain.com", port: 25

EHLO host.MyDomain.com
250-echange_server.MyDomain.com Hello [xx.xx.xx.xx]
250-SIZE
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-STARTTLS
250-X-ANONYMOUSTLS
250-AUTH NTLM
250-X-EXPS GSSAPI NTLM
250-8BITMIME
250-BINARYMIME
250-CHUNKING
250-XEXCH50
250-XRDST
250 XSHADOW
DEBUG SMTP: Found extension "SIZE", arg ""
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "DSN", arg ""
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "STARTTLS", arg ""
DEBUG SMTP: Found extension "X-ANONYMOUSTLS", arg ""
DEBUG SMTP: Found extension "AUTH", arg "NTLM"
DEBUG SMTP: Found extension "X-EXPS", arg "GSSAPI NTLM"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "BINARYMIME", arg ""
DEBUG SMTP: Found extension "CHUNKING", arg ""
DEBUG SMTP: Found extension "XEXCH50", arg ""
DEBUG SMTP: Found extension "XRDST", arg ""
DEBUG SMTP: Found extension "XSHADOW", arg ""
DEBUG SMTP: Attempt to authenticate using mechanisms: NTLM
DEBUG SMTP: AUTH NTLM failed

Exception in thread "main" java.lang.RuntimeException: javax.mail.AuthenticationFailedException: 250-exchange_host.MyDomain.com Hello [xx.xx.xx.xx]

    at testPakcage.Main.main(Main.java:51)
Caused by: javax.mail.AuthenticationFailedException: 250-exchange_host.MyDomain.com Hello [xx.xx.xx.xx]

请帮帮我,我过去几天搜索解决方案,但我什么也没找到

【问题讨论】:

  • 你检查过这个问题吗? stackoverflow.com/questions/4337812/…
  • @epoch:是的,我做了,不是一回事,在这个例子中,我使用 smtp 协议,而在另一个例子中,他使用 imap 协议和登录机制:“调试 SMTP:检查机制: LOGIN PLAIN DIGEST-MD5 NTLM AUTH LOGIN"
  • 根据交易所配置,可能需要以 DOMAIN\username 形式指定用户名
  • @jk1 :我尝试了所有这些组合:user_name,user_name@myDomain.com,myDomain.com\user_name 但出现相同的 msg 错误
  • @Azzedinemadi,不是myDomain.com,应该是windows域名

标签: java email exchange-server jakarta-mail ntlm


【解决方案1】:

我通过 NTLM 连接到我们的 Exchange 2010 服务器。

NTLM 使用您的 Windows 登录名和密码而不是您的电子邮件地址和密码进行身份验证。

我做了以下更改:

1) 用户名​​应该是 Windows 登录名,而不是电子邮件地址。 NTLM 使用您的 Windows 凭据进行身份验证。

2) mail.smtp.auth.ntlm.domain 应该是您的 Windows 域 - 即,如果您通常使用“MYDOMAIN\id12345”作为用户名登录到您的 Windows 计算机,则斜杠之前的部分。

更新代码如下:

public class Main {
  public static void main(String[] args) {

    // *** CHANGED ***
    final String username = "id12345"; // ID you log into Windows with
    final String password = "MyWindowsPassword";

    Properties props = new Properties();
    props.put("mail.smtp.auth", "true");
    props.put("mail.debug", "true");

    props.put("mail.smtp.host", "exchangeserver.mydomain.com");
    props.put("mail.smtp.port", "25");
    props.put("mail.smtp.auth.mechanisms","NTLM");

    // *** CHANGED ***
    props.put("mail.smtp.auth.ntlm.domain","WINDOMAIN"); // Domain you log into Windows with


    Session session = Session.getInstance(props,new MyAuthenticator(username,password));

    try {

        Message message = new MimeMessage(session);
        message.setFrom(new InternetAddress("john.smith@mydomain.com"));
        message.setRecipients(Message.RecipientType.TO,
                InternetAddress.parse("the.recipient@mydomain.com"));
        message.setSubject("Test email");
        message.setText("TEST EMAIL");

        Transport.send(message);

        System.out.println("Done");

    } catch (MessagingException e) {
        e.printStackTrace();
    }
  }


  public static class MyAuthenticator extends Authenticator {

    String user;
    String pw;
    public MyAuthenticator (String username, String password)
    {
        super();
        this.user = username;
        this.pw = password;
    }
    public PasswordAuthentication getPasswordAuthentication()
    {
        return new PasswordAuthentication(user, pw);
    }
  }
}

不管怎样,你原来的帖子帮助我解决了我已经连接了好几天的问题。

最后一点,您可能需要禁用/更改防病毒设置以允许访问端口 25。

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,在发现 javamail 不支持 NTLMv2 身份验证后,我想出了一个需要 JCIFS 库的解决方法。

    我下载了 javamail api 源代码 (https://java.net/projects/javamail/pages/Home) 并编辑了类 com.sun.mail.auth.Ntlm 以使用 JCIFS 库支持 (http://jcifs.samba.org) 添加对 NTLMv2 的缺失支持。

    文件 Ntlm.java 中的第一个修改是在方法 init0 中,包括添加缺少的标志 NTLMSSP_NEGOTIATE_NTLM2

    private void init0() {
    // ANDREA LUCIANO:
    //    turn on the NTLMv2 negotiation flag in TYPE1 messages: 
    //    NTLMSSP_NEGOTIATE_NTLM2   (0x00080000) 
    //  See also http://davenport.sourceforge.net/ntlm.html#type1MessageExample
    
        type1 = new byte[256];
        type3 = new byte[256];
        System.arraycopy(new byte[] {'N','T','L','M','S','S','P',0,1}, 0,
                type1, 0, 9);
        type1[12] = (byte) 3;
        type1[13] = (byte) 0xb2;
        type1[14] = (byte) 0x08;  // ANDREA LUCIANO - added
    

    ... }

    第二个修改是将方法 generateType3Msg 替换为:

    public String generateType3Msg(String challenge) {
        /* First decode the type2 message */
        byte[] type2 = null;
        try {
           type2 = BASE64DecoderStream.decode(challenge.getBytes("us-ascii"));
           logger.fine("type 2 message: " + toHex(type2)); // ANDREA LUCIANO - added
        } catch (UnsupportedEncodingException ex) {
           // should never happen
           assert false;
        }
        jcifs.ntlmssp.Type2Message t2m;
        try {
              t2m = new jcifs.ntlmssp.Type2Message(type2);
        } catch (IOException ex) {
              logger.log(Level.FINE, "Invalid Type 2 message", ex);
              return "";   // will fail later
        }
    
        final int type2Flags = t2m.getFlags();
        final int type3Flags = type2Flags & (0xffffffff ^ (jcifs.ntlmssp.NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | jcifs.ntlmssp.NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
    
        jcifs.ntlmssp.Type3Message t3m = new jcifs.ntlmssp.Type3Message(t2m, password, ntdomain, username, hostname, type3Flags);
           return jcifs.util.Base64.encode(t3m.toByteArray());
    }
    

    我发现修补库的最简单方法是编译类并更新库 jar 文件:

    "c:\Program Files\Java\jdk1.5.0_22\bin\javac.exe" -cp jcifs-1.3.17.jar;javax.mail-1.5.2.jar -d . Ntlm.java 
     jar uvf javax.mail-1.5.2.jar com\sun\mail\auth\Ntlm.class
    

    为了尽可能多地启用调试,我在测试类的 main 方法中使用了以下代码:

        final InputStream inputStream = Main.class.getResourceAsStream("/logging.properties");
        LogManager.getLogManager().readConfiguration(inputStream);
    
        Properties props = new Properties();
    
        props.put("mail.debug", "true");
        props.put("mail.debug.auth", "true");
    

    使用此 logging.properties:

       # Logging
       handlers = java.util.logging.ConsoleHandler
    
      .level = INFO
    
      # Console Logging
      java.util.logging.ConsoleHandler.level = INFO
    

    在应用补丁之前,测试在发送 Type 1 消息后被卡住,因为我的 Exchange 服务器需要 NTLMv2 身份验证。 打补丁后认证成功。

    【讨论】:

      猜你喜欢
      • 2015-01-10
      • 2011-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-02
      相关资源
      最近更新 更多