web-dev-qa-db-fra.com

SunCertPathBuilderException: impossible de trouver le chemin de certification valide de la cible demandée dans l'application CN1

Pouvez-vous m'aider, s'il vous plaît? J'ai une application Codename qui envoie une demande GET à un serveur cloud Tomcat 8 et attend du retour une réponse JSON. Il est important de noter qu'il s'agit d'un appel HTTPS.

Quand je lance la demande dans Postman cela fonctionne très bien:

https://www.mydomain.co.uk:8443/MyProject/v1/generate_token

La même adresse URL de mon navigateur fonctionne avec le nom "Sécurisé" et je peux voir les détails de mon certificat. J'ai acheté un certificat pour ma configuration SSL/TLS et semble fonctionner correctement dans les journaux au démarrage.

Dans le simulateur, l'erreur suivante apparaît au moment de la lecture de la réponse de l'appel d'URL - ce qui, je suppose, doit être crypté:

Exception: 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
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 Sun.security.ssl.Alerts.getSSLException(Alerts.Java:192)
    at Sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.Java:1959)
    at Sun.security.ssl.Handshaker.fatalSE(Handshaker.Java:302)
    at Sun.security.ssl.Handshaker.fatalSE(Handshaker.Java:296)
    at Sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.Java:1514)
    at Sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.Java:216)
    at Sun.security.ssl.Handshaker.processLoop(Handshaker.Java:1026)
    at Sun.security.ssl.Handshaker.process_record(Handshaker.Java:961)
    at Sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.Java:1072)
    at Sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.Java:1385)
    at Sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.Java:1413)
    at Sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.Java:1397)
    at Sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.Java:559)
    at Sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.Java:185)
    at Sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.Java:1564)
    at Sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.Java:1492)
    at Java.net.HttpURLConnection.getResponseCode(HttpURLConnection.Java:480)
    at Sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.Java:347)
    at com.codename1.impl.javase.JavaSEPort.getResponseCode(JavaSEPort.Java:7591)
    at com.codename1.io.ConnectionRequest.performOperation(ConnectionRequest.Java:702)
    at com.codename1.io.NetworkManager$NetworkThread.run(NetworkManager.Java:282)
    at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.Java:176)

Pourquoi l'application devrait-elle être différente de Postman effectuant l'appel (la fenêtre du Moniteur réseau confirme le même appel URL)?

Aucun des journaux n'est mis à jour après mon appel, donc rien à vérifier à cet endroit. Je n'ai apporté aucune modification à mon application (qui fonctionnait) depuis le passage de http à https.

Voici le code CN1 effectuant l'appel:

public String fetchTokenIntoStorage(String userName, String password) {
        ConnectionRequest r = new ConnectionRequest();
        r.setUrl(Constants.URL_Host_PORT + "/MyProject" + Constants.LIVE_OR_TEST
                + "/v1/generate_token");
        r.addRequestHeader("Content-Type", "application/json");
        r.addRequestHeader("userName", userName);
        r.addRequestHeader("password", password);
        r.setHttpMethod("GET");
        r.setFailSilently(false);
        r.setPost(false);
        // show spinning dialog while connecting
        InfiniteProgress prog = new InfiniteProgress();
        Dialog dlg = prog.showInifiniteBlocking();
        r.setDisposeOnCompletion(dlg);
        NetworkManager.getInstance().setTimeout(10000);
        // NetworkManager.getInstance().addErrorListener(new ActionListener() {
        //
        // @Override
        // public void actionPerformed(ActionEvent evt) {
        // MessageBox.showDialogMessage("Unable to connect to server. Please
        // retry later.");
        // }
        // });
        // NetworkManager.getInstance().updateThreadCount(2);
        NetworkManager.getInstance().addToQueueAndWait(r);

        if (r.getResponseData() != null) {
            JSONParser parser = new JSONParser();
            Map<String, Object> json = null;
            try {
                json = parser.parseJSON(new InputStreamReader(new ByteArrayInputStream(r.getResponseData())));
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if (json.get("error") != null) {
                return String.valueOf(json.get("error"));
            }
            JwtRecord record = new JwtRecord();
            record.userId = Integer.parseInt(String.valueOf(json.get("userId")));
            record.jsonWebToken = (String) json.get("jwt");
            record.theme = "LIGHT";
            Storage.getInstance().writeObject("MyToken", record);
            return "";
        }
        if (!r.getResponseErrorMessage().equalsIgnoreCase("")) {
            return r.getResponseErrorMessage();
        } else {
            return "Unable to connect to server. Please check connection.";
        }
    }

En parcourant le code, il semble y avoir une erreur juste après

NetworkManager.getInstance().addToQueueAndWait(r);

Les fonctions r.getResponseData () et r.getResponseErrorMessage () sont nulles.

Merci beaucoup

1
Think.Smart

Cela fonctionne maintenant. 

  1. (Sur le cloud Tomcat), je me suis assuré que le certificat racine et le certificat intermédiaire étaient dans mon magasin de clés (conformément aux liens que j'avais précédemment inclus). J'ai inclus mon fichier .ca dans le magasin de clés pour faire bonne mesure.

  2. (Sur le cloud Tomcat) Et j’ai remarqué que j’utilisais une ancienne version de la configuration d’Apache (leçon tirée de l’exploitation des anciens messages du forum). Il fallait que SSLCACertificateFile pointe vers mon fichier .ca-bundle, plutôt que d'utiliser SSCertificateChainFile, dans mon fichier Apache .conf.

  3. Il reste une erreur sur mon simulateur mais fonctionne sur mon iphone, ce qui indique (comme Shai le dit) des JDK différents, je m'attendais, donc j'ai mis mon ordinateur portable à niveau avec le JDK 1.8.171 supérieur. Cela ne faisait pas en soi une différence, mais était probablement nécessaire.

  4. En fouillant, j'ai réalisé que les simulateurs de mon ordinateur portable avaient également besoin de ce qui précède. J'ai donc fini par exécuter les instructions ci-dessous, dans la commande Invite en tant qu'administrateur, et maintenant mon simulateur fonctionne.

    cd% Java_home%\jre\lib\security

    chemin =% Java_home\bin

    keytool -import -alias comodo -keystore cacerts -fichier C:\chemin\ComodoRoot.cer

    keytool -import -alias comodo_intermediate -keystore cacerts -file C:\chemin\ComodoInter.cer

    keytool -import -alias acheté_cert -keystore cacerts -fichier C:\path\my_purchased_cert.crt

2
Think.Smart

Cela se produit si le pouvoir de signature n'est pas reconnu par le JDK sous-jacent. En supposant que vous ayez acheté votre certificat auprès d’une source valide, il est possible qu’il utilise une racine relativement nouvelle, ce qui signifie que vous devez utiliser la dernière version de JDK 8. 

Par exemple. letsencrypt n’a été ajouté que dans JDK 8 update 101. 

3
Shai Almog