Как настроить клиент Apache CXF для использования склада доверенных сертификатов WebSphere? (Получение исключения «Не найден доверенный сертификат».) - PullRequest
9 голосов
/ 01 сентября 2011

Сначала я начну с резюме.Я использую клиент Apache CXF для связи по SSL с поставщиком услуг Apache CXF, который использует самозаверяющий сертификат.Я импортировал сертификат в хранилище доверенных сертификатов WebSphere на клиентском сервере, но по-прежнему получаю «javax.net.ssl.SSLHandshakeException: SSLHandshakeException, вызывающее https://somesvcprovider.com/appname/svc/myservice: com.ibm.jsse2.util.h: доверенный сертификат не найден»исключение.

Теперь вот подробности:

У меня есть клиент веб-службы Apache CXF, который я настраиваю с помощью Spring, и клиент развернут на сервере приложений WebSphere 6.1.Клиент CXF связывается с поставщиком услуг Apache CXF на другом сервере WebSphere.Для связи используется SSL.

Поставщик услуг использует самозаверяющий сертификат.Я импортировал сертификат провайдера в доверенное хранилище WebSphere на клиентском сервере через административную консоль.Я достиг этого, перейдя в SSL-сертификат и управление ключами> Конфигурации SSL> NodeDefaultSSLSettings> Хранилища ключей и сертификаты> NodeDefaultTrustStore> Сертификаты подписавшего;затем я использовал инструмент «Извлечь из порта» для импорта сертификата.

Тем не менее, я все еще получаю эту ошибку при попытке связаться с поставщиком услуг: «javax.net.ssl.SSLHandshakeException: SSLHandshakeException invoking https://somesvcprovider.com/appname/svc/myservice: com.ibm.jsse2.util.h: доверенный сертификат не найден ".

Файл конфигурации Spring выглядит следующим образом:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:sec="http://cxf.apache.org/configuration/security"
  xmlns:http="http://cxf.apache.org/transports/http/configuration"
  xmlns:jaxws="http://cxf.apache.org/jaxws"
  xsi:schemaLocation="
      http://cxf.apache.org/configuration/security
      http://cxf.apache.org/schemas/configuration/security.xsd
      http://cxf.apache.org/transports/http/configuration
      http://cxf.apache.org/schemas/configuration/http-conf.xsd
      http://cxf.apache.org/jaxws
      http://cxf.apache.org/schemas/jaxws.xsd
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd">
    <http:conduit name="*.http-conduit">
        <!-- deactivate HTTPS url hostname verification (localhost, etc) -->
        <!-- WARNING ! disableCNcheck=true should not used in production. -->
        <http:tlsClientParameters disableCNCheck="true" />
    </http:conduit>
    <!-- Read properties from property file(s). -->
    <bean id="propertyPlaceholderConfigurer"
            class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <!-- The *.spring.properties files are prefixed with a system property
                    that is set on the WebSphere server. -->
                <value>classpath:spring.${my.env}.properties</value>
            </list>
        </property>
    </bean>
    <jaxws:client id="myServiceClient"
        serviceClass="com.client.stub.cxf.IMyService"
        address="${my.svc.url}" />
    <bean id="myReport" class="com.client.MyReportRequestor">
        <property name="client" ref="myServiceClient"/>
    </bean>
</beans>

Как показано выше, клиент CXFвпрыскивается через сеттер от Spring.Код для связи со службой приведен ниже:

List<String> formNames = client.retrieveNames(formIdsList);

Кроме того, я не знаю, связано ли это с этим, но при проверке объекта TLSClientParameters на клиенте CXF во время выполнения никакие диспетчеры доверия не возвращаются.Код для проверки приведен ниже:

// Get the trust managers for this client.
Client proxy = ClientProxy.getClient(client);
HTTPConduit conduit = (HTTPConduit) proxy.getConduit();
TLSClientParameters tls = conduit.getTlsClientParameters();
TrustManager[] trustManagers = tls.getTrustManagers();  // trustManagers is null

Что еще мне нужно сделать, чтобы клиент Apache CXF доверял самозаверяющему сертификату?

Я предпочитаюне нужно указывать путь к хранилищу доверенных сертификатов вместе с паролем в файле конфигурации.

Спасибо!

Ответы [ 4 ]

7 голосов
/ 13 июня 2012

CXF, вероятно, использует неправильную фабрику сокетов SSL.

Попробуйте добавить это в конфигурацию Spring:

<http-conf:conduit name="*.http-conduit">
    <http-conf:tlsClientParameters useHttpsURLConnectionDefaultSslSocketFactory="true"/>
</http-conf:conduit>
2 голосов
/ 23 января 2013

Решение beny23 прекрасно работает для меня на WAS7 со следующими изменениями (причина: httpConduit.getTlsClientParameters () может быть нулевым):

Заменить эту часть:

    TLSClientParameters tlsClientParameters = httpConduit.getTlsClientParameters();
    if (tlsClientParameters != null) {
      tlsClientParameters.setSSLSocketFactory(factory);
    }

С этим:

    TLSClientParameters tlsClientParameters = httpConduit.getTlsClientParameters();
    if (tlsClientParameters == null) {
      tlsClientParameters = new TLSClientParameters();
      httpConduit.setTlsClientParameters(tlsClientParameters);
    }
    tlsClientParameters.setSSLSocketFactory(factory);
2 голосов
/ 23 ноября 2011

Глядя на то, как работают CXF и WAS, довольно просто получить доступ к SSLSocketFactory Websphere и передать его в CXF с использованием исходящего перехватчика.

Если вы используете следующий класс:

public class WebsphereSslOutInterceptor extends AbstractPhaseInterceptor<Message> {

  private String sslAlias = null;

  public WebsphereSslOutInterceptor() {
    super(Phase.SETUP);
  }

  public void handleMessage(Message message) throws Fault {
    Conduit conduit = message.getExchange().getConduit(message);
    if (conduit instanceof HTTPConduit) {
      HTTPConduit httpConduit = (HTTPConduit)conduit;
      String endpoint = (String) message.get(Message.ENDPOINT_ADDRESS);
      if (endpoint != null) {
        try {
          URL endpointUrl = new URL(endpoint);
          Map<String, String> connectionInfo = new HashMap<String, String>();

          connectionInfo.put(
            JSSEHelper.CONNECTION_INFO_REMOTE_HOST, 
            endpointUrl.getHost());
          connectionInfo.put(
            JSSEHelper.CONNECTION_INFO_REMOTE_PORT, 
            Integer.toString(endpointUrl.getPort()));
          connectionInfo.put(
            JSSEHelper.CONNECTION_INFO_DIRECTION, 
            JSSEHelper.DIRECTION_OUTBOUND);
          SSLSocketFactory factory = 
            JSSEHelper.getInstance().getSSLSocketFactory(
              sslAlias, 
              connectionInfo, 
              null);

          TLSClientParameters tlsClientParameters = httpConduit.getTlsClientParameters();
          if (tlsClientParameters != null) {
            tlsClientParameters.setSSLSocketFactory(factory);
          }
        } catch (MalformedURLException e) {
          throw new Fault(e);
        } catch (SSLException e) {
          throw new Fault(e);
        }
      }
    }
  }

  public void setSslAlias(String sslAlias) {
    this.sslAlias = sslAlias;
  }
}

После этого вы сможете подключиться к SSLSocketFactory Websphere и по желанию использовать настройки «Конфигурация SSL динамической исходящей конечной точки» для указания любых сертификатов клиента, указав перехватчик в теге jaxws:client:

  <jaxws:client id="proxyName"
        serviceClass="proxyClass"
        address="${web.service.endpointaddress}">

    <jaxws:outInterceptors>
        <bean class="my.pkg.WebsphereSslOutInterceptor" />
    </jaxws:outInterceptors>
</jaxws:client>

Кроме того, если свойство sslAlias объявлено в WebsphereSslOutInterceptor, сертификат клиента может быть выбран на основе его псевдонима.

Поскольку для этого используется SSLSocketFactory от Websphere, хранилища доверия также будут использоваться из Websphere.

EDIT:

Я использовал CXF 2.3.6 и Websphere 6.1

0 голосов
/ 18 сентября 2011

Я не думаю, что вы можете использовать хранилища ключей WAS таким же образом с внешним компонентом (Apache CXF). Вы, вероятно, должны построить и использовать свой собственный TrustManager . Кажется, есть несколько рабочих примеров для этого.

...