简体   繁体   中英

How to implement client authentication when using java code and Apache CXF as SOAP client?

I have a SOAP webservice created using Apache CXF hosted on Apache Tomcat. A webserver runs in front of this and forwards web service requests to Tomcat using AJP protocol.

My requirement is to have client authentication to happen when I access the webservice through the webserver so that only authorized clients can connect to the webservice.

Currently only server authentication is happening and I am able to successfully make web service calls when SSL is enabled.

                URL wsdlURLStr = MyClassApiImpl.class.getResource("/wsdl/name-1.0.wsdl");
                JaxWsProxyFactoryBean proxyFactory = new  JaxWsProxyFactoryBean();
                ClientFactoryBean clientBean = proxyFactory.getClientFactoryBean();
                clientBean.setAddress(soapURL.toString());
                clientBean.setServiceClass(SPMLRequestPortType.class);
                clientBean.setWsdlURL(wsdlURLStr.toString());
                SpringBusFactory bf = new SpringBusFactory();
                URL cxfConfig = null;
                proxyFactory.setBus(bf.createBus(cxfConfig));
               
                m_endPoint = (SPMLRequestPortType) proxyFactory.create();
                Client deviceClient = ClientProxy.getClient(m_endPoint);
                HTTPConduit http = (HTTPConduit) deviceClient.getConduit();
              
                TLSClientParameters tlsCP = new TLSClientParameters();
                String keyPassword = "changeit";  
                java.security.cert.Certificate certca = getCACertificate(); //customcall
                java.security.cert.Certificate cert = getClientCertificate(); //customcall
                
                KeyStore keyStore = KeyStore.getInstance("JKS");
                keyStore.load(null, keyPassword.toCharArray());      
                keyStore.setCertificateEntry("clientCert", cert);
                KeyManager[] myKeyManagers = getKeyManagers(keyStore, keyPassword);
                tlsCP.setKeyManagers(myKeyManagers);
                KeyStore trustStore = KeyStore.getInstance("JKS");
                
                trustStore.load(null, keyPassword.toCharArray());
                trustStore.setCertificateEntry("caCrt", certca);
                TrustManager[] myTrustStoreKeyManagers = getTrustManagers(trustStore);
                tlsCP.setTrustManagers(myTrustStoreKeyManagers);
                tlsCP.setDisableCNCheck(true);
                http.setTlsClientParameters(tlsCP);
                 
                HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
                httpClientPolicy.setConnectionTimeout(36000);
                httpClientPolicy.setAllowChunking(false);
                httpClientPolicy.setReceiveTimeout(32000);
                http.setClient(httpClientPolicy);

Above is the code I am using from java client. How can I make client certificate exchange to happen?

Edit:

Current scenario is that only server authentication happens (with only truststore certificate I can connect to my web service hosted behind HTTP server). But it looks like CXF supports specifying custom SSLSocketFactory. Can this force me to exchange client certificate without doing any configuration at HTTP Server? If its doable, probably I should be doing some logic in my web service to validate the client.

I am listing the snippet from my code that finally worked.

//....
Client deviceClient = ClientProxy.getClient(m_endPoint);
HTTPConduit http = (HTTPConduit) deviceClient.getConduit();              
TLSClientParameters tlsCP = new TLSClientParameters();
String keyPassword = "changeit";  
java.security.cert.Certificate certca = getCACertificate(); //customcall
java.security.cert.Certificate[] certchain = getClientCertificateChain(); //customcall

KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(null, keyPassword.toCharArray());
trustStore.setCertificateEntry("caCrt", certca);
TrustManager[] myTrustStoreKeyManagers = getTrustManagers(trustStore);
tlsCP.setTrustManagers(myTrustStoreKeyManagers);

KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(null, keyPassword.toCharArray());
PrivateKey key = getClientPrivateKey(); //custom call
keyStore.setKeyEntry("myKey", key, keyPassword.toCharArray(), certchain);       
KeyManager[] myKeyManagers = getKeyManagers(keyStore, keyPassword);
tlsCP.setKeyManagers(myKeyManagers); 

tlsCP.setDisableCNCheck(true);
tlsCP.setSecureSocketProtocol("TLSv1.2");
tlsCP.setCipherSuites(Collections.singletonList("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"));
http.setTlsClientParameters(tlsCP); 
           
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(36000);
httpClientPolicy.setAllowChunking(false);
httpClientPolicy.setReceiveTimeout(32000);
http.setClient(httpClientPolicy);
//...

I hope the above code does not have any security issues. In Apache HTTP Server configuration I did the following. TLSv1.3 was disabled for me.

SSLCACertificateFile "<cacert_that_issued_clientcert"
SSLVerifyClient require

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM