Как установить параметры TLS для канала CXF?

Мое приложение имеет два исходящих соединения SOAP. Для тех, кто хочет реализовать TLS. Оба созданы с использованием CXF.

javax.xml.ws.Service.getPort() возвращает индивидуальный bindingProvider (оба соединения используют свой собственный WSDL), но оба используют один и тот же org.apache.cxf.bus.spring.SpringBus пример.

Перед использованием bindingProvider я установил параметры клиента TLS в Conduit:

Client client = ClientProxy.getClient(bindingProvider); // different
HTTPConduit httpConduit = (HTTPConduit) client.getConduit(); // same for both connections
TLSClientParameters tlsClientParameters = new TLSClientParameters();
tlsClientParameters.setTrustManagers(getTrustmanagers());
httpConduit.setTlsClientParameters(tlsClientParameters);

Проблема в том, что извлеченный клиент различен для обоих соединений, но канал - это один и тот же объект. Таким образом, когда я устанавливаю параметры для второго соединения для того же объекта, я перезаписываю ранее установленные настройки.

Ответы на часто задаваемые вопросы, если CXF является потокобезопасным, с "да" и рядом исключений. Я думаю, что второе исключение применимо здесь. Это говорит:

Ответ CXF: прокси-серверы CXF поточно-ориентированы для многих случаев использования. Исключения:

  • [...]

  • Настройки в канале - если вы используете код или конфигурацию для прямого манипулирования каналом (например, для установки настроек TLS или аналогичных), они не являются поточно-ориентированными. Канал для каждого экземпляра и, таким образом, эти параметры будут общими. Кроме того, если вы используете FailoverFeature и LoadBalanceFeatures, канал будет заменен на лету. Таким образом, настройки, установленные на кабелепроводе, могут быть потеряны перед использованием в потоке настройки.

  • [...]

В случае проблем с каналом вы МОЖЕТЕ установить новый ConduitSelector, использующий локальный поток или аналогичный. Это немного сложно, хотя.

Я не совсем уверен, является ли безопасность потоков моей проблемой. Я создаю два соединения, каждое в своем собственном компоненте. Springs использует только один поток для инициализации всех компонентов, поэтому оба соединения инициализируются одним и тем же потоком. Но впоследствии соединение использует потоки из пула. Перезапись настроек происходит во время инициализации, поэтому перед отправкой реальных сообщений SOAP используются разные потоки.

Когда проводник создан в org.apache.cxf.endpoint.AbstractConduitSelector#getSelectedConduitэто делается с помощью SpringBus который является одним и тем же экземпляром для обоих объектов.

Итак, в FAQ сказано, чтобы я использовал свой собственный ConduitSelector. Я попытался установить его до инициализации выше:

Client client = ClientProxy.getClient(bindingProvider);
client.setConduitSelector(
    new UpfrontConduitSelector(
        new URLConnectionHTTPConduit(client.getBus(), 
                                     client.getEndpoint().getEndpointInfo())));

и я попробовал то же самое после инициализации. В обоих случаях после установки селектора канала, когда что-то использует BindingProvider (который является прокси-объектом), он получает исключение NullPointerException, хотя объект не является нулевым.

Моя проблема здесь заключается в том, чтобы либо запустить пользовательский селектор кабелепровода, либо увидеть, что моя проблема может быть решена совершенно по-другому, или просто получить вдохновение:)

Какой-то парень из SO, похоже, решил это здесь, но ответ на его вопрос мне не помогает.

1 ответ

Я нашел решение.

Проблема действительно не имела ничего общего с многопоточностью, но с тем, как SpringBus подключен к моим объектам и как из него создается Conduit.

Решением было предоставить каждому сервису свой SpringBus.

Поэтому, прежде чем я создам каждый SOAP-сервис, вызывая его c'tor в javax.xml.ws.Service, Я делаю

BusFactory bf = BusFactory.newInstance();
Bus b = bf.createBus();
BusFactory.setThreadDefaultBus(b);

которая устанавливает новую локальную шину по умолчанию, которая затем используется для созданной службы. Таким образом, каждый из двух моих сервисов имеет свой собственный SpringBus, и они оба создают свой собственный Conduit.

Это работает, потому что каждая услуга является весной @Component и все пружинные компоненты создаются основной резьбой. Таким образом, существует только один поток, и ни в коем случае этот код не будет выполняться последовательно.

Другие вопросы по тегам