1

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>
franzke
  • 517
  • 1
  • 6
  • 18

2 Answers2

4

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();
}
user1516873
  • 5,060
  • 2
  • 37
  • 56
0

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.

hooknc
  • 4,854
  • 5
  • 31
  • 60
  • If I were to add the trust cert to cacerts in my jre, would I still need to add the VM argument? – franzke Jun 04 '14 at 17:38
  • If you add the new certificate to the default cacerts you would not require the vm argument, but I highly recommend against that strategy. If you add that certificate to your base cacerts, then all java applications running on your machine will trust that new certificate. Which might not be too harmful, but it just isn't super secure. Also, when you update your version of java you will have to remember to reinstall that certificate again. But then again, when you update your version of java, you should re-copy the cacerts and re-import the certificat anyways. – hooknc Jun 04 '14 at 17:49
  • Ok, that makes sense. Do I then need to change the path of the truststore in the http-conduit in cxf.xml to point to cacerts? – franzke Jun 04 '14 at 18:29
  • So, I didn't know what CXF was until just now, but a quick peek at their documentation, they explain how to define a truststore: http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport%28includingSSLsupport%29-ConfiguringSSLSupport – hooknc Jun 04 '14 at 19:18
  • That is the document I used as a guide – franzke Jun 04 '14 at 19:27
  • Understood. So, my lack of reading comprehension is at fault. Sorry. Is there a way to turn on ssl debugging (-Djavax.net.debug=ssl) with cxf? You need to verify the following: The server is actually requesting a client certificate, what certificates the server will accept (there will be a list of CAs that they accept, and finally that the correct client certificate is in your keystore (keytool -list -v -keystore keystore.jks). Sorry I didn't read your question more carefully the first time. – hooknc Jun 04 '14 at 19:45
  • No problem, this is all new to me. I ran the debug I can see where it is specifying the trustStore and the location, however, the line "keystore is:" comes up blank, which makes me think it is not recognizing the keystore I am providing. – franzke Jun 04 '14 at 21:14
  • 2
    Make sure that the keystore is AOK by using the 'keytool -list -v -keystore ' command. Other things to try: Use the full path to both your keystore and truststore (instead of just classpath). It looks like your keystore and truststore are the same file, this is ok, but I typically try to keep the two separate. The keystore contains your client certificates while the truststore would contain certificates and CAs that you trust. – hooknc Jun 04 '14 at 21:31