2009-11-18 58 views
29

Tôi có một máy chủ REST được tạo bằng Grizzly sử dụng HTTPS và hoạt động tuyệt vời với Firefox. Dưới đây là các mã:Sử dụng HTTPS với REST trong Java

//Build a new Servlet Adapter. 
ServletAdapter adapter=new ServletAdapter(); 
adapter.addInitParameter("com.sun.jersey.config.property.packages", "My.services"); 
adapter.addInitParameter(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS, SecurityFilter.class.getName()); 
adapter.setContextPath("/"); 
adapter.setServletInstance(new ServletContainer()); 

//Configure SSL (See instructions at the top of this file on how these files are generated.) 
SSLConfig ssl=new SSLConfig(); 
String keystoreFile=Main.class.getResource("resources/keystore_server.jks").toURI().getPath(); 
System.out.printf("Using keystore at: %s.",keystoreFile); 
ssl.setKeyStoreFile(keystoreFile); 
ssl.setKeyStorePass("asdfgh"); 

//Build the web server. 
GrizzlyWebServer webServer=new GrizzlyWebServer(getPort(9999),".",true); 

//Add the servlet. 
webServer.addGrizzlyAdapter(adapter, new String[]{"/"}); 

//Set SSL 
webServer.setSSLConfig(ssl); 

//Start it up. 
System.out.println(String.format("Jersey app started with WADL available at " 
    + "%sapplication.wadl\n", 
     "https://localhost:9999/")); 
webServer.start(); 

Bây giờ, tôi cố gắng để đạt được nó trong Java:

SSLContext ctx=null; 
try { 
    ctx = SSLContext.getInstance("SSL"); 
} catch (NoSuchAlgorithmException e1) { 
    e1.printStackTrace(); 
} 
ClientConfig config=new DefaultClientConfig(); 
config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(null,ctx)); 
WebResource service=Client.create(new DefaultClientConfig()).resource("https://localhost:9999/"); 

//Attempt to view the user's page. 
try{ 
    service 
     .path("user/"+username) 
     .get(String.class); 
} 

Và nhận được:

com.sun.jersey.api.client.ClientHandlerException: 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 com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:128) 
at com.sun.jersey.api.client.Client.handle(Client.java:453) 
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:557) 
at com.sun.jersey.api.client.WebResource.get(WebResource.java:179) 

Từ ví dụ mà tôi đã tìm thấy trên trang web, nó có vẻ như tôi sẽ cần phải thiết lập một Truststore sau đó thiết lập một số loại TrustManager. Điều này có vẻ như rất nhiều mã và thiết lập làm việc cho dự án nhỏ đơn giản của tôi. Có một cách dễ dàng hơn để chỉ nói .. Tôi tin tưởng cert này và trỏ đến một tập tin .cert?

Trả lời

42

Khi bạn nói "có cách nào dễ dàng hơn để ... tin tưởng chứng chỉ này" không, đó chính là điều bạn đang làm bằng cách thêm chứng chỉ vào kho lưu trữ tin cậy Java của bạn. Và điều này rất, rất dễ thực hiện và bạn không cần phải làm gì trong ứng dụng khách của mình để nhận được hoặc sử dụng kho tin cậy đó.

Trên máy tính của khách hàng của bạn, tìm nơi tập cacerts của bạn là (đó là cửa hàng tin cậy mặc định Java của bạn, và là, theo mặc định, tọa lạc tại < java-nhà >/lib/security/certs/cacerts.

Sau đó, , gõ như sau:

keytool -import -alias <Name for the cert> -file <the .cer file> -keystore <path to cacerts> 

Đó sẽ import cert vào cửa hàng tin cậy của bạn, và sau này, ứng dụng khách hàng của bạn sẽ có thể kết nối với máy chủ Grizzly HTTPS của bạn mà không vấn đề

Nếu bạn don'. t muốn impor t cert vào kho lưu trữ tin cậy mặc định của bạn - nghĩa là bạn chỉ muốn nó có sẵn cho ứng dụng khách này, nhưng không phải bất cứ thứ gì khác bạn chạy trên JVM trên máy đó - sau đó bạn có thể tạo một kho lưu trữ tin cậy mới ứng dụng của bạn. Thay vì đi qua keytool đường dẫn đến, file cacerts mặc định hiện có, vượt qua keytool đường dẫn đến tập tin lưu trữ tin tưởng mới của bạn:

keytool -import -alias <Name for the cert> -file <the .cer file> -keystore <path to new trust store> 

Bạn sẽ được yêu cầu để thiết lập và xác minh một mật khẩu mới cho các file lưu trữ tin cậy. Sau đó, khi bạn khởi động ứng dụng khách của mình, hãy bắt đầu ứng dụng với các thông số sau:

java -Djavax.net.ssl.trustStore=<path to new trust store> -Djavax.net.ssl.trustStorePassword=<trust store password> 

Dễ dàng cheesy, thực sự.

+0

Rất đẹp, nhưng ... Tôi có thể đặt trustStore và trustStorePassword trong mã thay vì đối số cho VM không? – User1

+3

Có - trước khi có bất kỳ cuộc gọi nào đến các phương thức yêu cầu SSL, hãy sử dụng System.setProperty ("javax.net.ssl.trustStore", ") và thực hiện tương tự cho javax.net.ssl. trustStorePassword. – delfuego

+1

Một phần buồn là tên tệp không chính xác cho một ngoại lệ rất mơ hồ: "java.security.InvalidAlgorithmParameterException: tham số trustAnchors phải không trống" – User1

10

Đây là con đường đau đớn:

SSLContext ctx = null; 
    try { 
     KeyStore trustStore; 
     trustStore = KeyStore.getInstance("JKS"); 
     trustStore.load(new FileInputStream("C:\\truststore_client"), 
       "asdfgh".toCharArray()); 
     TrustManagerFactory tmf = TrustManagerFactory 
       .getInstance("SunX509"); 
     tmf.init(trustStore); 
     ctx = SSLContext.getInstance("SSL"); 
     ctx.init(null, tmf.getTrustManagers(), null); 
    } catch (NoSuchAlgorithmException e1) { 
     e1.printStackTrace(); 
    } catch (KeyStoreException e) { 
     e.printStackTrace(); 
    } catch (CertificateException e) { 
     e.printStackTrace(); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } catch (KeyManagementException e) { 
     e.printStackTrace(); 
    } 
    ClientConfig config = new DefaultClientConfig(); 
    config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, 
      new HTTPSProperties(null, ctx)); 

    WebResource service = Client.create(config).resource(
      "https://localhost:9999/"); 
    service.addFilter(new HTTPBasicAuthFilter(username, password)); 

    // Attempt to view the user's page. 
    try { 
     service.path("user/" + username).get(String.class); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

Gotta love những sáu trường hợp ngoại lệ đánh bắt khác nhau :). Có chắc chắn một số refactoring để đơn giản hóa mã một chút. Nhưng, tôi thích các tùy chọn -D của delfuego trên máy ảo. Tôi muốn có một thuộc tính tĩnh javax.net.ssl.trustStore mà tôi có thể thiết lập. Chỉ cần hai dòng mã và hoàn thành. Có ai biết nó sẽ ở đâu không?

Điều này có thể là quá nhiều để hỏi, nhưng, lý tưởng keytool sẽ không được sử dụng. Thay vào đó, TrustedStore sẽ được tạo động bằng mã và cert được thêm vào khi chạy.

Phải có câu trả lời tốt hơn.

+0

Bỏ phiếu này vì tuyến đường đau đớn là những gì tôi đang tìm kiếm cho dự án (hơi phức tạp hơn) của tôi! :) –

+0

nơi chúng tôi nhận tệp này từ đâu? C: \\ truststore_client –

+1

Java 7 cho phép nhiều lần bắt ngoại lệ trong một khối xD –

3

Điều cần lưu ý là lỗi này không chỉ do các chứng chỉ tự ký. Các chứng chỉ Entrust CA mới không thành công với cùng một lỗi và điều đúng đắn cần làm là cập nhật máy chủ với các chứng chỉ gốc thích hợp, không tắt tính năng bảo mật quan trọng này.

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