Question

I am trying to connect to a SOAP webservice and need to provide a cert for authentication. I am currently using the cxf http conduit to locate my certificate. I received a p12 file from the service I am wanting to call. I have imported the p12 into a jks. I put the jks in the class path along with my cxf.xml page. I've modified my web.xml to contain the context-param and the listener-class, but I am still getting logs from the server saying no certificate provided. I've looked all over for solutions but nothing has worked this far. Any help is greatly appreciated

CXF.XML

<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://java.sun.com/xml/ns/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://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

    <http:conduit name="*.http-conduit">

        <http:tlsClientParameters>
            <sec:keyManagers keyPassword="changeit">
                <sec:keyStore type="JKS" password="changeit"
                              resource="myKeystore.jks"
                             />
            </sec:keyManagers>
            <sec:trustManagers>
                <sec:keyStore type="JKS" password="changeit"
                              resource="myKeystore.jks"/>
            </sec:trustManagers>
            <sec:cipherSuitesFilter>
                <!-- these filters ensure that a ciphersuite with
                     export-suitable or null encryption is used,
                     but exclude anonymous Diffie-Hellman key change as
                     this is vulnerable to man-in-the-middle attacks -->
                <sec:include>.*_EXPORT_.*</sec:include>
                <sec:include>.*_EXPORT1024_.*</sec:include>
                <sec:include>.*_WITH_DES_.*</sec:include>
                <sec:include>.*_WITH_AES_.*</sec:include>
                <sec:include>.*_WITH_NULL_.*</sec:include>
                <sec:exclude>.*_DH_anon_.*</sec:exclude>
            </sec:cipherSuitesFilter>
        </http:tlsClientParameters>

        <http:client AutoRedirect="true" Connection="Keep-Alive"/>

    </http:conduit>

</beans>

WEB.XML

     <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:cxf.xml</param-value>
    </context-param>
     <listener>
     <listener-class>
        org.springframework.web.context.ContextLoaderListener
     </listener-class>
  </listener>
Was it helpful?

Solution

I agree with @hooknc last comment. Make sure your keystore contains private key entry. Also, set privatekey password equal to keystore password. You can test your service with code listed below. I wrote it for cxf version 3.0.0-milestone2, because i need multiple signatures, but i think code should work also with stable branch 2.x

private PaymentService_Service service = null;
private PaymentService iface = null;

@Before
public void setUp() throws Exception {
    System.setProperty("com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump", "true");
    System.setProperty("javax.net.debug", "ssl");
    service = new PaymentService_Service();
    iface = service.getPaymentServiceImplPort();
    Client client = ClientProxy.getClient(iface);
    HTTPConduit http = (HTTPConduit) client.getConduit();
    TLSClientParameters parameters = new TLSClientParameters();
    parameters.setSSLSocketFactory(createSSLContext().getSocketFactory());
    http.setTlsClientParameters(parameters);
    HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
    httpClientPolicy.setConnectionTimeout(36000);
    httpClientPolicy.setAllowChunking(false);
    httpClientPolicy.setReceiveTimeout(32000);
    http.setClient(httpClientPolicy);
}

private SSLContext createSSLContext() throws Exception{
    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
    trustStore.load(new FileInputStream("/home/user/dev/project/key/http.jks"), "changeit".toCharArray());

    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(new FileInputStream("/home/user/dev/project/key/client.jks"), "changeit".toCharArray());


    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
    tmf.init(trustStore);

    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    kmf.init(keyStore, "changeit".toCharArray());

    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(kmf.getKeyManagers() , tmf.getTrustManagers(), new SecureRandom());
    return sslContext;
}

@Test
public void testSomeMethod() throws Exception {
    Client client = ClientProxy.getClient(iface);
    client.getInInterceptors().add(new LoggingInInterceptor());
    client.getOutInterceptors().add(new LoggingOutInterceptor());
    String res = iface.doSomeMethod();
}

OTHER TIPS

I don't believe just putting the truststore (jks) in your classpath will work the way you think it will. I'm fairly confident that you will need to call our the truststore that you wish to use via vm options.

Add -Djavax.net.ssl.trustStore={file_path_to_your_jks} to your application's VM arguments. You might also need to use -Djavax.net.ssl.trustStorePassword={your_jks_password} if the default password of 'changeit' wasn't used.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top