2008-12-17 26 views
8

Sử dụng lớp Java URL, tôi có thể kết nối với máy chủ HTTPS bên ngoài (chẳng hạn như trang web sản xuất của chúng tôi), nhưng sử dụng URL cục bộ tôi nhận được ngoại lệ sau.Làm cách nào để sử dụng URL HTTPS cục bộ trong java?

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

Làm cách nào để có được đường dẫn chứng nhận hợp lệ?

CHỈNH SỬA: Tôi không sử dụng URL này để trực tiếp tạo kết nối, tôi đang chuyển URL đến số itextPDFReader, sau đó gặp sự cố kết nối.

Trả lời

12

Đây là giải pháp của tôi kết hợp một số ý tưởng trong chuỗi này và được ghép với nhau cùng với mã từ trên mạng. Tất cả tôi gọi hàm này và nó đặt Trình quản lý tin cậy mặc định và Trình xác minh tên máy chủ cho HttpsURLConnection. Điều này có thể là không mong muốn đối với một số bởi vì nó sẽ ảnh hưởng đến tất cả các HttpsURLConnections nhưng tôi chỉ viết một proxy đơn giản để nó làm việc cho tôi.

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

Cảm ơn CornPuff - đó là chính xác khá nhiều mã tôi đã kết thúc bằng văn bản (mặc dù tôi đã làm nó một thời gian trước đây bây giờ). – RodeoClown

0

Vấn đề mà nó phàn nàn là khi bạn tạo kết nối SSL, máy chủ phải xuất trình chứng chỉ hợp lệ cho ứng dụng khách. Bạn có thể viết một điểm cuối thích hợp trong Java (HTTPServerSocket sẽ làm điều đó tôi nghĩ) nhưng nó sẽ yêu cầu một số hacking về để thiết lập nó. Nó có thể dễ dàng hơn để thiết lập một máy chủ web cục bộ với bất cứ thứ gì xử lý SSL chính xác --- Apache, lighttp, bất kỳ thứ gì --- và tạo ra một cert tự ký bằng cách sử dụng các công cụ openssl.

Đã cập nhật

Đây là ví dụ từ Java Almanac. http://www.exampledepot.com/egs/javax.net.ssl/Server.html

Ổ cắm máy chủ SSL yêu cầu chứng chỉ mà nó sẽ gửi cho khách hàng để xác thực. Chứng chỉ phải được chứa trong kho khóa có vị trí phải được chỉ định rõ ràng (không có mặc định). Sau ví dụ này, chúng tôi mô tả cách tạo và chỉ định kho khóa cho ổ cắm máy chủ SSL để sử dụng.

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

Xác định keystore giấy chứng nhận sử dụng tài sản hệ thống javax.net.ssl.keyStore:

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

Tôi có máy chủ HTTPS đang hoạt động, tôi không thể kết nối với lớp URL java (cập nhật bài đăng chính để phản ánh điều này) – RodeoClown

3

Bạn có thể cần phải thiết lập một HostnameVerifier. Trước khi kết nối, bạn cần thêm nó vào đối tượng kết nối

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); 
conn.setHostnameVerifier(new HostnameVerifier() { 
    public boolean verify(String hostname, SSLSession session) { 
    // check hostname/session 
    return true; 
    } 
}); 
conn.connect(); 
// read/write... 

Chắc chắn có một số triển khai ngoài đó, nếu bạn cần. Bạn cũng có thể muốn xem dự án HttpClient.

+0

Tôi đã sử dụng điều này, cảm ơn! – RodeoClown

3

Một điều cần xem là TrustManager bạn đang sử dụng. Thông báo lỗi cho thấy chứng chỉ được trình bày bởi máy chủ không được ký bởi một gốc tin cậy. Vì bạn không có quyền kiểm soát trực tiếp ổ cắm SSL được tạo, tôi nghĩ rằng đặt cược tốt nhất của bạn là initialize của riêng bạn SSLContext với TrustManager đó là setup with the root CA của chuỗi chứng chỉ của máy chủ. Sau đó, đặt bối cảnh này là default.

Giả sử bạn đang sử dụng Java 6. API bị giới hạn trong Java 5. Bạn có thể nhận được mặc định SSLSocketFactory, nhưng không có cách tiêu chuẩn nào để đặt nó.

0

Nó cũng có thể giúp bạn thêm chứng chỉ mà máy chủ lưu trữ cục bộ đang sử dụng (tôi cho rằng đó là tự ký) vào số keystore, using the "keytool" utility của JVM. Điều này sẽ có tác dụng nói cho JVM "bạn có thể tin tưởng chứng chỉ này".

0

Tôi đã kết thúc chạy một phương thức tĩnh (chỉ trên dev) cài đặt TrustManager rất đáng tin cậy (chấp nhận mọi thứ), và cũng thêm một hostnameVerifier luôn trả về true (nhờ sblundy).

Các vấn đề liên quan