JAVAMAIL : AUTH NTLM 失败

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19076270/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 13:55:12  来源:igfitidea点击:

JAVAMAIL : AUTH NTLM failed

javaemailexchange-serverjavamailntlm

提问by Azzedine madi

i try to send email with java in local network,using microsoft exchange server

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

there is my code :

有我的代码:

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 = "[email protected]";
            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("[email protected]"));
                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);
            }
        }
    }

and this is my authentificator class :

这是我的身份验证器类:

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);
    }

}

i use the NTLM mechanism but i get this error :

我使用 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]

please help me,i past several day to search solution but i found nothing

请帮帮我,我过去几天一直在寻找解决方案,但我什么也没找到

回答by Cookalino

I have this working connecting to our Exchange 2010 server via NTLM.

我有这个工作通过 NTLM 连接到我们的 Exchange 2010 服务器。

NTLM uses your Windows login and password for authentication rather than your email address and password.

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

I made the following changes:

我做了以下更改:

1) Username should be Windows login, NOT email address. NTLM uses your Windows credentials for authentication.

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

2) mail.smtp.auth.ntlm.domain should be your windows domain - i.e. the part before the slash if you normally log on to your Windows machine with "MYDOMAIN\id12345" as username.

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

Updated code below:

更新代码如下:

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("[email protected]"));
        message.setRecipients(Message.RecipientType.TO,
                InternetAddress.parse("[email protected]"));
        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);
    }
  }
}

For what it's worth, your original post helped me solve the problems I have had connecting which have been going on for several days.

就其价值而言,您的原始帖子帮助我解决了我已经连接好几天的问题。

One final point, you probably need to disable / change antivirus settings to allow access out on port 25.

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

回答by Andrea Luciano

I had the same problem and after finding out that javamail does not support NTLMv2authentication, I worked out a workaround that requires JCIFS library though.

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

I downloded the javamail api source code (https://java.net/projects/javamail/pages/Home) and edited the class com.sun.mail.auth.Ntlm to add the missing support for NTLMv2 using the JCIFS library support (http://jcifs.samba.org).

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

The first modification in file Ntlm.java was in method init0, and consisted of adding the missing flag NTLMSSP_NEGOTIATE_NTLM2:

文件 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

... }

... }

The second modification was to replace the method generateType3Msg with this:

第二个修改是用以下方法替换 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());
}

The simpest way I found to patch the library is to compile the class and update the library jar file:

我发现修补库的最简单方法是编译类并更新库 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

To enable debug as much as possible, I used the following code in the main method of my test 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");

with this logging.properties:

使用这个 logging.properties:

   # Logging
   handlers = java.util.logging.ConsoleHandler

  .level = INFO

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

Before applying the patch the test was stuck after sending Type 1 message, because my Exchange server required NTLMv2 authentication. After the patch the athentication was done successfully.

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