Использование HTTPS с REST в Java - PullRequest
32 голосов
/ 18 ноября 2009

У меня есть REST-сервер, созданный в Grizzly, который использует HTTPS и прекрасно работает с Firefox. Вот код:

//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();

Теперь я пытаюсь достичь этого на 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);
}

И получите:

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)

Из примеров, которые я нашел в Интернете, мне кажется, что мне нужно настроить Truststore, а затем установить какой-нибудь TrustManager. Это похоже на большой код и настройку для моего простого маленького проекта. Есть ли более простой способ сказать ... Я доверяю этому сертификату и указываю на файл .cert?

Ответы [ 4 ]

45 голосов
/ 18 ноября 2009

Когда вы говорите "есть более простой способ ... доверять этому сертификату", это именно то, что вы делаете, добавляя сертификат в ваше хранилище доверенных сертификатов Java. И это очень, очень легко сделать, и вам ничего не нужно делать в клиентском приложении, чтобы распознать или использовать хранилище доверия.

На вашем клиентском компьютере найдите, где находится ваш файл cacerts (это ваше хранилище доверенных сертификатов Java по умолчанию, которое по умолчанию расположено в /lib/security/certs/cacerts.

.

Затем введите следующее:

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

Это импортирует сертификат в ваше хранилище доверенных сертификатов, и после этого ваше клиентское приложение сможет без проблем подключаться к вашему HTTPS-серверу Grizzly.

Если вы не хотите импортировать сертификат в ваше хранилище доверенных сертификатов по умолчанию - то есть вы просто хотите, чтобы он был доступен для этого одного клиентского приложения, но не для чего-либо еще, что вы запускаете на JVM на этом компьютере - тогда вы можете создать новый магазин доверия только для вашего приложения. Вместо передачи keytool пути к существующему файлу cacerts по умолчанию, передайте keytool путь к новому файлу хранилища доверенных сертификатов:

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

Вам будет предложено установить и подтвердить новый пароль для файла хранилища доверенных сертификатов. Затем при запуске клиентского приложения запустите его со следующими параметрами:

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

Легко, сырный, правда.

11 голосов
/ 18 ноября 2009

Вот болезненный маршрут:

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

Должен любить эти шесть разных пойманных исключений :). Конечно, есть некоторый рефакторинг, чтобы немного упростить код. Но мне нравятся опции -D Дельфуэго на ВМ. Я хотел бы, чтобы было статическое свойство javax.net.ssl.trustStore, которое я мог просто установить. Всего две строки кода и готово. Кто-нибудь знает, где это будет?

Это может быть слишком много, чтобы спросить, но в идеале keytool не будет использоваться. Вместо этого доверенное хранилище будет динамически создаваться кодом, а сертификат добавляется во время выполнения.

Должен быть лучший ответ.

3 голосов
/ 23 ноября 2011

Следует иметь в виду, что эта ошибка не только из-за самозаверяющих сертификатов. Новые сертификаты Entrust CA дают сбой с той же ошибкой, и правильное решение - обновить сервер соответствующими корневыми сертификатами, чтобы не отключить эту важную функцию безопасности.

2 голосов
/ 28 июля 2011

Проверьте это: http://code.google.com/p/resting/. Я мог бы использовать отдых, чтобы потреблять HTTPS REST услуги.

...