JAVAMAIL: AUTH NTLM неуспешно

опитвам се да изпратя имейл с java в локална мрежа, като използвам Microsoft Exchange Server

има моят код:

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

и това е моят клас удостоверител:

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]

моля, помогнете ми, минаха няколко дни, за да търся решение, но не намерих нищо


person Azzedine madi    schedule 29.09.2013    source източник
comment
проверихте ли този въпрос? stackoverflow.com/questions/4337812/   -  person epoch    schedule 29.09.2013
comment
@epoch: да, направих, не е същото, в този пример използвам smtp протокола, а в другия той използва imap протокола и механизма LOGIN: DEBUG SMTP: механизми за проверка: LOGIN PLAIN DIGEST-MD5 NTLM AUTH LOGIN   -  person Azzedine madi    schedule 29.09.2013
comment
В зависимост от конфигурацията на обмена може да се наложи да посочите потребителско име във формуляра ДОМЕЙН\потребителско име   -  person Jk1    schedule 29.09.2013
comment
@jk1: опитвам всички тези комбинации: потребителско_име,потребителско_име@myDomain.com,myDomain.com\user_name, но се появява същата грешка в съобщението   -  person Azzedine madi    schedule 29.09.2013
comment
@Azzedinemadi, не е myDomain.com, трябва да е името на домейна на Windows   -  person epoch    schedule 29.09.2013
comment
@epoch: аз, разбира се, поставям името на домейна на моята компания, това имам предвид с моя домейн   -  person Azzedine madi    schedule 29.09.2013
comment
Въз основа на съобщението за грешка в изключението, изглежда, че нещо е объркано с обмена на протоколи. Можете ли да публикувате целия изход за отстраняване на грешки? Също така, имате ли работеща антивирусна програма, която може да филтрира вашите имейл връзки?   -  person Bill Shannon    schedule 30.09.2013
comment
@BillShannon : добре, ще редактирам публикацията си, за да поставя целия си изход за отстраняване на грешки, а за антивирусната програма я деактивирам, но имам същата грешка в съобщението   -  person Azzedine madi    schedule 30.09.2013
comment
Изглежда, че може да получавате неочаквано изключение, докато се опитвате да инициализирате NTLM удостоверяването. Моля, свържете се с мен на [email protected], за да можем да коригираме това допълнително.   -  person Bill Shannon    schedule 30.09.2013
comment
@BillShannon : благодаря Бил, ще го направя   -  person Azzedine madi    schedule 30.09.2013
comment
След известно офлайн отстраняване на грешки, това изглежда е проблем с инсталацията или конфигурацията на JDK, свързана с поддръжката на криптография. JavaMail криеше истинския източник на грешката, което е нещо, което ще поправя, но основният проблем също трябва да бъде коригиран и това не е свързано с JavaMail.   -  person Bill Shannon    schedule 02.10.2013
comment
@BillShannon : благодаря Бил, направих нова инсталация на jdk и работи, ти си ангел!! ^^   -  person Azzedine madi    schedule 02.10.2013


Отговори (2)


Имам това работещо свързване към нашия сървър Exchange 2010 чрез NTLM.

NTLM използва вашето потребителско име и парола за Windows за удостоверяване, а не вашия имейл адрес и парола.

Направих следните промени:

1) Потребителското име трябва да бъде вход в Windows, НЕ имейл адрес. NTLM използва вашите идентификационни данни за Windows за удостоверяване.

2) mail.smtp.auth.ntlm.domain трябва да бъде вашият Windows домейн - т.е. частта преди наклонената черта, ако обикновено влизате във вашата Windows машина с "MYDOMAIN\id12345" като потребителско име.

Актуализиран код по-долу:

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

Колкото и да си заслужава, вашата оригинална публикация ми помогна да реша проблемите, които имах при свързването, които продължават от няколко дни.

Една последна точка, вероятно трябва да деактивирате/промените антивирусните настройки, за да разрешите достъп до порт 25.

person Cookalino    schedule 05.11.2013

Имах същия проблем и след като разбрах, че javamail не поддържа NTLMv2 удостоверяване, разработих заобиколно решение, което обаче изисква JCIFS библиотека.

Изтеглих изходния код на API на javamail (https://java.net/projects/javamail/pages/Home) и редактира класа com.sun.mail.auth.Ntlm, за да добави липсващата поддръжка за NTLMv2, използвайки поддръжката на библиотеката JCIFS (http://jcifs.samba.org).

Първата модификация във файла 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

За да активирам отстраняването на грешки, доколкото е възможно, използвах следния код в основния метод на моя тестов клас:

    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

Преди прилагането на корекцията тестът беше блокиран след изпращане на съобщение тип 1, тъй като моят Exchange сървър изискваше NTLMv2 удостоверяване. След корекцията автентификацията беше извършена успешно.

person Andrea Luciano    schedule 27.09.2014