为了设置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?),我发现它似乎在包“太阳”和“com.sun”之间有区别.仍然没有确定的(记录的)答案.请参考你的答案.
问题2:如果我不能使用’com.sun.net.httpserver.HttpsServer’类,可以/应该使用什么?
注意:我不想使用容器(如Tomcat,Jetty,…).我不会解释原因.这就是主题.
解决方法
就个人而言,我会避开它,因为有更好的选择.您可以将您的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引擎.