Использование HTTPS с REST в Java
У меня есть сервер 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 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 файл?
Ответы
Ответ 1
Когда вы говорите "есть ли более простой способ... доверять этому сертификату", это именно то, что вы делаете, добавляя сертификат в хранилище доверия Java. И это очень, очень легко сделать, и вам нечего делать в своем клиентском приложении, чтобы получить это хранилище доверия или его использование.
На клиентской машине найдите, где находится ваш файл cacerts (это хранилище доверия Java по умолчанию и по умолчанию находится в каталоге < java-home > /lib/security/certs/cacerts.
Затем введите следующее:
keytool -import -alias <Name for the cert> -file <the .cer file> -keystore <path to cacerts>
Это импортирует сертификат в ваш магазин доверия, и после этого ваше клиентское приложение сможет подключиться к вашему серверу Grizzly HTTPS без проблем.
Если вы не хотите импортировать сертификат в хранилище доверия по умолчанию - то есть вы просто хотите, чтобы он был доступен для этого клиентского приложения, но не для чего-либо другого, который вы запускаете на своей 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>
Легкий дрянной, действительно.
Ответ 2
Вот мучительный маршрут:
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 page.
try {
service.path("user/" + username).get(String.class);
} catch (Exception e) {
e.printStackTrace();
}
Должен любить эти шесть разных пойманных исключений:). Есть, конечно, некоторые рефакторинги, чтобы немного упростить код. Но мне нравятся delfuego -D опции на виртуальной машине. Мне жаль, что не было статического свойства javax.net.ssl.trustStore, которое я мог бы установить. Всего две строки кода и сделаны. Кто-нибудь знает, где это будет?
Это может быть слишком много, чтобы спросить, но, в идеале, keytool не будет использоваться. Вместо этого, trustedStore будет создаваться динамически с помощью кода, а сертификат добавляется во время выполнения.
Должен быть лучший ответ.
Ответ 3
Что-то, о чем следует помнить, заключается в том, что эта ошибка связана не только с самоподписанными сертификатами. Новые сертификаты Entrust CA терпят неудачу с той же ошибкой, и правильная вещь - обновить сервер соответствующими корневыми сертификатами, а не отключать эту важную функцию безопасности.
Ответ 4
Проверьте это: http://code.google.com/p/resting/. Я мог бы использовать отдых для потребления
Услуги HTTPS REST.