Glassfish、Java 电子邮件和证书

Posted

技术标签:

【中文标题】Glassfish、Java 电子邮件和证书【英文标题】:Glassfish, Java email and certificate 【发布时间】:2015-03-12 12:25:44 【问题描述】:

我已经搜索了很长时间,但找不到答案。

我正在使用 Glassfish,并希望通过我们的 smtp 服务器发送电子邮件。

我已经获得了服务器的证书:

openssl s_client -connect mail.example.com:587 -starttls smtp > our.cer

我已将 cer 文件清理为仅包含证书数据。 我到处都导入它:

keytool -import -alias mail.example.com -file our.cer -keystore c:\Progra~1\Java\jre7\lib\security\cacerts
keytool -import -alias mail.example.com -file our.cer -keystore c:\Progra~1\Java\JDK17~1.0_4\jre\lib\security\cacerts
keytool -import -alias mail.example.com -file our.cer -keystore c:\PROGRA~1\GLASSF~1.0\GLASSF~1\domains\domain1\config\cacerts.jks

但我收到以下错误:

javax.mail.MessagingException: Could not convert socket to TLS;
    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
    ...
    Caused by...
    ...
    Caused by...
    ...
    Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

我的代码sn-p:

...
Properties properties = System.getProperties();
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.smtp.host", "mail.example.com");
properties.put("mail.smtp.user", "example@example.com");
properties.put("mail.smtp.password", "some.password");
properties.put("mail.smtp.port", "587"));
properties.put("mail.smtp.auth", "true"));
properties.put("mail.smtp.from", "example@example.com"));
properties.put("mail.transport", "smtp"));

...

Authenticator mailAuthenticator = new Authenticator()

    @Override
    protected PasswordAuthentication getPasswordAuthentication()
    
        return new PasswordAuthentication(properties.getProperty("mail.smtp.user"),
                        properties.getProperty("mail.smtp.password"));
    
;
try

    // Get the default Session object.
    Session session = Session.getDefaultInstance(properties, mailAuthenticator);
    MimeMessage mimeMessage = new MimeMessage(session);
    mimeMessage.setSubject("Hallo world!");
    mimeMessage.setFrom(new InternetAddress(properties.getProperty("mail.smtp.from")));
    mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("example@example.com"));
    mimeMessage.setText("Some text message...");

    Transport transport = session.getTransport(properties.getProperty("mail.transport"));//"smtp"

    int port = Integer.parseInt(properties.getProperty("mail.smtp.port"));//587
    transport.connect(properties.getProperty("mail.smtp.host"),//"mail.example.com"
                    port,
                    properties.getProperty("mail.smtp.user"),//"example@example.com"
                    properties.getProperty("mail.smtp.password"));//Clear text password
    transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
    LOG.info("...done sending email");

catch (AddressException e)

    LOG.log(Level.SEVERE, "Error while sending email", e);

catch (MessagingException e)

    LOG.log(Level.SEVERE, "Error while sending email", e);

catch (Exception e)

    LOG.log(Level.SEVERE, "Error while sending email", e);

我也尝试过 Mkyong's suggestion 对邮件服务器运行 InstallCert (source),但我得到了:

javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?

更新 1

我已在以下其他位置加载了证书:

keytool -import -alias mail.example.com -file our.cer -keystore c:\PROGRA~1\GLASSF~1.0\GLASSF~1\domains\domain1\config\keystore.jks
keytool -import -alias mail.example.com -file our.cer -keystore c:\GLASSFISH\config\keystore.jks
keytool -import -alias mail.example.com -file our.cer -keystore c:\GLASSFISH\config\cacerts.jks

我还设置了这些属性:

System.setProperty("javax.net.ssl.keyStore", "c:\\GLASSFISH\\config\\keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "changeit");
System.setProperty("javax.net.ssl.trustStore", "c:\\GLASSFISH\\config\\cacerts.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

我还开启了 ssl(Glassfish 控制台、服务器、属性)javax.net.debug=ssl 的调试。

它适用于独立测试应用程序 (Java SE),但不适用于 Glassfish。

更新 2

使用javax.net.debug=ssl 并检查日志输出,我可以看到,即使我已经“到处”加载了证书,或者如果我将 Glassfish 指向 java 密钥库,Glassfish 仍然缺少此证书。独立的测试应用程序有它:

adding as trusted cert:
    Subject: CN=avast! Web/Mail Shield Root, O=avast! Web/Mail Shield, OU=generated by avast! antivirus for SSL/TLS scanning
    Issuer:  CN=avast! Web/Mail Shield Root, O=avast! Web/Mail Shield, OU=generated by avast! antivirus for SSL/TLS scanning
    Algorithm: RSA; Serial number: 0x14128fa09c50b64ba6d5c99875872673
    Valid from Wed Feb 04 08:56:17 CAT 2015 until Sat Feb 01 08:56:17 CAT 2025

(注意序列号...)

似乎是 Glassfish 缺少证书;因为独立的测试应用会找到它:

Found trusted certificate:
[
[
    Version: V3
    Subject: CN=avast! Web/Mail Shield Root, O=avast! Web/Mail Shield, OU=generated by avast! antivirus for SSL/TLS scanning
    Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5

    Key:  Sun RSA public key, 2048 bits
    modulus: ---8<---
    public exponent: 65537
    Validity: [From: Wed Feb 04 08:56:17 CAT 2015, : Sat Feb 01 08:56:17 CAT 2025]
    Issuer: CN=avast! Web/Mail Shield Root, O=avast! Web/Mail Shield, OU=generated by avast! antivirus for SSL/TLS scanning
    SerialNumber: [    14128fa0 9c50b64b a6d5c998 75872673]

    ...

(查看序列号...)

请帮忙

【问题讨论】:

您是否设法进入“使用别名 'localhost-1' 将证书添加到密钥库 'jssecacerts'”部分? 【参考方案1】:

好吧,乖乖!我已经想通了。简而言之,这是我今天 5 天的旅程的结束方式...

首先我从 Java 密钥库中转储了所有证书,因为它正在使用该密钥库:

keytool -list -v -keystore c:\Progra~1\Java\jre7\lib\security\cacerts > allJavaCerts.txt

然后我从 Glassfish 密钥库中转储了所有证书,以查看证书是否正确导入:

keytool -list -v -keystore c:\WORKSP~1\GLASS\config\cacerts.jks > allGFCerts.txt

在 Java 密钥库列表中,我注意到邮件服务器的证书是由 Avast 颁发的……很奇怪,对吧?

Issuer: CN=avast! Web/Mail Shield Root, O=avast! Web/Mail Shield, OU=generated by avast! antivirus for SSL/TLS scanning

在 Java 密钥库列表中有 Alias name: avastsslscannerroot 的证书,但在 Glassfish 密钥库列表中没有 - 谢谢Beyond Compare v3

所以我从 Java 密钥库中导出了 avastsslscannerroot 证书并将其导入到 Glassfish 密钥库中:

keytool -export -keystore c:\Progra~1\Java\jre7\lib\security\cacerts -alias avastsslscannerroot -file avastsslscannerroot.cer
keytool -import -alias avastsslscannerroot -file avastsslscannerroot.cer -keystore c:\WORKSP~1\GLASS\config\keystore.jks
keytool -import -alias avastsslscannerroot -file avastsslscannerroot.cer -keystore c:\WORKSP~1\GLASS\config\cacerts.jks

现在它可以工作了......

然后它没有在服务器上......经过一番搜索,我遇到了这个:

mail.smtp.ssl.trust="*"

属性,它对我们有用,因为我们是从 我们的 Web 服务器到 我们的 邮件服务器的连接...

【讨论】:

【参考方案2】:

您的本地病毒防护似乎是Avast。

您的问题是由其所谓的 Active Protection Shield 引起的,它拦截 SSL 流量并扫描它以查找恶意内容。为了实现这一点,Avast 必须拦截 Java 程序和 SMTPS 服务器之间的通信。有关详细信息,请参阅 security.stackexchange.com 上的 this question 或 this question

问题:

因为 Avast-Certificate(当然)不受 GlassFish 信任,并且在安装 Avast 时未添加到 Glassfish,所以无法建立 SSL 连接

可能的解决方案:

    将 Avast-Certificate 添加到 GlassFishs 的有效证书列表(这就是提问者所做的) 禁用 Avast 的此功能(设置 -> 主动保护 -> 电子邮件保护)

【讨论】:

以上是关于Glassfish、Java 电子邮件和证书的主要内容,如果未能解决你的问题,请参考以下文章

【第14期】springboot: pdf电子签章

android 邮件服务器,全球邮企业邮箱Android(安卓)系统手机 POP3 IMAP协议设置方法

对于从 java 程序发送的电子邮件,html 内容中的 png 图像未显示在 gmail 客户端上

南邮数据结构考试时间

电子邮箱登陆3大方式普及

java认证与证书