mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
fix TomcatEngine to support https
This commit is contained in:
parent
b4eb357775
commit
cacfbd9fc8
@ -70,6 +70,26 @@ public class KeyManagerUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从KeyStore中获取{@link KeyManagerFactory}
|
||||
*
|
||||
* @param keyStore KeyStore
|
||||
* @param password 密码
|
||||
* @param algorithm 算法,{@code null}表示默认算法,如SunX509
|
||||
* @param provider 算法提供者,{@code null}使用JDK默认
|
||||
* @return {@link KeyManager}列表
|
||||
*/
|
||||
public static KeyManagerFactory getKeyManagerFactory(final KeyStore keyStore, final char[] password,
|
||||
final String algorithm, final Provider provider) {
|
||||
final KeyManagerFactory keyManagerFactory = getKeyManagerFactory(algorithm, provider);
|
||||
try {
|
||||
keyManagerFactory.init(keyStore, password);
|
||||
} catch (final KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
|
||||
throw new HutoolException(e);
|
||||
}
|
||||
return keyManagerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从KeyStore中获取{@link KeyManager}列表
|
||||
*
|
||||
@ -77,7 +97,7 @@ public class KeyManagerUtil {
|
||||
* @param password 密码
|
||||
* @return {@link KeyManager}列表
|
||||
*/
|
||||
public static KeyManager[] getDefaultKeyManagers(final KeyStore keyStore, final char[] password) {
|
||||
public static KeyManager[] getKeyManagers(final KeyStore keyStore, final char[] password) {
|
||||
return getKeyManagers(keyStore, password, null, null);
|
||||
}
|
||||
|
||||
@ -90,13 +110,8 @@ public class KeyManagerUtil {
|
||||
* @param provider 算法提供者,{@code null}使用JDK默认
|
||||
* @return {@link KeyManager}列表
|
||||
*/
|
||||
public static KeyManager[] getKeyManagers(final KeyStore keyStore, final char[] password, final String algorithm, final Provider provider) {
|
||||
final KeyManagerFactory keyManagerFactory = getKeyManagerFactory(algorithm, provider);
|
||||
try {
|
||||
keyManagerFactory.init(keyStore, password);
|
||||
} catch (final KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
|
||||
throw new HutoolException(e);
|
||||
}
|
||||
return keyManagerFactory.getKeyManagers();
|
||||
public static KeyManager[] getKeyManagers(final KeyStore keyStore, final char[] password,
|
||||
final String algorithm, final Provider provider) {
|
||||
return getKeyManagerFactory(keyStore, password, algorithm, provider).getKeyManagers();
|
||||
}
|
||||
}
|
||||
|
@ -24,10 +24,7 @@ import org.dromara.hutool.core.text.StrUtil;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.*;
|
||||
|
||||
|
||||
/**
|
||||
@ -51,6 +48,7 @@ public class SSLContextBuilder implements SSLProtocols, Builder<SSLContext> {
|
||||
private KeyManager[] keyManagers;
|
||||
private TrustManager[] trustManagers;
|
||||
private SecureRandom secureRandom;
|
||||
private Provider provider;
|
||||
|
||||
|
||||
/**
|
||||
@ -114,6 +112,17 @@ public class SSLContextBuilder implements SSLProtocols, Builder<SSLContext> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 Provider
|
||||
*
|
||||
* @param provider Provider,{@code null}表示使用默认或全局Provider
|
||||
* @return this
|
||||
*/
|
||||
public SSLContextBuilder setProvider(final Provider provider) {
|
||||
this.provider = provider;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建{@link SSLContext}
|
||||
*
|
||||
@ -133,7 +142,8 @@ public class SSLContextBuilder implements SSLProtocols, Builder<SSLContext> {
|
||||
* @since 5.7.22
|
||||
*/
|
||||
public SSLContext buildChecked() throws NoSuchAlgorithmException, KeyManagementException {
|
||||
final SSLContext sslContext = SSLContext.getInstance(protocol);
|
||||
final SSLContext sslContext = null != this.provider ?
|
||||
SSLContext.getInstance(protocol, provider) : SSLContext.getInstance(protocol);
|
||||
sslContext.init(this.keyManagers, this.trustManagers, this.secureRandom);
|
||||
return sslContext;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import org.dromara.hutool.core.io.IORuntimeException;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import java.security.KeyStore;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
@ -88,6 +89,33 @@ public class SSLContextUtil {
|
||||
trustManager == null ? null : new TrustManager[]{trustManager});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建和初始化{@link SSLContext}
|
||||
*
|
||||
* @param keyStore KeyStore
|
||||
* @param password 密码
|
||||
* @return {@link SSLContext}
|
||||
* @throws IORuntimeException 包装 GeneralSecurityException异常
|
||||
*/
|
||||
public static SSLContext createSSLContext(final KeyStore keyStore, final char[] password) throws IORuntimeException {
|
||||
return createSSLContext(
|
||||
KeyManagerUtil.getKeyManagers(keyStore, password),
|
||||
TrustManagerUtil.getTrustManagers(keyStore)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建和初始化{@link SSLContext}
|
||||
*
|
||||
* @param keyManagers 密钥管理器,{@code null}表示默认
|
||||
* @param trustManagers 信任管理器, {@code null}表示默认
|
||||
* @return {@link SSLContext}
|
||||
* @throws IORuntimeException 包装 GeneralSecurityException异常
|
||||
*/
|
||||
public static SSLContext createSSLContext(final KeyManager[] keyManagers, final TrustManager[] trustManagers) throws IORuntimeException {
|
||||
return createSSLContext(null, keyManagers, trustManagers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建和初始化{@link SSLContext}
|
||||
*
|
||||
|
@ -75,7 +75,8 @@ public class TrustManagerUtil {
|
||||
* @return {@link X509TrustManager} or {@code null}
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static X509TrustManager getTrustManager(final KeyStore keyStore, final String algorithm, final Provider provider) {
|
||||
public static X509TrustManager getTrustManager(final KeyStore keyStore, final String algorithm,
|
||||
final Provider provider) {
|
||||
final TrustManager[] tms = getTrustManagers(keyStore, algorithm, provider);
|
||||
for (final TrustManager tm : tms) {
|
||||
if (tm instanceof X509TrustManager) {
|
||||
@ -94,7 +95,19 @@ public class TrustManagerUtil {
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static TrustManager[] getDefaultTrustManagers() {
|
||||
return getTrustManagers(null, null, null);
|
||||
return getTrustManagers(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的{@link TrustManager}<br>
|
||||
* 此方法主要用于获取自签证书的{@link TrustManager}
|
||||
*
|
||||
* @param keyStore {@link KeyStore}
|
||||
* @return {@link TrustManager} or {@code null}
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static TrustManager[] getTrustManagers(final KeyStore keyStore) {
|
||||
return getTrustManagers(keyStore, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -107,7 +120,22 @@ public class TrustManagerUtil {
|
||||
* @return {@link TrustManager} or {@code null}
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static TrustManager[] getTrustManagers(final KeyStore keyStore, String algorithm, final Provider provider) {
|
||||
public static TrustManager[] getTrustManagers(final KeyStore keyStore, final String algorithm,
|
||||
final Provider provider) {
|
||||
return getTrustManagerFactory(keyStore, algorithm, provider).getTrustManagers();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定的{@link TrustManagerFactory}
|
||||
*
|
||||
* @param keyStore {@link KeyStore}
|
||||
* @param algorithm 算法名称,如"SunX509",{@code null}表示默认SunX509
|
||||
* @param provider 算法提供者,如bc,{@code null}表示默认SunJSSE
|
||||
* @return {@link TrustManager} or {@code null}
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static TrustManagerFactory getTrustManagerFactory(final KeyStore keyStore, String algorithm,
|
||||
final Provider provider) {
|
||||
final TrustManagerFactory tmf;
|
||||
|
||||
if(StrUtil.isEmpty(algorithm)){
|
||||
@ -128,6 +156,6 @@ public class TrustManagerUtil {
|
||||
throw new HutoolException(e);
|
||||
}
|
||||
|
||||
return tmf.getTrustManagers();
|
||||
return tmf;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,9 @@
|
||||
package org.dromara.hutool.crypto;
|
||||
|
||||
import org.dromara.hutool.core.io.IoUtil;
|
||||
import org.dromara.hutool.core.io.file.FileNameUtil;
|
||||
import org.dromara.hutool.core.io.file.FileUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.crypto.provider.GlobalProviderFactory;
|
||||
|
||||
import java.io.File;
|
||||
@ -35,11 +37,12 @@ import java.security.Provider;
|
||||
public class KeyStoreUtil {
|
||||
|
||||
/**
|
||||
* Java密钥库(Java Key Store,JKS)KEY_STORE
|
||||
* Java密钥库(Java Key Store,JKS)KEY_STORE,Java 平台特有的密钥库格式<br>
|
||||
* JKS 密钥库可以用 Java 的 keytool 工具进行管理。
|
||||
*/
|
||||
public static final String TYPE_JKS = "JKS";
|
||||
/**
|
||||
* jceks
|
||||
* JCEKS(Java Cryptography Extension Key Store)
|
||||
*/
|
||||
public static final String TYPE_JCEKS = "jceks";
|
||||
/**
|
||||
@ -100,6 +103,31 @@ public class KeyStoreUtil {
|
||||
return readKeyStore(TYPE_PKCS12, in, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取KeyStore文件<br>
|
||||
* KeyStore文件用于数字证书的密钥对保存<br>
|
||||
* 证书类型根据扩展名自动判断,规则如下:
|
||||
* <pre>
|
||||
* .jks .keystore -> JKS
|
||||
* .p12 .pfx等其它 -> PKCS12
|
||||
* </pre>
|
||||
*
|
||||
* @param keyFile 证书文件
|
||||
* @param password 密码,null表示无密码
|
||||
* @return {@link KeyStore}
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static KeyStore readKeyStore(final File keyFile, final char[] password) {
|
||||
final String suffix = FileNameUtil.getSuffix(keyFile);
|
||||
final String type;
|
||||
if(StrUtil.equalsIgnoreCase(suffix, "jks") || StrUtil.equalsIgnoreCase(suffix, "keystore")){
|
||||
type = TYPE_JKS;
|
||||
}else{
|
||||
type = TYPE_PKCS12;
|
||||
}
|
||||
return readKeyStore(type, keyFile, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取KeyStore文件<br>
|
||||
* KeyStore文件用于数字证书的密钥对保存<br>
|
||||
|
@ -30,6 +30,7 @@ import java.security.Provider;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* 数字证书{@link Certificate}相关工具类
|
||||
@ -141,4 +142,35 @@ public class CertUtil {
|
||||
}
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断一个证书是否是自签名的,即证书由自己签发。
|
||||
* @param cert 证书
|
||||
* @return true表示自签名的,false表示非自签名的
|
||||
*/
|
||||
public static boolean isSelfSigned(final X509Certificate cert) {
|
||||
return isSignedBy(cert, cert);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证一个证书是否由另一个证书签发。<br>
|
||||
* 来自:sun.security.tools.KeyStoreUtil
|
||||
*
|
||||
* @param end 需要验证的终端证书
|
||||
* @param ca 用于验证的CA证书
|
||||
* @return 如果终端证书由CA证书签发,则返回true,否则返回false
|
||||
*/
|
||||
public static boolean isSignedBy(final X509Certificate end, final X509Certificate ca) {
|
||||
// 检查CA证书的主题和终端证书的颁发者是否相同
|
||||
if (!ca.getSubjectX500Principal().equals(end.getIssuerX500Principal())) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
// 使用CA证书的公钥验证终端证书
|
||||
end.verify(ca.getPublicKey());
|
||||
return true;
|
||||
} catch (final Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,12 @@
|
||||
<artifactId>hutool-log</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- webservice SOAP, 从javaEE变成jakartaEE(javax.xml.soap) Jakarta XML SOAP(jakarta.xml.soap) -->
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.soap</groupId>
|
||||
|
@ -16,7 +16,10 @@
|
||||
|
||||
package org.dromara.hutool.http.server;
|
||||
|
||||
import org.dromara.hutool.core.net.ssl.SSLContextUtil;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.security.KeyStore;
|
||||
|
||||
/**
|
||||
* 服务器配置
|
||||
@ -115,6 +118,18 @@ public class ServerConfig {
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置证书库<br>
|
||||
* 此方法和{@link #setSslContext(SSLContext)}互斥
|
||||
*
|
||||
* @param keyStore 证书库
|
||||
* @param passwd 密码
|
||||
* @return this
|
||||
*/
|
||||
public ServerConfig setKeystore(final KeyStore keyStore, final char[] passwd) {
|
||||
return setSslContext(SSLContextUtil.createSSLContext(keyStore, passwd));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置SSL上下文
|
||||
*
|
||||
|
@ -125,20 +125,34 @@ public class TomcatEngine extends AbstractServerEngine {
|
||||
// SSL配置
|
||||
final SSLContext sslContext = config.getSslContext();
|
||||
if(null != sslContext){
|
||||
final SSLHostConfig sslHostConfig = new SSLHostConfig();
|
||||
final SSLHostConfigCertificate sslHostConfigCertificate =
|
||||
new SSLHostConfigCertificate(sslHostConfig, SSLHostConfigCertificate.Type.RSA);
|
||||
sslHostConfigCertificate.setSslContext(new JSSESSLContext(sslContext));
|
||||
sslHostConfig.addCertificate(sslHostConfigCertificate);
|
||||
connector.addSslHostConfig(sslHostConfig);
|
||||
protocol.setSSLEnabled(true);
|
||||
protocol.setSecure(true);
|
||||
protocol.addSslHostConfig(createSSLHostConfig(sslContext));
|
||||
|
||||
connector.setScheme("https");
|
||||
connector.setSecure(true);
|
||||
connector.setPort(config.getPort());
|
||||
}
|
||||
|
||||
return connector;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建SSL HostConfig
|
||||
*
|
||||
* @param sslContext SSLContext
|
||||
* @return SSL HostConfig
|
||||
*/
|
||||
private static SSLHostConfig createSSLHostConfig(final SSLContext sslContext) {
|
||||
final SSLHostConfig sslHostConfig = new SSLHostConfig();
|
||||
|
||||
final SSLHostConfigCertificate sslHostConfigCertificate =
|
||||
new SSLHostConfigCertificate(sslHostConfig, SSLHostConfigCertificate.Type.RSA);
|
||||
sslHostConfigCertificate.setSslContext(new JSSESSLContext(sslContext));
|
||||
|
||||
sslHostConfig.addCertificate(sslHostConfigCertificate);
|
||||
return sslHostConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化Context
|
||||
*
|
||||
|
@ -1,12 +1,23 @@
|
||||
package org.dromara.hutool.http.server.engine;
|
||||
|
||||
import org.dromara.hutool.core.io.file.FileUtil;
|
||||
import org.dromara.hutool.core.lang.Console;
|
||||
import org.dromara.hutool.core.net.ssl.SSLContextUtil;
|
||||
import org.dromara.hutool.crypto.KeyStoreUtil;
|
||||
import org.dromara.hutool.http.server.ServerConfig;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.security.KeyStore;
|
||||
|
||||
public class JettyTest {
|
||||
public static void main(final String[] args) {
|
||||
final char[] pwd = "123456".toCharArray();
|
||||
final KeyStore keyStore = KeyStoreUtil.readJKSKeyStore(FileUtil.file("d:/test/keystore.jks"), pwd);
|
||||
// 初始化SSLContext
|
||||
final SSLContext sslContext = SSLContextUtil.createSSLContext(keyStore, pwd);
|
||||
|
||||
final ServerEngine engine = ServerEngineFactory.createEngine("jetty");
|
||||
engine.init(ServerConfig.of());
|
||||
engine.init(ServerConfig.of().setSslContext(sslContext));
|
||||
engine.setHandler((request, response) -> {
|
||||
Console.log(request.getPath());
|
||||
response.write("Hutool Jetty response test");
|
||||
|
@ -1,12 +1,23 @@
|
||||
package org.dromara.hutool.http.server.engine;
|
||||
|
||||
import org.dromara.hutool.core.io.file.FileUtil;
|
||||
import org.dromara.hutool.core.lang.Console;
|
||||
import org.dromara.hutool.core.net.ssl.SSLContextUtil;
|
||||
import org.dromara.hutool.crypto.KeyStoreUtil;
|
||||
import org.dromara.hutool.http.server.ServerConfig;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.security.KeyStore;
|
||||
|
||||
public class SunServerTest {
|
||||
public static void main(String[] args) {
|
||||
final char[] pwd = "123456".toCharArray();
|
||||
final KeyStore keyStore = KeyStoreUtil.readJKSKeyStore(FileUtil.file("d:/test/keystore.jks"), pwd);
|
||||
// 初始化SSLContext
|
||||
final SSLContext sslContext = SSLContextUtil.createSSLContext(keyStore, pwd);
|
||||
|
||||
final ServerEngine engine = ServerEngineFactory.createEngine("SunHttpServer");
|
||||
engine.init(ServerConfig.of());
|
||||
engine.init(ServerConfig.of().setSslContext(sslContext));
|
||||
engine.setHandler((request, response) -> {
|
||||
Console.log(request.getPath());
|
||||
response.write("Hutool Sun Server response test");
|
||||
|
@ -1,12 +1,23 @@
|
||||
package org.dromara.hutool.http.server.engine;
|
||||
|
||||
import org.dromara.hutool.core.io.file.FileUtil;
|
||||
import org.dromara.hutool.core.lang.Console;
|
||||
import org.dromara.hutool.core.net.ssl.SSLContextUtil;
|
||||
import org.dromara.hutool.crypto.KeyStoreUtil;
|
||||
import org.dromara.hutool.http.server.ServerConfig;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.security.KeyStore;
|
||||
|
||||
public class TomcatTest {
|
||||
public static void main(String[] args) {
|
||||
public static void main(final String[] args) throws Exception {
|
||||
final char[] pwd = "123456".toCharArray();
|
||||
final KeyStore keyStore = KeyStoreUtil.readJKSKeyStore(FileUtil.file("d:/test/keystore.jks"), pwd);
|
||||
// 初始化SSLContext
|
||||
final SSLContext sslContext = SSLContextUtil.createSSLContext(keyStore, pwd);
|
||||
|
||||
final ServerEngine engine = ServerEngineFactory.createEngine("tomcat");
|
||||
engine.init(ServerConfig.of());
|
||||
engine.init(ServerConfig.of().setSslContext(sslContext));
|
||||
engine.setHandler((request, response) -> {
|
||||
Console.log(request.getPath());
|
||||
response.write("Hutool Tomcat response test");
|
||||
|
@ -16,13 +16,24 @@
|
||||
|
||||
package org.dromara.hutool.http.server.engine;
|
||||
|
||||
import org.dromara.hutool.core.io.file.FileUtil;
|
||||
import org.dromara.hutool.core.lang.Console;
|
||||
import org.dromara.hutool.core.net.ssl.SSLContextUtil;
|
||||
import org.dromara.hutool.crypto.KeyStoreUtil;
|
||||
import org.dromara.hutool.http.server.ServerConfig;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.security.KeyStore;
|
||||
|
||||
public class UndertowTest {
|
||||
public static void main(String[] args) {
|
||||
final char[] pwd = "123456".toCharArray();
|
||||
final KeyStore keyStore = KeyStoreUtil.readJKSKeyStore(FileUtil.file("d:/test/keystore.jks"), pwd);
|
||||
// 初始化SSLContext
|
||||
final SSLContext sslContext = SSLContextUtil.createSSLContext(keyStore, pwd);
|
||||
|
||||
final ServerEngine engine = ServerEngineFactory.createEngine("undertow");
|
||||
engine.init(ServerConfig.of());
|
||||
engine.init(ServerConfig.of().setSslContext(sslContext));
|
||||
engine.setHandler((request, response) -> {
|
||||
Console.log(request.getPath());
|
||||
response.write("Hutool Undertow response test");
|
||||
|
Loading…
x
Reference in New Issue
Block a user