java - 如何在 Java Tomcat (Liferay) 中为 SMTP、外部 JSON API 和 MySQL JDBC 配置不同的 SSL 配置的不同接口/上下文?
问题描述
我们在我们的环境中使用 Liferay 应用程序。这是一个 Java CMS 软件,我们使用 Tomcat 9 进行了部署。在我们的应用程序中需要使用以下接口:
- 我们通过 SSL 上的外部 SMTP 邮件网关发送电子邮件。该网关有一个“特殊”的 SSL 证书链。
- 我们还有一个需要 SSL 和证书身份验证的外部 JSON API!该接口有自己的“特殊” SSL 证书链。
- 我们还使用托管 MySQL 数据库实例,并且还要求该数据库必须通过 SSL 连接
现在,为了能够使用 SSL 邮件网关和 SSL 上的外部 JSON API 进行证书身份验证,已完成以下配置:
- 我们创建了一个 Java KeyStore 文件,其中包含 SMTP 邮件网关的证书链和外部 JSON API 的证书链
- 我们将此 KeyStore 文件配置为 [TOMCAT]/bin/setenv.sh 脚本中的 Java 启动参数 - 如下所示:
-Djavax.net.ssl.keyStore=/path/to/my/certificate.store
-Djavax.net.ssl.keyStorePassword=PASSW0RD!
-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.trustStore=/path/to/my/certificate.store
-Djavax.net.ssl.trustStorePassword=PASSW0RD!
-Djavax.net.ssl.trustStoreType=PKCS12
(我们需要将证书存储文件用作 KeyStore 和 TrustStore,因为我们需要能够建立与外部 SMTP 邮件网关和外部 JSON API 的 SSL 连接,并且 JSON API 需要通过 SSL 证书进行身份验证。所以我们的应用程序还需要出示有效的证书)。
现在的问题!如果我们开启了所描述的 SSL 配置,我们将无法通过 SSL 连接到我们的 MySQL 数据库。只有这个 JDBC URL 有效:
jdbc.default.url=jdbc:mysql://[MYSQL_IP]:3306/lportal?characterEncoding=UTF-8&dontTrackOpenResources=true&holdResultsOpenOverStatementClose=true&useFastDateParsing=false&useUnicode=true&sslMode=DISABLED
如果我们从 setenv.sh 中删除 -Djavax.net.ssl.* 参数,我们可以像这样通过 SSL 连接到我们的数据库:
jdbc.default.url=jdbc:mysql://[MYSQL_IP]:3306/lportal?characterEncoding=UTF-8&dontTrackOpenResources=true&holdResultsOpenOverStatementClose=true&useFastDateParsing=false&useUnicode=true&sslMode=REQUIRED&enabledTLSProtocols=TLSv1.2
是的,我们还尝试将托管 MySQL 数据库中的 ca-bundle.pem 放入我们的证书存储中!
其他所有配置都会导致:
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure__The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
和
Bad Handshake
因此,仅当我们不将 -Djavax.net.ssl.* 参数放入 setenv.sh 时,基于 JDBC 的 SSL 才有效。即使托管 MySQL 数据库中的 ca-bundle.pem 位于同一个 KeyStore/TrustStore 中,那么 SSL over JDBC 也将不起作用!曾经!我已经尝试了很多来让它运行,但它只是不起作用。我还使用了不同的 MySQL Connector/J 驱动程序版本。
是否有可能以某种方式获取 JDBC URL 以完全忽略 setenv.sh 中的 -Djavax.net.ssl.* 参数?
或者是否有其他方法可以将 SMTP over SSL、API over SSL 和 JDBC over SSL all-in-one?但是,所有接口都使用不同的证书链。
预先感谢您!
解决方案
我找到了我的问题的答案!解决方案是将 JDBC SQL 连接配置移动到 JNDI 数据源中。
在上述配置中,JDBC 配置位于 Java.properties 配置文件中,如下所示:
jdbc.default.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.default.url=jdbc:mysql://10.0.0.1:3306/lportal?characterEncoding=UTF-8&dontTrackOpenResources=true&holdResultsOpenOverStatementClose=true&useFastDateParsing=false&useUnicode=true&sslMode=DISABLED
jdbc.default.username=mysqluser
jdbc.default.password=PASSW0RD
现在我已经将 JDBC 配置移到了 Tomcat JNDI 数据源中,所以我现在只有这一行,而不是显示的 JDBC 属性:
jdbc.default.jndi.name=jdbc/LiferayPool
在 [TOMCAT_HOME]/conf/context.xml 我添加了这一行:
<Context>
...
<ResourceLink name="jdbc/LiferayPool" global="jdbc/LiferayPool" type="javax.sql.DataSource"/>
...
</Context>
我为我的 SQL Server CA 证书创建了一个额外的 Java 密钥库。这将在下一步的 JNDI 配置中使用。
在 [TOMCAT_HOME]/conf/server.xml 我有我的 JNDI 数据源配置:
<GlobalNamingResources>
...
<Resource name="jdbc/LiferayPool"
auth="Container"
description="Portal DB Connection"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://10.0.0.1:3306/lportal?characterEncoding=UTF-8&dontTrackOpenResources=true&holdResultsOpenOverStatementClose=true&useFastDateParsing=false&useUnicode=true&sslMode=VERIFY_CA&clientCertificateKeyStoreUrl=file:///path/to/my.keystore&clientCertificateKeyStorePassword=PASSW0RD&clientCertificateKeyStoreType=PKCS12&trustCertificateKeyStoreUrl=file:///path/to/my.keystore&trustCertificateKeyStorePassword=PASSW0RD&trustCertificateKeyStoreType=PKCS12&enabledTLSProtocols=TLSv1.2&autoReconnect=true"
username="mysqluser"
password="PASSW0RD"
maxActive="20"
maxIdle="5"
maxWait="10000" />
</GlobalNamingResources>
现在,我与我的数据库和我的 SMTP 以及我的 JSON API 建立了 SSL 连接,并具有不同的 SSL 配置,所有这些现在都可以正常工作!
mysql> SELECT sbt.variable_value AS tls_version, t2.variable_value AS cipher, processlist_user AS user, processlist_host AS host FROM performance_schema.status_by_thread AS sbt JOIN performance_schema.threads AS t ON t.thread_id = sbt.thread_id JOIN performance_schema.status_by_thread AS t2 ON t2.thread_id = t.thread_id WHERE sbt.variable_name = 'Ssl_version' and t2.variable_name = 'Ssl_cipher' ORDER BY tls_version, 4;
+-------------+-----------------------------+--------------+--------------+
| tls_version | cipher | user | host |
+-------------+-----------------------------+--------------+--------------+
| TLSv1.2 | ECDHE-RSA-AES256-GCM-SHA384 | mysqluser | 10.0.0.101 |
我希望这可以帮助有同样问题的人......
推荐阅读
- python - 如何在 PyQT5 中随窗口大小改变显示大小?
- javascript - (jQuery) 将变量内容克隆到 Div
- nlp - 如何使用 conllu python 库保存编辑的 .conllu 文件
- java - 将对象分配给对象
- javascript - Javascript Regex 测试字符串是否在分隔行上只有数字
- android - 使用意图时如何将DatabaseReference传递给android中的类?
- android - 如何限制android播放器并行播放多个媒体文件?
- json - 使用 Perl 模块 LWP::Authen::OAuth2 创建 Google Team Drive
- javascript - 使用 CSHTML MVC 中的模型创建具有预定义列的动态表
- java - 我无法重新打开 Eclipse 项目