1

I am working on Java dropwizard backend applicaton. I need to call an external API (https://example.com) from my Java backend API. I am successfully able to call the external API from my local machine: http://localhost:8080/

But when I have deployed my application on AWS server https://deployed.application.example

I am getting below error from deployed app when calling external API from there. Below are the error logs.

! java.io.EOFException: SSL peer shut down incorrectly
! at java.base/sun.security.ssl.SSLSocketInputRecord.read(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketInputRecord.readHeader(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketInputRecord.decode(Unknown Source)
! at java.base/sun.security.ssl.SSLTransport.decode(Unknown Source)
! ... 95 common frames omitted
! Causing: javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
! at java.base/sun.security.ssl.SSLSocketImpl.handleEOF(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.decode(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
! at java.base/sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
! at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
! at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
! at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
! at java.base/java.net.HttpURLConnection.getResponseCode(Unknown Source)
! at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
! at org.glassfish.jersey.client.internal.HttpUrlConnector.handleException(HttpUrlConnector.java:549)
! at org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:375)
! at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:267)
! ... 82 common frames omitted
! Causing: javax.ws.rs.ProcessingException: javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
! at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:269)
! at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:297)
! at org.glassfish.jersey.client.JerseyInvocation.lambda$invoke$0(JerseyInvocation.java:662)
! at org.glassfish.jersey.client.JerseyInvocation.call(JerseyInvocation.java:697)

Below is the code snippet for calling the external API. I tried disabling the hostname verification but this is also not working.

ClientBuilder clientBuilder = ClientBuilder.newBuilder();
clientBuilder.hostnameVerifier((hostname, session) -> true); // Disable hostname verification
SSLContext sslContext;
try {
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, null, null); // Use null parameters to disable SSL verification
} catch (KeyManagementException | NoSuchAlgorithmException e) {
    throw new RuntimeException(e);
}
clientBuilder.sslContext(sslContext);
Client client = clientBuilder.build();

// Prepare the API request
String apiUrl = API_URL + "/auth";
String httpMethod = "POST";
String requestBody = "{ \"username\": \”username\”,  \"password\": \”password\” }";
MediaType requestMediaType = MediaType.APPLICATION_JSON_TYPE;
MediaType responseMediaType = MediaType.APPLICATION_JSON_TYPE;

// Build the API request
javax.ws.rs.client.Invocation.Builder requestBuilder = client.target(apiUrl)
        .request(responseMediaType)
        .header("Accept", "application/json")
        .header("Content-Type", "application/json");// Add custom headers

// Set the HTTP method and request payload (if applicable)
Response response;
if ("POST".equalsIgnoreCase(httpMethod) || "PUT".equalsIgnoreCase(httpMethod)) {
    response = requestBuilder.method(httpMethod, Entity.entity(requestBody, requestMediaType));
} else {
    response = requestBuilder.method(httpMethod);
}

// Handle the API response
int statusCode = response.getStatus();
String responseBody = response.readEntity(String.class);

// Clean up the resources
response.close();
client.close();

// Process the API response
if (statusCode == Response.Status.OK.getStatusCode()) {
    // Success! Handle the successful response
} else {
    // Handle the error response
    System.err.println("API call failed with status code: " + statusCode);
    System.err.println("Response: " + responseBody);
}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Jyoti
  • 2,065
  • 3
  • 25
  • 28

2 Answers2

0

I believe SSL validation disabling is not a proper way in case of a real web application using https protocol. So you have to add the target's certificate to AWS's JDK cacerts to establish a proper connection.

Maksym Kosenko
  • 515
  • 7
  • 12
  • Thanks for the response. I will ask the External API team to share the certificate and try to add in my AWS' JDK. Meanwhile, Is there any other way to fix it? – Jyoti Jun 19 '23 at 14:21
  • I would try to [download](https://stackoverflow.com/questions/25940396/how-to-export-certificate-from-chrome-on-a-mac) their certificate in the browser. – Maksym Kosenko Jun 19 '23 at 14:42
0

I have figured out the issue. Actually, the AWS server on which I deployed was blocked for calling external URL. Our network team resolved the issue.

Thanks, Jyoti

Jyoti
  • 2,065
  • 3
  • 25
  • 28