首页 > 解决方案 > 如何在 Java Tomcat (Liferay) 中为 SMTP、外部 JSON API 和 MySQL JDBC 配置不同的 SSL 配置的不同接口/上下文?

问题描述

我们在我们的环境中使用 Liferay 应用程序。这是一个 Java CMS 软件,我们使用 Tomcat 9 进行了部署。在我们的应用程序中需要使用以下接口:

现在,为了能够使用 SSL 邮件网关和 SSL 上的外部 JSON API 进行证书身份验证,已完成以下配置:

  1. 我们创建了一个 Java KeyStore 文件,其中包含 SMTP 邮件网关的证书链和外部 JSON API 的证书链
  2. 我们将此 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?但是,所有接口都使用不同的证书链。

预先感谢您!

标签: javamysqlssltomcatssl-certificate

解决方案


我找到了我的问题的答案!解决方案是将 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&amp;dontTrackOpenResources=true&amp;holdResultsOpenOverStatementClose=true&amp;useFastDateParsing=false&amp;useUnicode=true&amp;sslMode=VERIFY_CA&amp;clientCertificateKeyStoreUrl=file:///path/to/my.keystore&amp;clientCertificateKeyStorePassword=PASSW0RD&amp;clientCertificateKeyStoreType=PKCS12&amp;trustCertificateKeyStoreUrl=file:///path/to/my.keystore&amp;trustCertificateKeyStorePassword=PASSW0RD&amp;trustCertificateKeyStoreType=PKCS12&amp;enabledTLSProtocols=TLSv1.2&amp;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   |

我希望这可以帮助有同样问题的人......


推荐阅读