I have a cxf service running at
https://localhost:8443/services/MyService?wsdl
with client certificate required. The WSDL is not important here.
I am able to invoke the service when I remove the client certificate or https requirement.
The service and client classes were generated with cxf wsdl2java utility.
Here is MyService.class:
package com.mycompany;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceFeature;
/**
* This class was generated by Apache CXF 2.7.3 2013-03-29T13:59:37.423-03:00 Generated source version: 2.7.3
*/
#WebServiceClient(name = "MyService", wsdlLocation = "myservice.wsdl", targetNamespace = "http://server/schemas/services")
public class MyService extends Service {
public final static URL WSDL_LOCATION;
public final static QName SERVICE = new QName("http://server/schemas/services", "MyService");
public final static QName MyServicePort = new QName("http://server/schemas/services", "MyServicePort");
static {
URL url = MyService.class.getResource("myservice.wsdl");
if (url == null) {
Logger.getLogger(MyService.class.getName()).log(Level.INFO, "Can not initialize the default wsdl from {0}", "myservice.wsdl");
}
WSDL_LOCATION = url;
}
public MyService(URL wsdlLocation) {
super(wsdlLocation, SERVICE);
}
public MyService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public MyService() {
super(WSDL_LOCATION, SERVICE);
}
/**
*
* #return returns EncaminharMensagemPortType
*/
#WebEndpoint(name = "MyServicePort")
public MyServicePortType getMyServicePort() {
return super.getPort(MyServicePort, MyServicePortType.class);
}
/**
*
* #param features
* A list of {#link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the
* <code>features</code> parameter will have their default values.
* #return returns EncaminharMensagemPortType
*/
#WebEndpoint(name = "MyServicePort")
public MyServicePortType getMyServicePort(WebServiceFeature... features) {
return super.getPort(MyServicePort, MyServicePortType.class, features);
}
}
Here is my client without client certificate requirement: (that work fine)
package com.mycompany;
import java.net.URL;
import javax.xml.namespace.QName;
import com.mycompany.IdHolder;
import com.mycompany.MyDataObject;
public class CxfClientSslTest {
public static void main(String[] args) {
try {
QName SERVICE_NAME = new QName("http://server/schemas/services", "MyService");
URL wsdlURL = new URL("https://localhost:8443/services/MyService?wsdl");
MyService ss = new MyService(wsdlURL, SERVICE_NAME);
MyServicePortType port = ss.getMyServicePort();
IdHolder mensagem = new IdHolder();
mensagem.setId(1L);
MyDataObject dataObject = port.getById(mensagem);
System.out.println("Id: " + dataObject.getId());
} catch (Exception e) {
e.printStackTrace();
}
}
}
And here is my client send his certificate:
package com.mycompany;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.xml.namespace.QName;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.HTTPConduit;
public class CxfClientSslTest {
public static void main(String[] args) {
try {
QName SERVICE_NAME = new QName("http://server/schemas/services", "MyService");
URL wsdlURL = new URL("https://localhost:8443/services/MyService?wsdl");
MyService ss = new MyService(wsdlURL, SERVICE_NAME);
MyServicePortType port = ss.getMyServicePort();
tslIt(port);
IdHolder mensagem = new IdHolder();
mensagem.setId(1L);
MyDataObject dataObject = port.getById(mensagem);
System.out.println("Id: " + dataObject.getId());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void tslIt(MyServicePortType port) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
UnrecoverableKeyException {
Client client = ClientProxy.getClient(port);
HTTPConduit http = (HTTPConduit) client.getConduit();
TLSClientParameters tlsClientParameters = http.getTlsClientParameters();
KeyStore keyStore = getKeyStore();
KeyStore trustStore = getTrustStore();
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "123456".toCharArray());
KeyManager[] keyMgrs = keyManagerFactory.getKeyManagers();
tlsClientParameters.setKeyManagers(keyMgrs);
trustManagerFactory.init(trustStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
tlsClientParameters.setTrustManagers(trustManagers);
tlsClientParameters.setDisableCNCheck(true);
}
public static KeyStore getKeyStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
URL keyStoreUrl = CxfClientSslTest.class.getResource("/certs/client.jks");
File keystoreFile = new File(keyStoreUrl.getPath());
if (!keystoreFile.exists()) {
throw new RuntimeException("keystore doesn't exists: " + keystoreFile.getAbsolutePath());
}
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream keystoreInput = new FileInputStream(keystoreFile.getAbsolutePath());
keystore.load(keystoreInput, "changeit".toCharArray());
keystoreInput.close();
return keystore;
}
public static KeyStore getTrustStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
URL trustStoreUrl = CxfClientSslTest.class.getResource("/certs/client-trust.jks");
File trustStoreFile = new File(trustStoreUrl.getPath());
if (!trustStoreFile.exists()) {
throw new RuntimeException("truststore doesn't exists: " + trustStoreFile.getAbsolutePath());
}
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream trustStoreInput = new FileInputStream(trustStoreFile.getAbsolutePath());
trustStore.load(trustStoreInput, "changeit".toCharArray());
trustStoreInput.close();
return trustStore;
}
}
The TLS configuration both from client and server were checked and are ok. But when I run the program I get this:
Information: Can not initialize the default wsdl from myservice.wsdl
javax.xml.ws.WebServiceException: org.apache.cxf.service.factory.ServiceConstructionException: Failed to create service.
at org.apache.cxf.jaxws.ServiceImpl.<init>(ServiceImpl.java:149)
at org.apache.cxf.jaxws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:98)
at javax.xml.ws.Service.<init>(Service.java:77)
at com.mycompany.MyService.<init>(MyService.java:36)
at com.mycompany.CxfClientSslTest.main(CxfClientSslTest.java:32)
Caused by: org.apache.cxf.service.factory.ServiceConstructionException: Failed to create service.
at org.apache.cxf.wsdl11.WSDLServiceFactory.<init>(WSDLServiceFactory.java:100)
at org.apache.cxf.jaxws.ServiceImpl.initializePorts(ServiceImpl.java:199)
at org.apache.cxf.jaxws.ServiceImpl.<init>(ServiceImpl.java:147)
... 4 more
Caused by: javax.wsdl.WSDLException: WSDLException: faultCode=PARSER_ERROR: Problem parsing 'https://localhost:8443/services/MyService?wsdl'.: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found
at com.ibm.wsdl.xml.WSDLReaderImpl.getDocument(Unknown Source)
at com.ibm.wsdl.xml.WSDLReaderImpl.readWSDL(Unknown Source)
at com.ibm.wsdl.xml.WSDLReaderImpl.readWSDL(Unknown Source)
at org.apache.cxf.wsdl11.WSDLManagerImpl.loadDefinition(WSDLManagerImpl.java:262)
at org.apache.cxf.wsdl11.WSDLManagerImpl.getDefinition(WSDLManagerImpl.java:205)
at org.apache.cxf.wsdl11.WSDLServiceFactory.<init>(WSDLServiceFactory.java:98)
... 6 more
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1868)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1337)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:154)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:998)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1294)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1321)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1305)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:523)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1296)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:653)
at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:189)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:799)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:123)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:240)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:300)
... 12 more
Caused by: java.security.cert.CertificateException: No name matching localhost found
at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:208)
at sun.security.util.HostnameChecker.match(HostnameChecker.java:93)
at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:347)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:203)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1319)
... 30 more
I can see that the problem is happening before my https configuration get done, when cxf tries to download the wsdl.
I made a research on how to make cxf use that https configuration to download the wsdl. It take me a lot of time, but I can't find the answer out there.
So my question is: how to make cxf use the https configuration to download the wsdl?
Please, I have the answer already and I intend to put it here. So, if you don't have a good answer, or better the answer, please don't post one.
After a lot of research on the web without success, I decide it is time to debug the cxf API. That is one of the points of open source, right?
So I found out that cxf don't download directly the wsdl. It delegates that to wsdl4j through the call of
javax.wsdl.xml.WSDLReader.readWSDL(javax.wsdl.xml.WSDLLocator)
which calls
javax.wsdl.xml.WSDLLocator.getBaseInputSource()
which calls
org.apache.cxf.wsdl11.ResourceManagerWSDLLocator.getInputSource(String, String)
because ResourceManagerWSDLLocator were the WSDLLocator of the first method call.
ResourceManagerWSDLLocator.getInputSource first line is:
InputStream ins = bus.getExtension(ResourceManager.class).getResourceAsStream(importLocation);
Now as ResourceManager is a extension of xcf's Bus, and you can add more ResourceResolver to it and the DefaultResourceManager (implements ResourceManager) will loop through all registered resolvers and will use the first one resolving a non-null value, you just need add a ResourceResolver to the ResourceManager.
My final and working client application is:
package com.mycompany;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.xml.namespace.QName;
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.resource.ResourceManager;
import org.apache.cxf.resource.ResourceResolver;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.BasicClientConnectionManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
public class CxfClientSslTest {
public static void main(String[] args) {
try {
Bus bus = BusFactory.getThreadDefaultBus();
ResourceManager extension = bus.getExtension(ResourceManager.class);
extension.addResourceResolver(new ResourceResolver() {
#Override
public <T> T resolve(String resourceName, Class<T> resourceType) {
System.out.println("resourceName: " + resourceName + " - resourceType: " + resourceType);
return null;
}
#Override
public InputStream getAsStream(String name) {
try {
if (!name.startsWith("https")) {
return null;
}
SSLSocketFactory sslSocketFactory = SslUtil.getSslSocketFactory();
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("https", 8443, sslSocketFactory));
final HttpParams httpParams = new BasicHttpParams();
DefaultHttpClient httpClient = new DefaultHttpClient(new BasicClientConnectionManager(schemeRegistry), httpParams);
HttpGet get = new HttpGet(name);
HttpResponse response = httpClient.execute(get);
return response.getEntity().getContent();
} catch (Exception e) {
return null;
}
}
});
QName SERVICE_NAME = new QName("http://server/schemas/services", "MyService");
URL wsdlURL = new URL("https://localhost:8443/services/MyService?wsdl");
MyService ss = new MyService(wsdlURL, SERVICE_NAME);
MyServicePortType port = ss.getMyServicePort();
tslIt(port);
IdHolder mensagem = new IdHolder();
mensagem.setId(1L);
MyDataObject dataObject = port.getById(mensagem);
System.out.println("Id: " + dataObject.getId());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void tslIt(MyServicePortType port) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
UnrecoverableKeyException {
Client client = ClientProxy.getClient(port);
HTTPConduit http = (HTTPConduit) client.getConduit();
TLSClientParameters tlsClientParameters = http.getTlsClientParameters();
KeyStore keyStore = getKeyStore();
KeyStore trustStore = getTrustStore();
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "123456".toCharArray());
KeyManager[] keyMgrs = keyManagerFactory.getKeyManagers();
tlsClientParameters.setKeyManagers(keyMgrs);
trustManagerFactory.init(trustStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
tlsClientParameters.setTrustManagers(trustManagers);
tlsClientParameters.setDisableCNCheck(true);
}
public static KeyStore getKeyStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
URL keyStoreUrl = CxfClientSslTest.class.getResource("/certs/client.jks");
File keystoreFile = new File(keyStoreUrl.getPath());
if (!keystoreFile.exists()) {
throw new RuntimeException("keystore doesn't exists: " + keystoreFile.getAbsolutePath());
}
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream keystoreInput = new FileInputStream(keystoreFile.getAbsolutePath());
keystore.load(keystoreInput, "changeit".toCharArray());
keystoreInput.close();
return keystore;
}
public static KeyStore getTrustStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
URL trustStoreUrl = CxfClientSslTest.class.getResource("/certs/client-trust.jks");
File trustStoreFile = new File(trustStoreUrl.getPath());
if (!trustStoreFile.exists()) {
throw new RuntimeException("truststore doesn't exists: " + trustStoreFile.getAbsolutePath());
}
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream trustStoreInput = new FileInputStream(trustStoreFile.getAbsolutePath());
trustStore.load(trustStoreInput, "changeit".toCharArray());
trustStoreInput.close();
return trustStore;
}
}
I think the standard way in apache cxf is to set-up an http conduit in your cxf.xml refering to your jks keystore:
<http:conduit id="{Namespace}PortName.http-conduit">
<http:tlsClientParameters>
...
<sec:trustManagers>
<sec:keyStore type="JKS"
password="StorePass"
file="certs/truststore.jks"/>
</sec:trustManagers>
...
</http:tlsClientParameters>
</http:conduit>
More information here: Configuring SSL support
tlsClientParameters.setUseHttpsURLConnectionDefaultSslSocketFactory(false);
Above line is required to disable default SslSocketFactory (which will ignore the keyStore and trustStore configured in tlsClientParamters)
Adding to reply https://stackoverflow.com/a/15755512/19664676
by #DiogoSantana
One can simply add HTTPConduitConfigurer extension to bus like this.
package com.mycompany;
import com.mycompany.IdHolder;
import com.mycompany.MyDataObject;
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transport.http.HTTPConduitConfigurer;
import java.net.URL;
import java.security.SecureRandom;
import javax.net.ssl.SSLContext;
import javax.xml.namespace.QName;
public class CxfClientSslTest {
public static void main(String[] args) {
Bus bus = BusFactory.getThreadDefaultBus();
bus.setExtension(new HTTPConduitConfigurer() {
#Override
public void configure(String name, String address, HTTPConduit c) {
//crate and configure sslcontext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(getKeyManagers(), getTrustManagers(), new SecureRandom());
TLSClientParameters tls = new TLSClientParameters();
//configure tls client params here
tls.setSSLSocketFactory(sslContext.getSocketFactory());
//set tls client params
c.setTlsClientParameters(tls);
}
}, HTTPConduitConfigurer.class);
QName SERVICE_NAME = new QName("http://server/schemas/services", "MyService");
URL wsdlURL = new URL("https://localhost:8443/services/MyService?wsdl");
MyService ss = new MyService(wsdlURL, SERVICE_NAME);
MyServicePortType port = ss.getMyServicePort();
IdHolder mensagem = new IdHolder();
mensagem.setId(1L);
MyDataObject dataObject = port.getById(mensagem);
System.out.println("Id: " + dataObject.getId());
}
}
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found
Above exception happens When you create your self-signed certificate with your name,
To resolve this exception, you need to add "localhost" on the following step
What is your first and last name?
[Unknown]: localhost
Related
I've been asked to migrate a Java 8 (spring) micro-service to a Java 11 microservice (Quarkus framework).
The microservice uses a X509 certificate to authenticate to a MongoDB 4.4 database. This works well for the Java 8 version without any error or issue.
Nevertheless the Java 11 version won't work and it displays the following Stack Trace when deployed:
com.mongodb.MongoSocketWriteException: Exception sending message
at com.mongodb.internal.connection.InternalStreamConnection.translateWriteException(InternalStreamConnection.java:619)
at com.mongodb.internal.connection.InternalStreamConnection.sendMessage(InternalStreamConnection.java:497)
at com.mongodb.internal.connection.InternalStreamConnection.sendCommandMessage(InternalStreamConnection.java:328)
at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:278)
at com.mongodb.internal.connection.CommandHelper.sendAndReceive(CommandHelper.java:83)
at com.mongodb.internal.connection.CommandHelper.executeCommand(CommandHelper.java:33)
at com.mongodb.internal.connection.InternalStreamConnectionInitializer.initializeConnectionDescription(InternalStreamConnectionInitializer.java:107)
at com.mongodb.internal.connection.InternalStreamConnectionInitializer.initialize(InternalStreamConnectionInitializer.java:62)
at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:144)
at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.lookupServerDescription(DefaultServerMonitor.java:188)
at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:144)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: javax.net.ssl.SSLHandshakeException: PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
Relevant Source Code:
package everest.onecd.config;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
public class MongoConfiguration {
private static final String PATH = "/usr/share/easy-rsa/keys/java11/mongo.jks";
private static final Logger LOG = LoggerFactory.getLogger(MongoConfiguration.class);
private static final String IP = "XX.XX.XX.XX";
private static final String PORT = "27017";
public static MongoDatabase getDatabase() {
SSLContext context = getSSLContext();
MongoClientSettings.Builder settings = MongoClientSettings.builder();
settings.applyToSslSettings(builder -> { builder.context(context); builder.invalidHostNameAllowed(true); builder.enabled(true); });
settings.applyConnectionString(new ConnectionString("mongodb://" + IP + ":" + PORT + "/test?ssl=true&authMechanism=MONGODB-X509&connectTimeoutMS=60000&socketTimeoutMS=60000&retryWrites=true&maxIdleTimeMS=60000"));
MongoClient client = MongoClients.create(settings.build());
MongoDatabase database = client.getDatabase("test");
return database;
}
private static SSLContext getSSLContext() {
SSLContext sslContext = null;
try (FileInputStream fis = new FileInputStream(new File(PATH))) {
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(fis, ".sevenzip".toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
LOG.info("Se ejecuto SSLContext exitosamente");
} catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException | KeyManagementException e) {
LOG.error(e.toString(), e);
}
return sslContext;
}
}
I already tried this: Java 11 and 12 SSL sockets fail on a handshake_failure error with TLSv1.3 enabled
So, I generated the new JKS with -keyalg RSA but it didn't work either. I also changed the TLS version to 1.2 and 1.3 and got the same exception.
This is the solution, after all the struggle. In Quarkus, it is required to fully inicialize all trust stores and key stores. So, aparently, it ignores both JVM args -Djavax.net.ssl.keyStore and -Djavax.net.ssl.trustStore.
private static SSLContext getSSLContext() {
SSLContext sslContext = null;
try (FileInputStream fis = new FileInputStream(new File(TPATH))) {
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(fis, ".sevenzip".toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
FileInputStream fKS = new FileInputStream(new File(PATH));
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(fKS, ".sevenzip".toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, ".sevenzip".toCharArray());
sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
LOG.info("Se ejecuto SSLContext exitosamente");
} catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException | KeyManagementException e) {
LOG.error(e.toString(), e);
} catch (UnrecoverableKeyException e) {
LOG.error(e.toString(), e);
}
return sslContext;
}
I use SSL security in my Spring Boot application. While calling the address
final UriComponents uriComponents
= uriComponentsBuilder.path("/api/v1.0/register/token/{token}").buildAndExpand(token);
ResponseEntity<Boolean> response;
try {
response = restTemplate
.exchange(uriComponents.toUri(),
HttpMethod.PUT,
entity,
Boolean.class);
throw away me https://pastebin.com/A4Vb69hT carefully
I/O error on PUT request for "https://localhost:8443/api/v1.0/register/token/PBe3AzJ245W0sNyeg": java.security.cert.CertificateException: No name matching localhost found; nested exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found
I found on the Internet on the website http://java.globinch.com/enterprise-java/security/fix-java-security-certificate-exception-no-matching-localhost-found/
static {
//for localhost testing only
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
(hostname, sslSession) -> hostname.equals("localhost"));
}
after adding it, it receives further errors https://pastebin.com/kJZCqJ6K carefully
I/O error on PUT request for "https://localhost:8443/api/v1.0/register/token/EMNy7W9jJgsMWEn0z6hFOIHoB96zzSaeHWUs": sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
What should I do now?
I have two SSL files https://github.com/JonkiPro/REST-Web-Services/tree/master/src/main/resources/keystore
This answer is some kind of hack to run locally though enabling in actual environment will still work with certificates.
Just call SSLContextHelper.disable() before restTemplate.exchange
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import javax.security.cert.X509Certificate;
import org.apache.log4j.Logger;
public class SSLContextHelper {
private static final String KEY_STORE_TYPE="JKS";
private static final String CLASS_NAME=SSLContextHelper.class.getName();
private static final String TRANSPORT_SECURITY_PROTOCOL="TLS";
private static final Logger logger=Logger.getLogger(SSLContextHelper.class);
public static void enable(){
String keystoreType = "JKS";
InputStream keystoreLocation = null;
char [] keystorePassword = null;
char [] keyPassword = null;
try {
KeyStore keystore = KeyStore.getInstance(keystoreType);
keystore.load(keystoreLocation, keystorePassword);
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmfactory.init(keystore, keyPassword);
InputStream truststoreLocation = null;
char [] truststorePassword = null;
String truststoreType = KEY_STORE_TYPE;
KeyStore truststore = KeyStore.getInstance(truststoreType);
truststore.load(truststoreLocation, truststorePassword);
TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyManager [] keymanagers = kmfactory.getKeyManagers();
TrustManager [] trustmanagers = tmfactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance(TRANSPORT_SECURITY_PROTOCOL);
sslContext.init(keymanagers, trustmanagers, new SecureRandom());
SSLContext.setDefault(sslContext);
} catch (Exception e) {
logger.error(CLASS_NAME+"Exception in SSL "+e.getMessage());
e.printStackTrace();
}
}
public static void disable() {
try {
SSLContext sslc = SSLContext.getInstance("TLS");
TrustManager[] trustManagerArray = { (TrustManager) new NullX509TrustManager() };
sslc.init(null, trustManagerArray, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new NullHostnameVerifier());
} catch(Exception e) {
e.printStackTrace();
}
}
private static class NullX509TrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
System.out.println();
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
System.out.println();
}
}
private static class NullHostnameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
The certificate of server is not a valid certificate chain or is probably self signed. Add the certificate to your trust store as trusted certificate ( do it only if you know it's a testing local certificate) and then try.
For details you can see https://eclipse-ee4j.github.io/mail/InstallCert
Certificate does not match the hostname, in this case localhost. please check that your self-signed certificate is using the right CN and if not recreate it.
Good article how to fix error :
http://java.globinch.com/enterprise-java/security/fix-java-security-certificate-exception-no-matching-localhost-found/
I am creating a client and a server that connect via java SSL sockets. Only the server is authenticated (one-way authentication). After the client connects to the server, the client will prompt the user for a single line of input and send it to the server.
Whenever I run the client I get the following error:
Exception in thread "main" java.lang.IllegalStateException: KeyManagerFactoryImpl is not initialized
at sun.security.ssl.KeyManagerFactoryImpl.engineGetKeyManagers(KeyManagerFactoryImpl.java:51)
at javax.net.ssl.KeyManagerFactory.getKeyManagers(KeyManagerFactory.java:289)
at SSLClient.createSSLContext(SSLClient.java:43)
at SSLClient.main(SSLClient.java:50)
My Client code is:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
public class SSLClient {
public static final int PORT_NO = 9020;
static void doProtocol( Socket cSock ) throws IOException
{
OutputStream out = cSock.getOutputStream();
InputStream in = cSock.getInputStream();
out.write("World".getBytes());
out.write('!');
int ch = 0;
while ((ch = in.read()) != '!')
{
System.out.print((char)ch);
}
System.out.println((char)ch);
}
static SSLContext createSSLContext() throws Exception
{
// set up a key manager for our local credentials
KeyManagerFactory mgrFact = KeyManagerFactory.getInstance("SunX509");
// KeyStore clientStore = KeyStore.getInstance("PKCS12");
// clientStore.load(new FileInputStream("client.p12"), "Password");
// mgrFact.init(clientStore, "password");
// create a context and set up a socket factory
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(mgrFact.getKeyManagers(), null, null);
return sslContext;
}
public static void main( String[] args ) throws Exception
{
SSLContext sslContext = createSSLContext();
SSLSocketFactory fact = sslContext.getSocketFactory();
// SSLSocketFactory fact = (SSLSocketFactory)SSLSocketFactory.getDefault();
SSLSocket cSock = (SSLSocket)fact.createSocket("localhost", PORT_NO);
doProtocol(cSock);
}
}
My Server code is:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;
import java.security.Principal;
import java.util.Date;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.crypto.tls.Certificate;
import org.bouncycastle.jcajce.provider.asymmetric.x509.KeyFactory;
public class SSLSocketServer {
public static int SERVER_PORT = 9020;
static boolean isEndEntity( SSLSession session ) throws SSLPeerUnverifiedException
{
Principal id = session.getPeerPrincipal();
if (id instanceof X500Principal)
{
X500Principal x500 = (X500Principal)id;
String Expireddate = x500.getName("Expireddate");
String Name = x500.getName("Name");
return (Name.equals("James") && Date.parse(Expireddate) > System.currentTimeMillis());
}
return false;
}
/**
* Carry out the '!' protocol - server side.
*/
static void doProtocol(
Socket sSock)
throws IOException
{
System.out.println("session started.");
InputStream in = sSock.getInputStream();
OutputStream out = sSock.getOutputStream();
// Send Key
out.write("Hello ".getBytes());
int ch = 0;
while ((ch = in.read()) != '!')
{
out.write(ch);
}
out.write('!');
sSock.close();
}
/**
* Create an SSL context with identity and trust stores in place
*/
SSLContext createSSLContext()
throws Exception
{
// set up a key manager for our local credentials
KeyManagerFactory mgrFact = KeyManagerFactory.getInstance("SunX509");
KeyStore serverStore = KeyStore.getInstance("JKS");
serverStore.load(new FileInputStream("server.jks"), "password".toCharArray());
mgrFact.init(serverStore, "password".toCharArray());
// set up a trust manager so we can recognize the server
TrustManagerFactory trustFact = TrustManagerFactory.getInstance("SunX509");
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("trustStore.jks"), "trustpassword".toCharArray());
trustFact.init(trustStore);
// create a context and set up a socket factory
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(mgrFact.getKeyManagers(), trustFact.getTrustManagers(), null);
return sslContext;
}
public static void main( String[] args ) throws Exception
{
SSLServerSocketFactory fact = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
SSLServerSocket sSock = (SSLServerSocket)fact.createServerSocket(SERVER_PORT);
SSLSocket sslSock = (SSLSocket)sSock.accept();
sSock.setNeedClientAuth(false); // current ignore
doProtocol(sslSock);
}
}
You will need to call one of the KeyManagerFactories init methods:
init(KeyStore ks, char[] password)
or
init(ManagerFactoryParameters spec)
prior to calling KeyManagerFactory.getKeyManagers() otherwise it will throw the observed IllegalStateException.
Your code could for example look somthing like this:
...
final KeyStore keyStore = KeyStore.getInstance("JKS");
try (final InputStream is = new FileInputStream(fullPathOfKeyStore())) {
keyStore.load(is, JKS_PASSWORD);
}
final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
.getDefaultAlgorithm());
kmf.init(keyStore, KEY_PASSWORD);
...
See programcreek.com for full example.
I am facing problem with connecting to elasticsearch(ELK) using Jest API. I am looking for rest based java API for ELK which supports SCROLL & SCAN and also support certificate based authentication.
I found out Jest and Flummi are the available one's.
Since Jest is popular and has more support, I am trying to use it.
My ELK db needs an certificate for authentication, which I have installed in Personal certificates.
My question is how do I use Jest Client to do a Http request with the certificate? I have found some code, but it dint help me. My code is below.
package pkg;
import io.searchbox.core.*;
import com.google.gson.JsonArray;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestClientFactory;
import io.searchbox.client.JestResult;
import io.searchbox.client.config.HttpClientConfig;
import io.searchbox.params.Parameters;
public class ScrollELK {
private static final String INDEX = "daivb-logs";
private static final String TYPE = "cep";
public void scroll() throws IOException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, NoSuchProviderException {
//SSL certificate incorporation
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy()
{ #java.lang.Override
public boolean isTrusted(java.security.cert.X509Certificate[] x509Certificates, java.lang.String s) throws CertificateException {
return false;}
}).build();
// skip hostname checks
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
SchemeIOSessionStrategy httpsIOSessionStrategy = new SSLIOSessionStrategy(sslContext, hostnameVerifier);
// Get Jest client
HttpClientConfig clientConfig = new HttpClientConfig
.Builder("https://***.net/")
.multiThreaded(true)
.connTimeout(2000)
.defaultSchemeForDiscoveredNodes("https")
.sslSocketFactory(sslSocketFactory)
.httpsIOSessionStrategy(httpsIOSessionStrategy)
.build();
JestClientFactory factory = new JestClientFactory();
factory.setHttpClientConfig(clientConfig);
JestClient client = factory.getObject();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
Search search = new Search.Builder(searchSourceBuilder.toString())
.addIndex(INDEX)
.addType(TYPE)
.setParameter(Parameters.SIZE, 100)
.setParameter(Parameters.SCROLL, "5m")
.setParameter(Parameters.SEARCH_TYPE, "scan")
.build();
JestResult result = client.execute(search);
JsonArray hits = result.getJsonObject().getAsJsonObject("hits").getAsJsonArray("hits");
String scrollId = result.getJsonObject().get("_scroll_id").getAsString();
int count =0;
do
{ SearchScroll scroll = new SearchScroll.Builder(scrollId, "5m")
.build();
result = client.execute(scroll);
hits = result.getJsonObject().getAsJsonObject("hits").getAsJsonArray("hits");
scrollId = result.getJsonObject().getAsJsonPrimitive("_scroll_id").getAsString();
count =result.getJsonObject().getAsJsonObject("hits").getAsJsonArray("hits").size();
System.out.println(count);
}while(count>0);
// clear a single scroll id
ClearScroll clearScroll = new ClearScroll.Builder().addScrollId(scrollId).build();
result = client.execute(clearScroll);
}
}
Pls suggest on the issue.
private SSLContext createSSLContext() {
try {
SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(null, (x509Certificates, s) -> true);
final SSLContext sslContext = sslBuilder.build();
return sslContext;
} catch (Exception e) {
LOGGER.error("cannot create SSLContext", e);
}
return null;
}
I know that to load a certificate to use, I need to call KeyStore.load(InputStream, char[]);. How could I load the certificate on the client side if I need the password? I don't need this when connecting to Google, but I want to use Trust Managers to validate Google certificates. I also cannot make a SSLServerSocket and connect to it without loading a certificate.
EDIT: Added code:
package testing;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SSLClientTest {
public static void main(String[] args) {
int port = 443;
String host = "google.com";
try {
SSLContext sc = SSLContext.getInstance("TLSv1.2");
KeyStore ks = KeyStore.getInstance("JKS");
InputStream ksIs = new FileInputStream("securecert.certificate");
try {
ks.load(ksIs, "pwdpwdpwd".toCharArray());
} finally {
if (ksIs != null) {
ksIs.close();
}
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "pwdpwdpwd".toCharArray());
sc.init(kmf.getKeyManagers(),
new TrustManager[] { new MyTrustManager() }, null);
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory
.getDefault();
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
socket.startHandshake();
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
System.out.println(in.readLine());
in.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static final class MyTrustManager implements X509TrustManager {
#Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
#Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
#Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] {};
}
}
}
Note that I have to load the certificate, securecert.certificate, at the like of code ks.load(InputStream, char[]); I of course know the password, but what if I don't? Then how could I validate the certificate with a trust manager? This code simply locks. Please answer. Thanks!
Seems that you need a client authentication through SSL and you want let the user enter the password for his keystore. Based on your explanation I suppose that each installed client has its own keystore from a local path (If not the question has nonsense because if the keystore is always the same you don't need to pass a different password each time... however if this is the case you've to check if this client it's secure).
So to let the user enter a password you can instantiate the keystore in a different way instead of using KeyStore.getInstance(InputStream, Char[]), you can use KeyStore.Builder.newInstance and KeyStore.CallbackHandlerProtection methods, and you have to create a class which implements javax.security.auth.callback.CallbackHandler, this class have to override handle() method for example using swing or awt panel to let the user introduce the password. Below I show you some sample code to guide you through this steps:
Load the keystore
import java.io.File;
import java.security.KeyStore;
import java.security.Provider;
import java.util.Enumeration;
public class KeyStoreCallbackSample {
public static void main(String args[]) throws Exception {
// instantiate a keystore to get the provider for specific type
KeyStore ks = KeyStore.getInstance("JKS");
// create the callback handler to get the password
KeyStore.CallbackHandlerProtection cbhp = new KeyStore.CallbackHandlerProtection(new YourImplementationCallbackHander());
// create the builder passing keystoreType, provider, keystore file, and callbackhandler
KeyStore.Builder builder = KeyStore.Builder.newInstance("JKS", ks.getProvider(), new File("/path/YourKeyStore.jks"), cbhp);
// create the keystore
ks = builder.getKeyStore();
// print the keystores alias to check if all it's load correctly
Enumeration<String> aliases = ks.aliases();
while(aliases.hasMoreElements()){
System.out.println(aliases.nextElement());
}
}
}
CallbackHandler implementation
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
/**
* PIN handler for keystores
*/
public class PinInputHandler implements CallbackHandler {
private char[] lastPassword;
public PinInputHandler(){}
// implement this method to handle the callback
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback cb : callbacks) {
if (cb instanceof javax.security.auth.callback.PasswordCallback) {
javax.security.auth.callback.PasswordCallback pcb = (javax.security.auth.callback.PasswordCallback) cb;
try {
this.lastPassword = // HERE YOUR SWING OR AWT OR ANOTHER WAY TO GET THE PASSWORD FROM THE CLIENT
} catch (Exception e) {}
pcb.setPassword(this.lastPassword);
}
}
}
}
If you need more info you can check at KeyStore, KeyStore.Builder, KeyStore.CallbackHandlerProtection and CallbackHandlerdocumentation.
Hope this helps,