Skip to content
Advertisement

How connection with JIRA using RESTAPI with java?

My task is to establish a connection to JIRA in java using RESTAPI. I’m facing an error with the SSL security certificate. I have tried many times and looked on google, but I didn’t find any solution to my problem. Can anyone help me to fix this error?

APOD.java

package com.jiraconnection;
import com.fasterxml.jackson.annotation.JsonProperty;

public class APOD {
    public final String expand;
    public final String id;
    public final String key;
    public final String self;

    public APOD(@JsonProperty("expand") String expand,
        @JsonProperty("id") String id,
        @JsonProperty("key") String key,
        @JsonProperty("self") String self) {
        this.expand = expand;
        this.id = id;
        this.key = key;
        this.self = self;

    }
}

JavaHttpURLConnectionDemo.java

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class JavaHttpURLConnectionDemo {

   public static void main(String[] args) throws IOException {

    // Create a neat value object to hold the URL
    URL url = new URL("https://jira.atlassian.com/rest/api/latest/issue/JRA-9");

    // Open a connection(?) on the URL(?) and cast the response(??)
    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();

    // Now it's "open", we can set the request method, headers etc.
    connection.setRequestProperty("accept", "application/json");

    // This line makes the request
    InputStream responseStream = connection.getInputStream();

    // Manually converting the response body InputStream to APOD using Jackson
    ObjectMapper mapper = new ObjectMapper();
    APOD apod = mapper.readValue(responseStream, APOD.class);

    // Finally we have the response
    System.out.println(apod.expand);

   }

}

Error

    Exception in thread "main" javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:324)
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:267)
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:262)
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1340)
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1215)
        at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1158)

Advertisement

Answer

HttpsURLConnection is using by default the JDK trusted certificates to validate the server certificate whether it is known and trusted. If it is present over there it won’t throw a SSLHandshakeException

Jira has currently the following certificate chain:

Jira server certificate

You can easily verify whether your HttpsURLConnection has the trusted certificate by adding a breakpoint after initializing the HttpsURLConnection See below for an example:

debug information

So my assumption is that in your case the certificate is not present in the JDK truststore. What you can do is extract the Jira certificate, just like shown here: Using openssl to get the certificate from a server afterwords either import it into cacert file here: $JAVA_HOME/lib/security/cacerts. But I think it will be better to provide a custom ssl configuration to your HttpsUrlConnection as it would be more maintainable in my opinion. But either options will work.

So the following code snippet is for option 2 when using custom trustore:

Option 2

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.util.Objects;
import java.util.stream.Collectors;

public class App {

    public static void main(String[] args) throws Exception {
        Path trustStorePath = Paths.get("/path/to/your/truststore.jks");
        char[] trustStorePassword = "my-password".toCharArray();

        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        try(InputStream inputStream = Objects.requireNonNull(Files.newInputStream(trustStorePath))) {
            trustStore.load(inputStream, trustStorePassword);
        }

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(trustStore);

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
        SSLSocketFactory socketFactory = sslContext.getSocketFactory();

        URL url = new URL("https://jira.atlassian.com/rest/api/latest/issue/JRA-9");
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        connection.setSSLSocketFactory(socketFactory);
        connection.setRequestProperty("accept", "application/json");

        try(InputStream inputStream = connection.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {

            String responseBody = bufferedReader.lines().collect(Collectors.joining(System.lineSeparator()));
            System.out.println(responseBody);
        }

    }

}

Or you can do everything inline without the custom truststore from your filesystem as shown below. In this way you have the the root ca as pem, which is DigiCert High Assurance EV ROOT CA and load it programatically into your in memory truststore.

Option 3

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Arrays;
import java.util.Base64;
import java.util.UUID;
import java.util.stream.Collectors;

public class App {

    public static void main(String[] args) throws Exception {
        String atlassian = ""
                + "MIIFdzCCBP6gAwIBAgIQAgzZlKL4HKlpT4RkDXUi8TAKBggqhkjOPQQDAzBWMQsw"
                + "CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTAwLgYDVQQDEydEaWdp"
                + "Q2VydCBUTFMgSHlicmlkIEVDQyBTSEEzODQgMjAyMCBDQTEwHhcNMjIwNTEwMDAw"
                + "MDAwWhcNMjMwNjEwMjM1OTU5WjBuMQswCQYDVQQGEwJBVTEYMBYGA1UECBMPTmV3"
                + "IFNvdXRoIFdhbGVzMQ8wDQYDVQQHEwZTeWRuZXkxGjAYBgNVBAoTEUF0bGFzc2lh"
                + "biBQdHkgTHRkMRgwFgYDVQQDDA8qLmF0bGFzc2lhbi5jb20wWTATBgcqhkjOPQIB"
                + "BggqhkjOPQMBBwNCAAR7p4KtlAjEKMIH66rdbCXtkR5nO20hqZco8B/L+EuJ9mqJ"
                + "PT4dmaDR8OZWzlLXfqiKKhtxuPckC5dtwns4kXyAo4IDlDCCA5AwHwYDVR0jBBgw"
                + "FoAUCrwIKReMpTlteg7OM8cus+37w3owHQYDVR0OBBYEFMw8XjgJmgk4VGCBWOyG"
                + "Lr/FMrRZMCkGA1UdEQQiMCCCDyouYXRsYXNzaWFuLmNvbYINYXRsYXNzaWFuLmNv"
                + "bTAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC"
                + "MIGbBgNVHR8EgZMwgZAwRqBEoEKGQGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E"
                + "aWdpQ2VydFRMU0h5YnJpZEVDQ1NIQTM4NDIwMjBDQTEtMS5jcmwwRqBEoEKGQGh0"
                + "dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRMU0h5YnJpZEVDQ1NIQTM4"
                + "NDIwMjBDQTEtMS5jcmwwPgYDVR0gBDcwNTAzBgZngQwBAgIwKTAnBggrBgEFBQcC"
                + "ARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGFBggrBgEFBQcBAQR5MHcw"
                + "JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBPBggrBgEFBQcw"
                + "AoZDaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VExTSHlicmlk"
                + "RUNDU0hBMzg0MjAyMENBMS0xLmNydDAJBgNVHRMEAjAAMIIBgQYKKwYBBAHWeQIE"
                + "AgSCAXEEggFtAWsAdwCt9776fP8QyIudPZwePhhqtGcpXc+xDCTKhYY069yCigAA"
                + "AYCt4OEbAAAEAwBIMEYCIQC37AW4L7CCrKn0+kTydWf3zn6tdkFOg/ZI3mUU4/P3"
                + "CwIhAOnIlT0eX2nzpr6+d3GReTVlVf5+coiyYsSOJWOANM2ZAHcANc8ZG7+xbFe/"
                + "D61MbULLu7YnICZR6j/hKu+oA8M71kwAAAGAreDg7wAABAMASDBGAiEAj67xO2t2"
                + "OVtwSjLdsD8RknexjRqu+Ifwp5wO/2p8a84CIQDw9OKwzRnQ4cxYPKPrIYGm5hbH"
                + "KfVwcBMmo0u0XQ2YlQB3ALNzdwfhhFD4Y4bWBancEQlKeS2xZwwLh9zwAw55NqWa"
                + "AAABgK3g4SEAAAQDAEgwRgIhAP/l3SLBl5/9RHQvd5GjApgGAne4J/XnA68l/vQp"
                + "x7jHAiEAxWnEzde1lf4a1kMuFUyc6fBUE88GVb+zC9rjv4KCDcQwCgYIKoZIzj0E"
                + "AwMDZwAwZAIwFcy1X+o/HkXrM8rFdcjBGCieA0oBeRSSifale32U36xquKPBtSvm"
                + "2g/HAZh2N3DDAjBM4zmAiD0WTA0o3Fnh03mIwP/98RqXvjiDUL/bzovejseo8eRp"
                + "FDjNl90IcJuAoGc=";

        String digicertCa = ""
                + "MIIEFzCCAv+gAwIBAgIQB/LzXIeod6967+lHmTUlvTANBgkqhkiG9w0BAQwFADBh"
                + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3"
                + "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD"
                + "QTAeFw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaMFYxCzAJBgNVBAYTAlVT"
                + "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMDAuBgNVBAMTJ0RpZ2lDZXJ0IFRMUyBI"
                + "eWJyaWQgRUNDIFNIQTM4NCAyMDIwIENBMTB2MBAGByqGSM49AgEGBSuBBAAiA2IA"
                + "BMEbxppbmNmkKaDp1AS12+umsmxVwP/tmMZJLwYnUcu/cMEFesOxnYeJuq20ExfJ"
                + "qLSDyLiQ0cx0NTY8g3KwtdD3ImnI8YDEe0CPz2iHJlw5ifFNkU3aiYvkA8ND5b8v"
                + "c6OCAYIwggF+MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFAq8CCkXjKU5"
                + "bXoOzjPHLrPt+8N6MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA4G"
                + "A1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYI"
                + "KwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j"
                + "b20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp"
                + "Q2VydEdsb2JhbFJvb3RDQS5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2Ny"
                + "bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDA9BgNVHSAE"
                + "NjA0MAsGCWCGSAGG/WwCATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgG"
                + "BmeBDAECAzANBgkqhkiG9w0BAQwFAAOCAQEAR1mBf9QbH7Bx9phdGLqYR5iwfnYr"
                + "6v8ai6wms0KNMeZK6BnQ79oU59cUkqGS8qcuLa/7Hfb7U7CKP/zYFgrpsC62pQsY"
                + "kDUmotr2qLcy/JUjS8ZFucTP5Hzu5sn4kL1y45nDHQsFfGqXbbKrAjbYwrwsAZI/"
                + "BKOLdRHHuSm8EdCGupK8JvllyDfNJvaGEwwEqonleLHBTnm8dqMLUeTF0J5q/hos"
                + "Vq4GNiejcxwIfZMy0MJEGdqN9A57HSgDKwmKdsp33Id6rHtSJlWncg+d0ohP/rEh"
                + "xRqhqjn1VtvChMQ1H3Dau0bwhr9kAMQ+959GG50jBbl9s08PqUU643QwmA==";

        String digicertRootCa = ""
                + "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh"
                + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3"
                + "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD"
                + "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT"
                + "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j"
                + "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG"
                + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB"
                + "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97"
                + "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt"
                + "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P"
                + "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4"
                + "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO"
                + "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR"
                + "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw"
                + "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr"
                + "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg"
                + "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF"
                + "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls"
                + "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk"
                + "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=";

        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null);

        for (String certificateContent : Arrays.asList(atlassian, digicertCa, digicertRootCa)) {
            byte[] decodedCertificate = Base64.getDecoder().decode(certificateContent);

            try(ByteArrayInputStream certificateAsInputStream = new ByteArrayInputStream(decodedCertificate);
                BufferedInputStream bufferedCertificateStream = new BufferedInputStream(certificateAsInputStream)) {

                CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                Certificate certificate = certificateFactory.generateCertificate(bufferedCertificateStream);
                trustStore.setCertificateEntry(UUID.randomUUID().toString(), certificate);
            }
        }

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(trustStore);

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
        SSLSocketFactory socketFactory = sslContext.getSocketFactory();

        URL url = new URL("https://jira.atlassian.com/rest/api/latest/issue/JRA-9");
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        connection.setSSLSocketFactory(socketFactory);
        connection.setRequestProperty("accept", "application/json");

        try(InputStream inputStream = connection.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {

            String responseBody = bufferedReader.lines().collect(Collectors.joining(System.lineSeparator()));
            System.out.println(responseBody);
        }
    }

}

Last resort would be disable the certificate validation, but I would not recommend that. Below is an example for that:

Option 4

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.stream.Collectors;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedTrustManager;

public class App {

    public static void main(String[] args) throws Exception {
        X509ExtendedTrustManager unsafeTrustManager = new X509ExtendedTrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) {}

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) {}

            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) {}

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) {}

            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {}

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {}

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[]{ unsafeTrustManager }, null);
        SSLSocketFactory socketFactory = sslContext.getSocketFactory();

        URL url = new URL("https://jira.atlassian.com/rest/api/latest/issue/JRA-9");
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        connection.setSSLSocketFactory(socketFactory);
        connection.setRequestProperty("accept", "application/json");

        try(InputStream inputStream = connection.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {

            String responseBody = bufferedReader.lines().collect(Collectors.joining(System.lineSeparator()));
            System.out.println(responseBody);
        }
    }

}
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement