'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, и вы найдете тот же подход для многих других сервлет-движков.