2011-09-01 14 views
9

Innanzitutto, inizierò con un riepilogo. Sto utilizzando un client Apache CXF per comunicare su SSL con un fornitore di servizi Apache CXF che utilizza un certificato autofirmato. Ho importato il certificato nel truststore WebSphere sul server client, ma ricevo comunque un'eccezione "javax.net.ssl.SSLHandshakeException: SSLHandshakeException che invoca l'errore https://somesvcprovider.com/appname/svc/myservice: com.ibm.jsse2.util.h: nessun certificato attendibile".Come impostare il client Apache CXF per utilizzare il truststore WebSphere? (Ricezione dell'eccezione "Nessun certificato attendibile trovato")

Ora, ecco i dettagli:

Ho un client di servizi web Apache CXF che sto configurando usando primavera, e il cliente viene distribuito a un server di applicazioni WebSphere 6.1. Il client CXF comunica con un provider di servizi Apache CXF su un server WebSphere diverso. La comunicazione utilizza SSL.

Il fornitore di servizi utilizza un certificato autofirmato. Ho importato il certificato del fornitore nel truststore WebSphere sul server client attraverso la console di gestione. Ho raggiunto questo obiettivo passando al certificato SSL e alla gestione delle chiavi> Configurazioni SSL> NodeDefaultSSLSettings> Memorie chiave e certificati> NodeDefaultTrustStore> Certificati firmatario; quindi ho utilizzato lo strumento "Recupera da porta" per importare il certificato.

Tuttavia, ho ancora ricevo questo errore quando si tenta di contattare il fornitore del servizio: "javax.net.ssl.SSLHandshakeException: SSLHandshakeException invocando https://somesvcprovider.com/appname/svc/myservice: com.ibm.jsse2.util.h: certificato n fidato trovato".

Il file di configurazione della sorgente è il seguente:

<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> 

Come indicato sopra, il client CXF viene iniettato tramite un setter da Spring. Il codice per contattare il servizio è al di sotto:

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

Inoltre, non so se questo è legato, ma nessun manager di fiducia vengono restituiti quando ho ispezionare il TLSClientParameters oggetto sul client CXF in fase di esecuzione. Il codice per fare l'ispezione è qui sotto:

// 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 

C'è qualcos'altro che devo fare per ottenere il client Apache CXF a fidarsi del certificato auto-firmato?

Preferisco non specificare il percorso di un truststore insieme a una password nel file di configurazione.

Grazie!

risposta

0

Non penso che sia possibile utilizzare i keystore WAS proprio così con componenti esterni (Apache CXF). Probabilmente devi costruire e usare your own TrustManager. Sembrano esserci molti diversi che funzionano allo stesso modo su examples.

+0

Non riesco a trovare un modo per utilizzare i truststor WAS, quindi presumo che sia necessario specificare il truststore nel file di configurazione come menzionato. –

+0

Trovo la soluzione @kjetil più fattibile, in quanto non richiede uno sviluppo personalizzato –

2

Osservando come funzionano CXF e WAS, è abbastanza semplice accedere a SSLSocketFactory di Websphere e passarlo a CXF utilizzando un intercettore in uscita.

Se si utilizza la seguente classe:

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; 
    } 
} 

allora sarete in grado di collegare fino a SSLSocketFactory di Websphere e può facoltativamente utilizzare le impostazioni "dinamico in uscita Endpoint configurazione SSL" per specificare eventuali certs client, da specificando l'intercettore nel tag jaxws:client:

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

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

per inciso, se la proprietà sslAlias è dichiarata nel WebsphereSslOutInterceptor, un certificato client può essere scelto in base alla sua alias.

Poiché questo sta utilizzando SSLSocketFactory da Websphere, anche gli archivi attendibili verranno utilizzati da Websphere.

EDIT:

ho usato CXF 2.3.6 e WebSphere 6.1

+0

Questa soluzione funziona per me fintanto che mantengo la definizione dell'intercettore nella configurazione dell'endpoint. Tuttavia, se lo metto sul bus, il metodo handleMessage non viene chiamato. Qualcuno sa perché è così? Preferirei non dover specificare lo stesso intercettore per ogni endpoint. – Sandman

+0

@ beny23 Se utilizzo gli endpoint dinamici di Websphere, ho ancora bisogno di tutto il materiale Interceptor e SSLSocketFactory? La mia comprensione è che posso effettuare una semplice chiamata SSL dal mio codice e Dynamic Endpoint dovrebbe intercettare tutte le richieste in uscita in base alla corrispondenza dell'URL. È corretto? – CodeClimber

7

CXF probabilmente sta usando il torto fabbrica presa SSL.

Prova ad aggiungere questo alla tua primavera config: soluzione

<http-conf:conduit name="*.http-conduit"> 
    <http-conf:tlsClientParameters useHttpsURLConnectionDefaultSslSocketFactory="true"/> 
</http-conf:conduit> 
+0

Grazie, questo funziona per me! - [WAS 8] [CXF 2.7.18] – DaniEll

+0

Funziona anche per me ... anche quando si utilizza ProxyFactoryBean per creare dinamicamente il client [WAS 8.5] [CXF 3.1.8] –

2

di beny23 grandi opere per me su WAS7, con le seguenti modifiche (motivo: httpConduit.getTlsClientParameters() potrebbe essere nullo):

Sostituire questa parte:

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

Con questo:

TLSClientParameters tlsClientParameters = httpConduit.getTlsClientParameters(); 
    if (tlsClientParameters == null) { 
     tlsClientParameters = new TLSClientParameters(); 
     httpConduit.setTlsClientParameters(tlsClientParameters); 
    } 
    tlsClientParameters.setSSLSocketFactory(factory); 
Problemi correlati