Загрузка хранилища пользовательских ключей в 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 больше не занесен в черный список, как это было во время вопроса.

Другие вопросы по тегам