'javax.xml.ws.Endpoint' и 2 способа SSL
Я попытался развернуть веб-службу двумя способами SSL в java, используя класс javax.xml.ws.Endpoint. Моя настройка SSL очень ограничительна. Я должен установить определенный набор параметров и настроек. Это требование я не могу обсуждать.
Чтобы настроить SSL, мне нужно предоставить объект Контекст сервера. После выполнения некоторого поиска я заканчиваю использование класса com.sun.net.httpserver.HttpsServer(и некоторых других связанных классов также в пакете com.sun). Он отлично работает на JVM Windows и на JVM HPUX.
Однако я знаю (я должен сказать, я считаю), что классы из пакета 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 valid? Почему я объяснил? Из моего поиска (например, Что находится внутри пакета com.sun?), я узнал, что это похоже на разницу между пакетом "солнце". и "com.sun". Еще нет окончательного (документированного) ответа. Пожалуйста, дайте ссылку для вашего ответа.
Вопрос 2: Если я не должен использовать класс com.sun.net.httpserver.HttpsServer, что я могу использовать?
ПРИМЕЧАНИЕ. Я не хочу использовать контейнер (например, Tomcat, Jetty,...). Я не буду объяснять причину. Это вне темы.
Ответы
Ответ 1
Запуск JDK9 (и последней версии JDK8), есть инструмент с именем 'jdeps', который предоставляет опцию '-jdkinternals'. Использование его против моего кода ничего не сообщит. Это означает (по вопросу Нет вывода с jdeps при использовании -jdkinternals) 'com.sun.net.httpserver.HttpsServer' НЕ является внутренним классом.
Ответ 2
Нет проблем с использованием HTTP-сервера пакета com.sun.net
, кроме него, не являющегося частью спецификации JDK, это просто еще один код, который Oracle связывает с их дистрибутивом. Вы не найдете эти классы в OpenJDK, но это ничем не отличается от tomcat или пристани. Проблема с использованием пакетов sun
или com.sun
всегда заключалась в том, что они не являются частью спецификации JDK, они являются их кодом, который реализует различные компоненты JDK или просто материал, который они предоставляют, потому что они хорошие парни/девушки. См. этот вопрос SO и этот FAQ из Oracle для получения более подробной информации о sun.
и com.sun
Лично я бы избегал этого, потому что есть лучшие варианты. Вы можете упаковать свою конечную точку в качестве файла WAR и развернуть в механизм сервлетов или использовать Spring Boot/Dropwizard, чтобы связать движок сервлета с большим файлом jar.
Я бы посмотрел на сервлет-модули, которые используют бит-тестирование без блокировки ввода-вывода и имеют гораздо лучшее управление и оперативное управление. Уже упоминались Jetty и Tomcat, которые оба очень хороши, там также JBoss Wildfly и множество других коммерческих опций (WebLogic, Websphere, возможно, тысячи других)
Все это позволит вам выполнять двухсторонний SSL, и многие из них позволят вам повторно использовать существующие коды KeyStore
и TrustStore
.
Spring У Boot есть хороший пример SOAP, и вы найдете тот же подход для многих других сервлет-движков.