Calling WS with SSL in java - java

I connect to a web service with this client that work fine:
WSCSI WSCS = new WSCSI("http://localhost:8080/ServiceV2/services/WSCSISoap?wsdl","WSCSI","WSCSISoap");
IScoring instance = new ScoringCFA(WSCS);
assertEquals(true, instance.statusService());
I need to use SSL, So i change the url to:
https://localhost:8181/ServiceV2/services/WSCSISoap?wsdl
And add this in the VM Options:
-Djavax.net.ssl.trustStore="C:\cacerts.jks"
('Keytool -list -keystore "C:\cacerts.jks', when i run this command i see that the certificate that i need is there)
When i run the client get this error:
java.security.cert.CertificateException: No name matching localhost found.)

That's probably because the cert you're using is issued against a specific hostname (www.myhost.com). Try the solution in this article.
But be warned, the code sample is only intended for localhost testing, remove it once you move onto the integration/assembly testing on a proper server.

Sounds to me that disabling SSL hostname verification might work for you. Another example here.

Related

graphDB User/PW proxy settings lead to statuscode 407

I'm trying to run following SPARQL-query on my local graphDB-Instance (GraphDB Free 9.4.1 on Windows).
PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT * WHERE {
SERVICE <https://query.wikidata.org/sparql> {
?subj wdt:P31 wd:Q744913 ;
wdt:P625 ?coord ;
rdfs:label ?label
FILTER (lang(?label) = "en")
}
}
The query works without a problem on my personal computer.
But within my companies network, it doesn't, because we have a proxy.
I checked my proxy settings with a RDF4J-Java programm and they work perfectly fine.
[...]
System.setProperty("https.proxyHost", "<company_proxy>");
System.setProperty("https.proxyPort", "<company_proxy_port>");
System.setProperty("https.nonProxyHost", "localhost|127.0.0.1|<company_list>");
System.setProperty("https.proxyUser", "<user>");
System.setProperty("https.proxyPassword", "<password>");
[...]
I tried to set the same settings for GraphDB with different approaches
via the UI
via the C:\Users\XXXX\AppData\Local\GraphDB Free\runtime\conf\net configuration-file
via the C:\Users\XXXX\AppData\Roaming\GraphDB\conf\proxy.properties configuration-file
via the C:\Users\XXXX\AppData\Local\GraphDB Free\app\ configuration-file
All do something to the configuration, meaning I now see an error message and don't have a connection timeout anymore. Since I validated the settings with RDF4J I am guessing the problem is how I apply the configuration or there is a problem with parsing the configuration.
Edit:
I get an statuscode 407, Proxy Authentication Required.
I'm guessing, that graphDB doesn't accept the properties https.proxyUser and https.proxyPassword.
Did anybody had the same issue and has a solution? Or how could I debug this problem further?
ps. my password contains the '!' character. might this be the problem? I tried every escape mechanism i could think of (!, ^!, ^^!, all in "") but neither did work.
Edit 2.0:
The guys from ontotext found a bug and it was fixed with the release 9.5.0-TR14.
The proxy-configuration mentioned in this questions works now.
To closest possible scenario to simulate the issue with your proxy server was:
Download and install mitmproxy server
Trust the mitmproxy's certificate for all Java programs so GraphDB can use HTTPS connections to the proxy
# ~/.mitmproxy/mitmproxy-ca-cert.cer is the certificate shipped with the proxy
sudo keytool -importcert -file ~/.mitmproxy/mitmproxy-ca-cert.cer -alias mitmproxy -keystore $JAVA_HOME/jre/lib/security/cacerts
Start the proxy server with username and password
# The proxy will require username and password
mitmproxy --set proxyauth=testUser:testPassword
Start GraphDB and point it to the local mitmproxy server:
# Point the Apache HTTP Client to use the mitmproxy
./graphdb -Dhttps.proxyHost=localhost -Dhttps.proxyPort=8080 -Dhttps.proxyUser=testUser -Dhttps.proxyPassword=testPassword
At this point, I was able to reproduce the HTTP 407 error, where the HTTPS client of GraphDB fails to negotiate the authenticating process with the proxy server. The same process works fine for the HTTP protocol, so this is how I have reached a workaround, which overcomes this glitch by specifying both the https.proxyUser and its http.proxyUser equivalent. The example works fine with your query and the mitmproxy server:
# Setup not only HTTPS but also HTTP connection
/graphdb -Dhttps.proxyHost=localhost -Dhttps.proxyPort=8080 -Dhttps.proxyUser=testUser -Dhttps.proxyPassword=testPassword -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8080 -Dhttp.proxyUser=testUser -Dhttp.proxyPassword=testPassword
What you can try doing is setting up the 'graphdb.workbench.external-url' parameter to whatever URL/subpath your instance should reside at. This parameter is used for rewriting incoming requests and can help with API calls.

Is it possible to force SSLHandshake to always use the hostname, not IP for HttpsUrlConnection

So I have this situation: I try to download an image from somedomain.com using HTTPS. The domain is probably misconfigured, but unfortunately I can't change that. What exactly is happening:
When I browse to https://somedomain.com/animage.jpg I get a valid certificate issued for somedomain.com, which is perfect. But when I call the same site using it's IP address, say https://123.123.123.123 - I get a (also valid) certificate for *.hostingcompany.com - the certificate of the hosting company.
Now, I try to download the contents of the file using Java's HttpsUrlConnection, nothing special:
var urlConnection = new URL(imageUrl).openConnection();
((HttpURLConnection) urlConnection).getResponseCode();
(I want to first check the response code, but it's not important here.)
This code runs inside a Spring Boot App and is run on request. It works fine for the first request since booting the app. Each subsequent request fails with java.security.cert.CertificateException: No subject alternative DNS name matching somedomain.com found. It's because on each subsequent request the SSL Handshake is sent to the IP, not hostname, and get's the hosting company's certificate.
I was trying to find different settings for the SSL classes, but to no avail. I know there is a workaround where I could supply my own HostnameVerifier which could just return true, but that won't be secure, so I don't want to do that.
Did anyone encounter such problem? Maybe I'm searching in the wrong places? Maybe it's something with DNSes? I will appreciate any help.
Turns out it is a bug in Java 11.01. It is fixed since 11.02. After switching to 11.03. the behaviour I described above is gone. Each request gets a proper certificate.
Here are the details of the bug: https://bugs.openjdk.java.net/browse/JDK-8211806

How do I use a client certificate with Java 8.31

I have an SSL client certificate. It was working with my app up until one of the Java updates happened at some point in the recent past (maybe as far back as a year). It works with web browsers. It works with curl.
For example, I can do this and it is fine:
curl --cert example.pem https://example.net
Now I cannot get this cert to work with Java. I've gone as far as trying a very minimal app, like SSLPoke from https://gist.github.com/4ndrej/4547029
Putting the cert into the client certs from ControlPanel doesn't do it.
Importing the .pem into a keystore and then pointing at that keystore with -Djavax.net.ssl.trustStore or .keystore doesn't do it.
All I get out of Java is:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
So I can't figure out what is wrong - the way I'm invoking Java? The place I'm putting the certificate? The way I've imported the certificate?
The debug output using -Djava.security.debug=all does not show it using the trustStore/keyStore I specify. It doesn't even show anything about the URL I'm trying to reach.
I'm out of ideas.
Your server is likely using an outdated SSL protocol, that Java is no longer allowing, by default, for security reasons.
Try running Java with this option (e.g. needed for older SQL Server instances):
-Djsse.enableCBCProtection=false
If that doesn't work, maybe the server is using SSLv3, so see this SO question for How to enable SSL 3 in Java.
If any of those work, they are workarounds need to downgrade the SSL security, so you are strongly encouraged to upgrade the server instead, and remove these workarounds again.

How to send client certificate along with SOAP request in Jmeter

I have a certificate which i need to pass along with the SOAP Request in JMeter.
I have edited the system.properites file to add
javax.net.ssl.keyStore= path to keystore file
javax.net.ssl.keyStorePassword=password
I am still getting the error You need valid client certificate from DHW to access page.
Am I missing somethig here?
The same request is working well from SOAP_UI.
There is a lot that can be going wrong here.
Here is my guess though...
The server is most likely setup for mutual authentication. You can test this by running your java client with the following system property: -Djavax.net.debug=ssl
You should see the ssl handshake and see if the server is requesting a client certificate or not. The messaging will be VERY verbose and you will have to diligently look though the log output to see what is actually occurring.
Hopefully, in the output you will see a list of Certificate Authorities (CAs) that the server trusts. Your client's certificate MUST be signed by one of these CAs. If not, the client won't even attempt to send its client certificate.
If you have access to the server, you can create your own CA and then sign the clients certificate with that new CA and that will work. I actually just did that yesterday. :D
The issue is resolved. I was giving only single backspace instead of two backspaces as per java conventions. It works fine with this minor modification.

Use keystore file to run client for a SOAP WS

I was given a SOAP WS to work with.
They gave me the wsdl file from which I was able to create client stub (I've used wsdl2java utility within cxf).
With that wsdl I was also give a .keystore file and the thing is I do know know how to add it to my keytool (is this is even the right way of putting it?).
I've built a junit test that I run to test my client but I constantly get
HTTP transport error: 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
Where can I find an easy guide on what to do with this .keystore file?
Thanks
The error means that the server certificate could not be found in your truststore. Check the contents of the .keystore file to see whether it contains the server certificate (listed as trustedEntry in your truststore). If yes, set the following system properties (either using -D JVM parameter or System.setProperty()).
javax.net.ssl.trustStore=<<your .keystore>>
javax.net.ssl.trustStorePassword=<<keystore password>>
If these properties are not set, the default ones will be picked up from your the default location.[$JAVA_HOME/lib/security/jssecacerts, $JAVA_HOME/lib/security/cacerts]
To view the contents of keystore file, use
keytool -list -v -keystore file.keystore -storepass mypassword
To debug the ssl handshake process and view the certificates, set the VM parameter -Djavax.net.debug=all
If the web service requires 2 way SSL, the client needs to send its identity (picked up from your keystore). In this case, your .keystore will contain a privateKeyEntry which will be sent to the server during handshake process. To configure this, set the JVMM properties javax.net.ssl.keyStore and javax.net.ssl.keyStorePassword to point to your keystore.
The next works for me:
Application server configuration. Apache Tomcat/7.0.52. server.xml: set clientAuth="true" in the https connector.
Application server configuration. Apache Tomcat/7.0.52. tomcat-users.xml: crate a user with the DN of the user as it appears in your certificate (subject)
Web service JAX-WS web service eclipse tutorial. Thanks Arpit! Add it a security constraint in the deployment descriptor (web.xml)
Client. Generated with apache-cxf maven plugin.
Main class:
HelloWorldImplService helloWorldImplService = new HelloWorldImplService();
HelloWorld helloWorld = helloWorldImplService.getHelloWorldImplPort();
SayHelloWorld parameters = new SayHelloWorld();
parameters.setArg0("World");
SayHelloWorldResponse helloWorldResponse = helloWorld.sayHelloWorld(parameters);
System.out.println(helloWorldResponse.getReturn());
Client JVM options:
-Djavax.net.ssl.trustStore=/xxxx/cacerts.jks -Djavax.net.ssl.trustStorePassword=xxxx -Djavax.net.ssl.keyStore=/xxx/user.jks -Djavax.net.ssl.keyStorePassword=xxxx
You can take a look here: Java SOAP client with certificate authentication
An excellent blog to help you understand the keystores and certificates imports required for HTTPS SSL handshake:
http://ruchirawageesha.blogspot.in/2010/07/how-to-create-clientserver-keystores.html
Hope it helps you to setup ur client keystore correctly in order to call the web services.
Good Luck!

Categories

Resources