2008-12-17 14 views
8

Używając klasy Java URL, mogę połączyć się z zewnętrznym serwerem HTTPS (takim jak nasza strona produkcyjna), ale używając lokalnego adresu URL otrzymuję następujący wyjątek.Jak używać lokalnego adresu URL HTTPS w java?

"SunCertPathBuilderException: unable to find valid certification path to requested target". 

Jak uzyskać prawidłową ścieżkę certyfikacji?

EDYCJA: Nie używam tego adresu URL do bezpośredniego utworzenia połączenia. Podaję adres URL do itextPDFReader, który ma wówczas problem z połączeniem.

Odpowiedz

12

Oto moje rozwiązanie, które zawiera niektóre z pomysłów w tym wątku i wycenione wraz z kodem z sieci. Wszystko, co nazywam tą funkcją, ustawia domyślny Trust Manager i HostName Verifier dla HttpsURLConnection. Może to być niepożądane dla niektórych, ponieważ wpłynie to na wszystkie połączenia HTTP, ale ja po prostu piszę prosty serwer proxy, więc zadziałało to dla mnie.

private void setTrustAllCerts() throws Exception 
{ 
    TrustManager[] trustAllCerts = new TrustManager[]{ 
     new X509TrustManager() { 
      public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
       return null; 
      } 
      public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { } 
      public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { } 
     } 
    }; 

    // Install the all-trusting trust manager 
    try { 
     SSLContext sc = SSLContext.getInstance("SSL"); 
     sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
     HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 
     HttpsURLConnection.setDefaultHostnameVerifier( 
      new HostnameVerifier() { 
       public boolean verify(String urlHostName, SSLSession session) { 
        return true; 
       } 
      }); 
    } 
    catch (Exception e) { 
     //We can not recover from this exception. 
     e.printStackTrace(); 
    } 
} 
+0

Dzięki CornPuff - to jest dokładnie ten sam kod, który napisałem (chociaż zrobiłem to już jakiś czas temu). – RodeoClown

0

Problem, na który narzeka, polega na tym, że podczas tworzenia połączenia SSL serwer musi przedstawić klientowi poprawny certyfikat. Możesz napisać odpowiedni punkt końcowy w Javie (HTTPServerSocket zrobi to, jak sądzę), ale wymagałoby to trochę hakowania, aby go skonfigurować. Prawdopodobnie łatwiej jest skonfigurować lokalny serwer sieciowy z wszystkim, co poprawnie obsługuje SSL --- Apache, lighttp, cokolwiek --- i stworzyć samopodpisany certyfikat za pomocą narzędzi openssl.

Zaktualizowany

Oto przykład z Almanachu Java. http://www.exampledepot.com/egs/javax.net.ssl/Server.html

Gniazdo serwera SSL wymaga certyfikatów, które wyśle ​​do klientów w celu uwierzytelnienia. Certyfikaty muszą znajdować się w magazynie kluczy, którego lokalizacja musi być jawnie określona (nie ma wartości domyślnej). Poniższy przykład opisuje sposób tworzenia i określania magazynu kluczy dla gniazda SSL serwera.

try { 
    int port = 443; 
    ServerSocketFactory ssocketFactory = SSLServerSocketFactory.getDefault(); 
    ServerSocket ssocket = ssocketFactory.createServerSocket(port); 

    // Listen for connections 
    Socket socket = ssocket.accept(); 

    // Create streams to securely send and receive data to the client 
    InputStream in = socket.getInputStream(); 
    OutputStream out = socket.getOutputStream(); 

    // Read from in and write to out... 

    // Close the socket 
    in.close(); 
    out.close(); 
} catch(IOException e) { 
} 

Określ kluczy certyfikatów wykorzystujących właściwości systemu javax.net.ssl.keyStore:

> java -Djavax.net.ssl.keyStore=mySrvKeystore -Djavax.net.ssl.keyStorePassword=123456 MyServer 
+0

mam pracę HTTPS serwer działa, po prostu nie może się z nim połączyć z klasy URL Java (aktualizowanego Poczta Główna w celu odzwierciedlenia tego) – RodeoClown

3

prawdopodobnie trzeba skonfigurować HostnameVerifier. Przed połączeniem należy dodać go do obiektu połączenia. W tym miejscu są pewne implementacje, jeśli ich potrzebujesz. Możesz również spojrzeć na projekt HttpClient.

+0

Użyłem tego, dzięki! – RodeoClown

3

Kolejną rzeczą, na którą trzeba zwrócić uwagę, jest używany TrustManager. Komunikat o błędzie sugeruje, że certyfikat prezentowany przez serwer nie jest podpisany przez zaufany root. Ponieważ nie masz bezpośredniej kontroli nad utworzonym gniazdem SSL, myślę, że najlepiej jest uzyskać initialize swój własny SSLContext z TrustManager, który był setup with the root CA łańcucha certyfikatów serwera. Następnie ustaw ten kontekst jako default.

Zakłada się, że używasz Java 6. Interfejs API jest bardziej ograniczony w Javie 5. Możesz uzyskać domyślną wartość SSLSocketFactory, ale nie ma standardowego sposobu jej ustawienia.

0

Może również pomóc w dodaniu certyfikatu, który jest używany przez serwer localhost (zakładam, że jest on samopodpisany) do JVM keystore, using the "keytool" utility. Powinno to spowodować poinformowanie JVM "możesz zaufać temu certyfikatowi".

0

Skończyło się na uruchomieniu statycznej metody (tylko na dev), która instaluje bardzo zaufany TrustManager (akceptuje wszystko), a także dodaje nazwę hosta, który zawsze zwraca wartość true (dzięki sblundy).

Powiązane problemy