Home > Software design >  How connection with JIRA using RESTAPI with java?
How connection with JIRA using RESTAPI with java?

Time:05-13

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)

CodePudding user response:

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);
        }
    }

}
  • Related