我尝试使用类'javax.xml.ws.Endpoint'在java中使用2种方式部署SSL服务。我的SSL设置非常严格。我必须设置一组特定的选项和设置。这是我无法讨论的要求。
为了设置SSL,我需要提供一个Server Context对象。在做了一些搜索之后,我最终使用了类'com.sun.net.httpserver.HttpsServer'(以及其他一些相关的类也在包'com.sun'中)。它可以在Windows JVM和HPUX JVM上完美运行。
但是,我知道(我应该说,我相信)不应该使用包'com.sun'中的类,因为它们不是标准运行时环境的一部分。可以在不事先通知的情况下移动/修改/删除这些类,并且依赖于JVM实现。
我的实际代码是:
private static HttpsServer createHttpsServer() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException, KeyManagementException, NoSuchProviderException {
final String keyStoreType = "...";
final String keyStoreFile = "...";
final String keyStorePassword = "...";
final String trustStoreType = "...";
final String trustStoreFile = "...";
final String trustStorePassword = "...";
final String hostName = "...";
final int portNumber = "...;
final String sslContextName = "TLSv1.2";
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(new FileInputStream(keyStoreFile), keyStorePassword.toCharArray());
KeyStore trustStore = KeyStore.getInstance(trustStoreType);
trustStore.load(new FileInputStream(trustStoreFile), trustStorePassword.toCharArray());
KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyFactory.init(keyStore, keyStorePassword.toCharArray());
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
SSLContext sslContext = SSLContext.getInstance(sslContextName);
sslContext.init(keyFactory.getKeyManagers(), trustFactory.getTrustManagers(), getSecureRandom(pConfiguration));
HttpsServer httpsServer = HttpsServer.create(new InetSocketAddress(hostName, portNumber), portNumber);
HttpsConfigurator configurator = getHttpsConfigurator(pConfiguration, sslContext);
httpsServer.setHttpsConfigurator(configurator);
httpsServer.start();
return httpsServer;
}
private static Endpoint publishSsl(final HttpsServer pHttpsServer, final String pPath, final Object implementationObject) {
LOGGER.entering(LOGGER_SOURCE_CLASS, "publishSsl");
HttpContext httpContext = pHttpsServer.createContext(pPath);
Endpoint endPoint = Endpoint.create(implementationObject);
endPoint.publish(httpContext);
return endPoint;
}
private static HttpsConfigurator getHttpsConfigurator(final MyProperties pConfiguration, SSLContext pSslContext) {
EnforcingHttpsConfigurator configurator = new EnforcingHttpsConfigurator(pSslContext);
// Those are hidden properties to override the SSL configuration if needed.
final String ciphers = pConfiguration.getProperty("overrideSslConfiguration.ciphers", "");
final boolean needClientAuth = pConfiguration.getPropertyAsBoolean("overrideSslConfiguration.needClientAuth", true);
final String protocols = pConfiguration.getProperty("overrideSslConfiguration.protocols", "");
if (!ciphers.isEmpty()) {
configurator.setCiphers(ciphers);
}
configurator.setNeedClientAuth(needClientAuth);
if (!protocols.isEmpty()) {
configurator.setProtocols(protocols);
}
return configurator;
}
public class EnforcingHttpsConfigurator extends HttpsConfigurator {
private static final Logger LOGGER = Logger.getLogger(EnforcingHttpsConfigurator.class.getCanonicalName());
private static final String LOGGER_SOURCE_CLASS = EnforcingHttpsConfigurator.class.getName();
private String mProtocols = "TLSv1.2";
private String mCiphers = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_GCM_SHA256";
private boolean mNeedClientAuth = true;
public EnforcingHttpsConfigurator(SSLContext pSslContext) {
super(pSslContext);
}
public String getProtocols() {
return mProtocols;
}
public void setProtocols(String pProtocols) {
LOGGER.warning("Override SSL configuration, Set protocols '" + pProtocols + "'. This is potentially unsafe.");
mProtocols = pProtocols;
}
public String getCiphers() {
return mCiphers;
}
public void setCiphers(String pCiphers) {
LOGGER.warning("Override SSL configuration, Set ciphers '" + pCiphers + "'. This is potentially unsafe.");
mCiphers = pCiphers;
}
public boolean isNeedClientAuth() {
return mNeedClientAuth;
}
public void setNeedClientAuth(boolean pNeedClientAuth) {
if (!pNeedClientAuth) {
LOGGER.warning("Override SSL configuration, no client authentication required. This is potentially unsafe.");
}
mNeedClientAuth = pNeedClientAuth;
}
@Override
public void configure(HttpsParameters params) {
LOGGER.entering(LOGGER_SOURCE_CLASS, "configure");
final SSLContext context = getSSLContext();
final SSLParameters sslParams = context.getDefaultSSLParameters();
// Override current values
sslParams.setCipherSuites(mCiphers.split(","));
sslParams.setProtocols(mProtocols.split(","));
sslParams.setNeedClientAuth(mNeedClientAuth);
params.setSSLParameters(sslParams);
LOGGER.exiting(LOGGER_SOURCE_CLASS, "configure");
}
}
问题1:语句“不应该使用com.sun中的类”有效吗?我解释的原因是什么?从我的搜索(例如What is inside com.sun package?),我发现包'sun。'和'com.sun。'之间似乎有区别。仍然没有明确(记录)的答案。请给出你的答案参考。
问题2:如果我不应该使用“com.sun.net.httpserver.HttpsServer”类,我可以/应该使用什么?
注意:我不想使用容器(如Tomcat,Jetty,...)。我不会解释原因。这不是主题。
答案 0 :(得分:3)
使用com.sun.net
包HTTP服务器没有问题,除了它不是JDK规范的一部分,它只是Oracle捆绑到其分发中的更多代码。你不会在OpenJDK中找到这些类,但它与tomcat或jetty没有什么不同。使用sun
或com.sun
包的问题一直是它们不是JDK规范的一部分,它们是实现各种JDK组件的代码,或者只是它们提供的东西,因为它们是好人/加仑。有关sun.
和com.sun
我个人会避免它,因为有更好的选择。您可以将Endpoint打包为WAR文件并部署到servlet引擎或使用Spring Boot / Dropwizard将servlet引擎捆绑到一个大的jar文件中。
我会看一下使用经过战斗测试的非阻塞IO的servlet引擎,并且具有更好的管理和操作控制。已经提到Jetty和Tomcat都非常好,还有JBoss Wildfly和一些其他商业选项(WebLogic,Websphere,可能还有数千个)
所有这些都允许您执行双向SSL,许多允许您重复使用现有的KeyStore
和TrustStore
代码。
Spring Boot有一个nice SOAP example,您会发现同样的方法适用于许多其他servlet引擎。
答案 1 :(得分:0)
启动JDK9(以及JDK8的最新版本),有一个名为'jdeps'的工具,它提供了选项'-jdkinternals'。对我的代码使用它将不会报告任何内容。这意味着(根据问题No output with jdeps when using -jdkinternals)'com.sun.net.httpserver.HttpsServer'不是内部类。