Getting ssl.SSLHandshakeException when using REST client with header but works fine with PostMan
Asked Answered
A

2

6

I have an external REST resource with below details:

  1. The URL: abc.com/orders (the domain is with https)
  2. I need to pass UserID as an HTTP header with key "user" value is "abcd"
  3. This would return an JSON response

I am using below Java code for this:

try {

            Client client = Client.create();

            WebResource webResource = client.resource("abc.com/orders");

            ClientResponse response = webResource.header("user", "abcd").accept("application/json")
                    .get(ClientResponse.class);

            if (response.getStatus() != 200) {
                throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
            }

            String output = response.getEntity(String.class);

            System.out.println("Output from Server .... \n");
            System.out.println(output);

        } catch (Exception e) {

            e.printStackTrace();

        }

But I am getting below exception although it works fine with PostMan

com.sun.jersey.api.client.ClientHandlerException: 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
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:155)
    at com.sun.jersey.api.client.Client.handle(Client.java:652)
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:682)
    at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
    at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:509)

I tried to search a bit on it and found somewhere that I need to get certificate from that URL and add to jdk/lib/security folder. But I don't know how to proceed.

With openssl I get below output:

user>openssl s_client -connect  abc.com:443

CONNECTED(00000214)
7832:error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error:s23_clnt.c:802:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 308 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : 0000
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1531657560
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
Aliquant answered 15/7, 2018 at 11:53 Comment(6)
Is abc.com/orders a server that you have control over? I.e. can you check what is the cert setup on that server? Also what framework that webservice is written in (node-express, java etc)Hellenic
@Hellenic no I don't have any control. It's just a third party.Aliquant
ok can you post the output of openssl s_client -connect abc.com:443, particularly the certificate chain partHellenic
oh one more thing, in postman did you have to turn off SSL Certificate Verification (in Settings -> General)Hellenic
@Hellenic no I didn't have to turn off SSL Certificate VerificationAliquant
@Hellenic I've updated the openssl command outputAliquant
P
8

These are the instructions to make your program work. Btw, I am on windows, using google chrome.

You do need a certificate.

1) First, go to the url (doesn't matter if it's a website or a restful service), let's pick google.com. Right click on the page and click "inspect".

enter image description here

2) Go to the security tab.

enter image description here

3) Once, you're there, click "view certificate". enter image description here

A window will pop up, with site's certificate's details.

4) Go to the "certification path" tab. And double click on the certificate that you want from the hierarchy. enter image description here

A new window will pop up:

enter image description here

I chose the root certificate in this case called "Google trust services...", but you can choose a more specific one, like "Google Internet Authority G3". I think the more specific it is, the more security it provides (but I'm not sure).

5) Go to the "Details" tab and choose your certificate's name:

enter image description here

6) Click "Copy To File", then choose the name for it and where you want to save it. I saved mine on desktop and named it "test.cer".

Now you are done exporting the certificate. Next, you want to add it to jvm's truststore.

1) Look up which JRE your application is running on, for example I have only one JRE on my computer (excluding the one bundled with the JDK). It's located here:

enter image description here

The target file that stores certificates is cacerts:

enter image description here

2) Open cmd as administrator and do cd "C:\Program Files\Java\jre-10.0.1\lib\security" (path to cacerts in my case).

3) Issue the following command:

keytool -import -storepass changeit -noprompt -alias *alias* -keystore cacerts -trustcacerts -file *path_to_certificate*

Note that alias can be anything, regardless of what you called your file, as long as it doesn't clash with aliases of other certificates already in the truststore.

In my case I issue this:

enter image description here

4) You can now issue this command: keytool -list -keystore cacerts -alias *alias* to make sure your certificate was added. When you issue this command, it will ask you for your password. In step three, the command I gave your had this option: -storepass changeit, so your password will be changeit.

enter image description here

In my case everything is okay.

5) Now you can restart your application and it should work. Some people recommend restarting your computer, but I don't know if that's necessary.

Photography answered 15/7, 2018 at 13:5 Comment(6)
I appreciate your effort but it's not an website. It's just a RESTful webservice exposed. can't access it in this wayAliquant
@J.Doe why not? Paste the url into chrome and do what I said. It should work.Photography
please refer point 2. Header is mandatory. How do I pass header ?Aliquant
You pass the header in your application to get the response, you do not need to pass it while getting your certificate.Photography
It doesn't matter if it's a website or a restful service. Header info is needed for requests, not certificates. Please try what I said and tell me if you have any problems.Photography
it's really WOW..... Thank you so much... it worked.. I truly appreciate your effort :)Aliquant
P
5

MAN! No need any of above!!! Just pass RestAssured.useRelaxedHTTPSValidation(); before Rest Api code. DONE!`

Puri answered 5/4, 2020 at 2:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.