I have been trying to connect to a service endpoint which is 2 way SSL enabled. I am using Spring resttemplate. I have added the certificate in keystore, but I am getting the below mentioned error:
>org.springframework.web.client.ResourceAccessException: I/O error on POST request for "path":Received fatal alert: handshake_failure; nested exception is javax.net.ssl.SSLException: Received fatal alert: handshake_failure
I enabled the SSL debus logs and in the logs I can see the warning as well:
<BEA-000000> <Warning: no suitable certificate found - continuing without client authentication>
Same code is working fine with same implementation on my DEV server, but not working on UAT server, but on UAT server REST call on same endpoint is working fine(which is also 2 way SSL enabled). Below is the code that I am using for SOAP and REST call:
REST:
ObjectMapper mapper = new ObjectMapper();
ServReqRespLogMgr reqRespLogMgr = (ServReqRespLogMgr)UtilityMgr.getBean("servReqRespLogMgr");
SSLContext sc = SSLContext.getInstance(StringUtils.trimToEmpty(PropertyUtil.getProperty("SSL_CONTEXT")));
PasswordEncryptor pe = new PasswordEncryptor();
KeyManagerFactory factory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(PropertyUtil.getProperty("JKS_LOC_VALUE")), pe.decrypt(PropertyUtil.getProperty(IConstants.JKS_PWD_VALUE)).toCharArray());
factory.init(keyStore, pe.decrypt(PropertyUtil.getProperty(IConstants.JKS_PWD_VALUE)).toCharArray());
sc.init(factory.getKeyManagers(), null, null);
CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sc).build();
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
HttpHeaders headers = new HttpHeaders();
SOAP:
BindingProvider bindingProvider = (BindingProvider) services;
bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, filenetWsUrl);
Map<String, List<String>> headers = new HashMap<String, List<String>>();
headers.put("X-APPCERT", Arrays.asList(StringUtils.trimToEmpty(PropertyUtil.getProperty("FILENET_APP_CERT"))));
bindingProvider.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS,headers);
bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, filenetWsUrl);
SSLContext sc = SSLContext.getInstance(StringUtils.trimToEmpty(PropertyUtil.getProperty("SSL_CONTEXT")));
KeyManagerFactory factory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(PropertyUtil.getProperty("JKS_LOC_VALUE")), jksPwd);
factory.init(keyStore, jksPwd);
sc.init(factory.getKeyManagers(), null, null);
//sc.init(factory.getKeyManagers(), null, null);
//End Trust Store
((BindingProvider) services).getRequestContext().put(JAXWSProperties.SSL_SOCKET_FACTORY, sc.getSocketFactory());
I checked the permission on keystore file which looks good. If I switch to one way SSL endpoint then also its working fine. My Java run time is 1.8.0_144 and my app server is WebLogic 12.2.1.3.
Can anyone help me with this please?
Here are few things you have to check.
Check if your Cert chain is properly created.
Add your certs to CACERTS file and configure weblogic to point to the CACERTS file.
This should most definitely resolve your problem.
Related
Is there any example of how make a HTTPS call with a hapi fhir client ?
FhirContext ctx = new FhirContext();
IGenericClient client = ctx.newRestfulGenericClient("https://fhirtest.uhn.ca/base");
By default the above code will not work as the server will require SSL authentication.
how do I add SSL authentication to the hapi client ??
The next example shows how to connect to a FHIR server using https while using the HAPI FHIR client. Please be aware that this example accepts all certificates. To make it secure you should specify a truststore and a different hostname verifier.
FhirContext ctx = new FhirContext();
KeyStore truststore = null;
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(truststore, new TrustSelfSignedStrategy()).build();
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory sslFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslFactory).build();
ctx.getRestfulClientFactory().setHttpClient(httpClient);
IGenericClient client = ctx.newRestfulGenericClient("https://fhirtest.uhn.ca/base");
I'm putting together a soap client to call a thirdparty soap service. I'm having issues connecting with Java. It works fine with SoapUI. This is the first time I've set up a keystore within the app. All the code I have found is the same and pretty simple but I can't figure out why the java version isn't working.. I'm using a TLS pfx file provided by the company whose service I'm trying to connect too.
I'm getting a 403 back from the server.. Here is the code
URL wsdlLocation = new URL(SECURE_INTEGRATION_WSDL);
ObjectFactory ofactory = new ObjectFactory();
HttpsURLConnection httpsConnection = (HttpsURLConnection)wsdlLocation.openConnection();
char[] password = CLIENT_KEYSTORE_PASSWORD.toCharArray();
//load keystore
FileInputStream is = new FileInputStream(new File(CLIENT_KEYSTORE_PATH));
final KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(is, password);
is.close();
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keystore, password);
//set the ssl context
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null,
new java.security.SecureRandom());
httpsConnection.setSSLSocketFactory(sc.getSocketFactory());
SecureIntegrationServicesImap client = new SecureIntegrationServicesImap(wsdlLocation);
SesMessage message = ofactory.createSesMessage();
ReceiveRequest r = ofactory.createReceiveRequest();
r.setEmail(ofactory.createReceiveRequestEmail("<email ommitted>"));
ArrayOfMessageSummary messages = client.getWSHttpBindingSecureIntegrationServiceImap().getMessageList(r);
log.info(messages.getMessageSummary().size());
Any help with what I'm wrong is greatly appreciated..
Not sure if it matters but the server is a .NET platform
Here is the stacktrace I'm getting
javax.xml.ws.WebServiceException: Failed to access the WSDL at: https://<host omitted>/TS?wsdl. It failed with:
Server returned HTTP response code: 403 for URL: https://<host omitted>/TS?wsdl.
at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.tryWithMex(RuntimeWSDLParser.java:265)
at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:246)
at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:209)
at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:178)
at com.sun.xml.ws.client.WSServiceDelegate.parseWSDL(WSServiceDelegate.java:363)
at com.sun.xml.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:321)
at com.sun.xml.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:230)
at com.sun.xml.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:211)
at com.sun.xml.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:207)
at com.sun.xml.ws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:114)
at javax.xml.ws.Service.<init>(Service.java:77)
at org.tempuri.SecureIntegrationServicesImap.<init>(SecureIntegrationServicesImap.java:50)
at com.wiredinformatics.utils.SecureExchange.main(SecureExchange.java:127) Caused by: java.io.IOException: Server returned HTTP response code: 403 for URL: https://host omitted/TS?wsdl
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1876)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at java.net.URL.openStream(URL.java:1045)
at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.createReader(RuntimeWSDLParser.java:999)
at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.resolveWSDL(RuntimeWSDLParser.java:400)
at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:231)
... 11 more
It sounds like you're using TLS based client authentication. Based on the code you posted I suspect the issue is that you're not using httpsConnection anywhere after you initialize it. Therefore it's not trying to use your client certificate as you were expecting but is instead using the default request context settings.
Assuming you're using JAX-WS you should be able to use the solution outlined in this answer to bind your certificate to your request context (instead of initializing your own HttpsURLConnection):
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
I have been attempting to have my jersey client do a ssl client authentication with my Jersey/Grizzly Rest api. Other clients are successful handshaking with this server, but I am having trouble with my java client using Jersey client. When I run the code below, the keystore is successfully loaded and when the SslConfigurator's createSSLContext() is called, the ssl debug output shows this keystore properly being accessed and my private keys found.
However, when the Client's WebTarget is used, the ssl debug output shows the handshake is happening with the default keystore JKS. Why isn't the ClientBuilder using this keystore from the SSLContext?
File tmpConfigFile = File.createTempFile("pkcs11-", "conf");
tmpConfigFile.deleteOnExit();
PrintWriter configWriter = new PrintWriter(new FileOutputStream(tmpConfigFile), true);
configWriter.println("name=ActiveClient");
configWriter.println("library=\"C:\\\\Program Files\\\\ActivIdentity\\\\ActivClient\\\\acpkcs211.dll\"");
configWriter.println("slotListIndex=0");
SunPKCS11 provider = new SunPKCS11(tmpConfigFile.getAbsolutePath());
Security.addProvider(provider);
// KeyStore keyStore = KeyStore.getInstance("PKCS11", provider);
KeyStore keyStore = KeyStore.getInstance("PKCS11");
keyStore.load(null, null);
ClientConfig config = new ClientConfig();
SslConfigurator sslConfig = SslConfigurator.newInstance()
.keyStore(keyStore)
.keyStorePassword("mypin")
.keyStoreType("PKCS11")
.trustStoreFile(TRUSTORE_CLIENT_FILE)
.trustStorePassword(TRUSTSTORE_CLIENT_PWD)
.securityProtocol("TLS");
final SSLContext sslContext = sslConfig.createSSLContext();
Client client = ClientBuilder
.newBuilder().hostnameVerifier(new MyHostnNameVerifier())
.sslContext(sslContext)
.build();
WebTarget target = client.target("https://localhost:8443/appname/resources/employees?qparam=something");
Response res = target.request().accept(MediaType.APPLICATION_JSON).get();
This code actually worked. The problem was that my server's trust certificate wasn't available for the smart card cert that it needed to trust. I added the correct certs to the truststore on the server and then it worked. The ssl debug messages weren't very clear.
I've run into many issues this time and I found a way to achieve my goals. In your example I can not see any use of ClientConfig config instance. This worked for me:
ClientConfig config = new ClientConfig();
config.connectorProvider(new ApacheConnectorProvider());
Client client = ClientBuilder.newBuilder().hostnameVerifier(new MyHostnNameVerifier())
.sslContext(sslContext).withConfig(config).build();
I found ApacheConnectorProvider more suitable for connections using secure layers or proxies (witch was another huge problem I solved).
SslContextFactory sec = new SslContextFactory();
sec.setValidateCerts(false);
WebSocketClient client = new WebSocketClient(sec);
The above code is implemented for Jetty WebSockets, to tell the java client to disable certificate validation. Is there any way I can achieve the same in Java API for Tomcat8 WebSockets (JSR-356)?
PS: I have tried this method. It didn't work for Secure WebSocket connection of Tomcat WebSockets
Did you generate self signed certificate and trying to use it?
Then import your self signed certificate to new keystore and use that keystore as a trust store on your client side.
For a tyrus websocket client, I use like this:
String keyStorePath = StompClientTest.class.getResource("/myapp.keystore").getPath();
System.getProperties().put("javax.net.debug", "all"); // debug your certificate checking
System.getProperties().put(SslContextConfigurator.KEY_STORE_FILE, keyStorePath);
System.getProperties().put(SslContextConfigurator.TRUST_STORE_FILE, keyStorePath);
System.getProperties().put(SslContextConfigurator.KEY_STORE_PASSWORD, "secret");
System.getProperties().put(SslContextConfigurator.TRUST_STORE_PASSWORD, "secret");
final SslContextConfigurator defaultConfig = new SslContextConfigurator();
defaultConfig.retrieve(System.getProperties());
SslEngineConfigurator sslEngineConfigurator = new SslEngineConfigurator(defaultConfig);
sslEngineConfigurator.setHostVerificationEnabled(false);
StandardWebSocketClient webSocketClient = new StandardWebSocketClient();
webSocketClient.getUserProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
For tomcat read answer in following question: https://stackoverflow.com/a/32205864/386213
I want to connect to a https jira server using the jersey client (version 1.1.9).
How do I need to configure the security options to make use of the REST-API?
I followed these instructions:
Accessing secure restful web services using jersey client
But the first link in the answer is broken and I don't know how to configure the truststore and the keystore. Where do I get these files?
I switched to jersey-client-2.19 and configured the keystore and truststore with the keytool.
System.setProperty("jsse.enableSNIExtension", "false");
SslConfigurator sslConfig = SslConfigurator.newInstance()
.trustStoreFile("C:/Program Files/Java/jre1.8.0_45/lib/security/cacerts.jks")
.trustStorePassword("somepass")
.keyStoreFile("C:/Program Files/Java/jre1.8.0_45/lib/security/keystore.jks")
.keyPassword("somepass");
SSLContext sslContext = sslConfig.createSSLContext();
Client client = ClientBuilder.newBuilder().sslContext(sslContext)
.build();
HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic(
JIRA_ADMIN_USERNAME, JIRA_ADMIN_PASSWORD);
client.register(feature);
WebTarget webTarget = client.target(JIRA_URL);
WebTarget projectWebTarget = webTarget.path("project");
Invocation.Builder invocationBuilder = projectWebTarget
.request(MediaType.APPLICATION_JSON);
Response response = invocationBuilder.get();
System.out.println(response.getStatus());
System.out.println(response.readEntity(String.class));
Maybe there is a better way to set the properties for the keystore and truststore. So please let me know.