Ошибка в JavaMail: создание пути PKIX не удалось найти допустимый путь сертификации для запрошенной цели
Я пытаюсь создать почтовое клиентское приложение в Android, и сейчас я хочу настроить часть javaMail.
Я пытаюсь установить соединение с сервером imap, но что-то не так с моим кодом.
вот мой код:
package mailpackage;
import java.util.Properties;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;
public class Connection implements Runnable
{
boolean done;
public Connection()
{
this.done=false;
}
@Override
public void run()
{
System.out.println("Hello from Connection Thread!");
while(!done)
{
String host = "myhost";// change accordingly
String mailStoreType = "imap";
String username = "myusername";// change accordingly
String password = "mypasswd";// change accordingly
check(host, mailStoreType, username, password);
}
}
public static void receiveEmail(String host, String storeType, String username, String password)
{
try
{
Properties properties = new Properties();
properties.put("mail.imap.com", host);
properties.put("mail.imap.starttls.enable","true");
properties.put("mail.imap.auth", "true"); // If you need to authenticate
// Use the following if you need SSL
properties.put("mail.imap.socketFactory.port", 993);
properties.put("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
properties.put("mail.imap.socketFactory.fallback", "false");
Session emailSession = Session.getDefaultInstance(properties);
emailSession.setDebug(true);
//2) create the IMAP store object and connect with the Imap server
IMAPStore emailStore = (IMAPStore) emailSession.getStore(storeType);
emailStore.connect(host, username, password);
//3) create the folder object and open it
Folder emailFolder = emailStore.getFolder("INBOX");
emailFolder.open(Folder.READ_ONLY);
//4) retrieve the messages from the folder in an array and print it
Message[] messages = emailFolder.getMessages();
for (int i = 0; i <messages.length; i++)
{
Message message = messages[i];
MimeMessage m = new MimeMessage(emailSession);
m.setContent(((MimeMessage)messages[i]).getContent() , "text/plain; charset=UTF-8");
System.out.println("---------------------------------");
System.out.println("Email Number " + (i + 1));
System.out.println("Subject: " + message.getSubject());
System.out.println("From: " + message.getFrom()[0]);
System.out.println("Text: " + message.getContent().toString());
m.writeTo(System.out);
}
//5) close the store and folder objects
emailFolder.close(false);
emailStore.close();
}
catch (NoSuchProviderException e) {e.printStackTrace();}
catch (MessagingException e) {e.printStackTrace();}
catch (IOException e) {e.printStackTrace();}
}
public void stopThread()
{
this.done=true;
}
}
Я вызываю поток из другого класса, такого как
connec=new Connection();
(new Thread(connec)).start();
Я получаю следующие ошибки:
javax.mail.MessagingException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target;
nested exception is:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:571)
at javax.mail.Service.connect(Service.java:288)
at javax.mail.Service.connect(Service.java:169)
at mailpackage.Connection.check(Connection.java:63)
at mailpackage.Connection.run(Connection.java:33)
at java.lang.Thread.run(Thread.java:744)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1341)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:882)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:102)
at com.sun.mail.util.TraceInputStream.read(TraceInputStream.java:110)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
at com.sun.mail.iap.ResponseInputStream.readResponse(ResponseInputStream.java:98)
at com.sun.mail.iap.Response.<init>(Response.java:96)
at com.sun.mail.imap.protocol.IMAPResponse.<init>(IMAPResponse.java:61)
at com.sun.mail.imap.protocol.IMAPResponse.readResponse(IMAPResponse.java:135)
at com.sun.mail.imap.protocol.IMAPProtocol.readResponse(IMAPProtocol.java:261)
at com.sun.mail.iap.Protocol.<init>(Protocol.java:114)
at com.sun.mail.imap.protocol.IMAPProtocol.<init>(IMAPProtocol.java:104)
at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:538)
... 5 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1323)
... 23 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
... 29 more
Я прочитал что-то о ошибке пути PKIX, которая говорит, что добавить сертификат в java-хранилище в качестве доверенного сертификата, но я не знаю, является ли это решением для этого, и если я не знаю, как это сделать.
//У меня нет доступа к почтовому серверу
Любые предложения? благодарю!
Ответы
Ответ 1
Проблема решена!
Решение таково:
Сначала получите самозаверяющий сертификат с почтового сервера через openssl:
echo | openssl s_client -connect yoursever:port 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > yourcert.pem
Затем сохраните файл yourcert.pem в этом пути /Library/Java/Home/lib/security (на macOSX) и поместите файл сертификата в такие cacerts, как это.
keytool -keystore cacerts -importcert -alias youralias -file yourcert.pem
Пароль хранилища ключей по умолчанию - changeit
Вы можете просмотреть изменение, которое вы сделали с помощью этой команды, которая показывает отпечаток сертификата.
keytool -list -keystore cacerts
После этого вы должны передать эти аргументы в VM
(для окон и типа linux ваш путь между "")
-Djavax.net.ssl.trustStore="/Library/Java/Home/lib/security/cacerts"
-Djavax.net.ssl.trustStorePassword="changeit"
Отладка:
-Djava.security.debug=certpath
-Djavax.net.debug=trustmanager
Ответ 2
Вы можете попробовать обновить библиотеку javax.mail.jar по адресу https://java.net/projects/javamail/pages/Home (теперь версия 1.5.5) и добавить код:
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.imap.ssl.trust", "*");
properties.put("mail.imap.ssl.socketFactory", sf);
Ответ 3
простой способ решить эту проблему с помощью getiing файла сертификата с Java 7
скопируйте файл "cacerts" из следующего каталога java 7
C:\Program Files\Java\jdk1.7.0_79\jre\lib\security
и вставьте его в каталог java 6
C:\Program Files\Java\jdk1.6.0\jre\lib\security
Ответ 4
Эта запись в FAQ по JavaMail должна помочь.
Цитата из связанного сайта:
В: При подключении к моему почтовому серверу через SSL я получаю исключение, например "неспособный найти допустимый путь сертификации для запрошенной цели".
A: Возможно, ваш сервер использует тестовый сертификат или самозаверяющий сертификат вместо сертификата, подписанного коммерческим центром сертификации. Вам нужно будет установить сертификат сервера в свой магазин доверия. Программа InstallCert поможет.
В качестве альтернативы вы можете установить свойство mail.protocol.ssl.trust для имени хоста вашего почтового сервера. Подробнее см. Javadocs для пакетов поставщиков протокола.
Другими распространенными причинами этой проблемы являются:
- Там брандмауэр или антивирусная программа перехватывают ваш запрос.
- В вашей установке JDK что-то не так, чтобы не найти сертификаты для доверенных сертификационных центров.
- Вы работаете на сервере приложений, который переопределил список доверенных сертификационных сертификатов JDK.
Ответ 5
Я потерял столько дней, чтобы найти решение, и этот пост мне помог. У меня такая же проблема. Я создал файл pem, как здесь, а затем файл сертификата .pem был инкорпорирован в файл cacert (копия TrustStore.jks) с помощью этой команды:
keytool.exe -import -noprompt -keystore TrustStore.jks -storepass changeit ^ -alias DOMAINNAME файл MYCERTFILE.pem
(DOMAINNAME должно быть заменено именем хоста - этот трюк очень важен, а MYCERTFILE - файлом недавнего создания...)
Я надеюсь, что это решение может помочь кому-то.
Ответ 6
Я также столкнулся с этой проблемой при разговоре с почтовым сервером. Однако основная причина заключалась в том, что сервер (Exchange 2013) имел как настоящий сертификат, так и самоподписанный. Правильный курс действий заключался в том, чтобы удалить самозаверяющий сервер, поскольку он имеет приоритет и блокирует реальный сертификат.
Ответ 7
Я должен был заменить:
props.setProperty("mail.smtp.starttls.enable", "true");
props.setProperty("mail.smtp.auth", "true");
с:
props.put("mail.smtp.starttls.enable", true);
props.put("mail.smtp.auth", true);
избавиться от ошибки.
Обратите внимание, что я использую Jetty 9, который включает в себя древнюю версию javamail.
Я отправил это, потому что ошибка не должна означать, что с сертификатом что-то не так.