Загрузка хранилища пользовательских ключей в Java-приложение Google App Engine
Я хочу открыть HTTPS- соединение в приложении Google App Engine с помощью службы URLFetch. Чтобы иметь возможность проверить SSL-сертификат сервера, с которым разговаривает мое приложение, я использую свой собственный файл хранилища ключей. Я хочу прочитать этот файл в запросе на разогрев при загрузке моего приложения, т.е. до того, как будут выполнены любые запросы HTTPS. Файл хранилища ключей является частью моего файла WAR.
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(ClassLoader.getSystemResourceAsStream("myKeystoreFile"), "password".toCharArray());
trustManagerFactory.init(keystore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
Однако я не могу использовать этот подход, потому что, хотя HttpURLConnection находится в белом списке JRE GAE, HttpsUrlConnection нет.
Есть ли другой способ использовать пользовательское хранилище ключей в GAE? Я не нашел никакой информации об этом в документации GAE. Похоже, что хотя служба Google URLFetch поддерживает HTTPS, хранилище ключей не может быть настроено. Это правильно?
Если это невозможно, остается ли этот подход в целом действительным? Или есть другой подход, который все еще позволяет мне проверять сертификат SSL?
ОБНОВИТЬ
В 2009 году разработчик App Engine Ник Джонсон из Google сказал на https://groups.google.com/d/topic/google-appengine-python/C9RSDGeIraE/discussion:
API urlfetch не позволяет вам указывать свои собственные клиентские сертификаты, поэтому, к сожалению, то, чего вы хотите достичь, в настоящее время невозможно.
Это все еще правильно? Если каждый HTTP-запрос в App Engine полагается на URLFetch, это будет означать, что пользовательские сертификаты просто не могут использоваться вообще в GAE.
4 ответа
Вы должны зарегистрироваться в качестве доверенного тестера для поддержки исходящих сокетов. Под желаемыми функциями они используют SSL. Если бы поддерживали больше частей API JDK SSL, создать нечто подобное было бы просто.
Недавно я столкнулся с той же проблемой, и мне помогло использование реализации HttpClient в комплекте с appengine-api-stubs.
Зависимость Maven:
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-api-stubs</artifactId>
<version>1.9.18</version>
</dependency>
Код:
// create SSL Context which trusts your self-signed certificate
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(ClassLoader.getSystemResourceAsStream("myKeystoreFile"), "password".toCharArray());
trustManagerFactory.init(keystore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, null);
// register your trusting SSL context
Protocol.registerProtocol("https",
new Protocol("https", (ProtocolSocketFactory) new SocketFactoryWrapper(sslContext.getSocketFactory()), 443));
// make the https call
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://myendpoint.com");
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine());
Это по сути то же самое, что и
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
Но по той или иной причине движок приложения не блокирует его.
У меня была похожая проблема... Мне нужна была keystore.p12
вызвать иностранный веб-сервис, но у него не было возможности загрузить его из classpath. Единственный способ, которым я мог использовать это, был поместить это в, например, /WEB-INF/keystore.p12
и загрузить его оттуда.
ServletContext context = getContext();
URL resourceUrl = context.getResource("/WEB-INF/keystore.p12");
Я использую Appengine API 1.9.56 и то, что предложил Дима
Protocol.registerProtocol("https",
new Protocol("https", (ProtocolSocketFactory) new SocketFactoryWrapper(sslContext.getSocketFactory()), 443));
больше не работает Поэтому мне не нужно appengine-api-stubs
библиотека тоже.
Тем не мение, HttpsURLConnection.setDefaultSSLSocketFactory
просто отлично работает
Вот мое полное решение, которое решило мою проблему:
KeyStore keystore = KeyStore.getInstance("JKS");
InputStream in = getClass().getResourceAsStream("/mytruststore.jks");
keystore.load(in, "password".toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keystore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
к счастью HttpsURLConnection
больше не занесен в черный список, как это было во время вопроса.