I want to open a HTTPS connection in a Google App Engine app using the URLFetch service. To be able to verify the SSL certificate of the server my app is talking to, I am using my own keystore file. I want to read this file in a warmup request when my app is loaded i.e. before any HTTPS requests are performed. The keystore file is part of my WAR file.
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());
I cannot use this approach, however, because while HttpURLConnection is on the GAE's JRE whitelist, HttpsUrlConnection is not.
Is there another way to use a custom keystore in GAE? I did not find any information on this in the GAE docs. It looks like while Google's URLFetch service supports HTTPS, the keystore cannot be customized. Is this correct?
If this isn't possible, is the approach still valid in general? Or is there a different approach that does still allow me to verify the SSL certificate?
UPDATE
In 2009, App Engine developer Nick Johnson from Google said on https://groups.google.com/d/topic/google-appengine-python/C9RSDGeIraE/discussion:
The urlfetch API doesn't allow you to specify your own client certificates, so unfortunately what you want to achieve is not currently possible.
Is this still correct? If every HTTP(s) request in App Engine relies on URLFetch this would mean that custom certificates just cannot be used at all in GAE.
I was recently facing the same issue and using the HttpClient implementation packaged with appengine-api-stubs worked for me.
Maven Dependency:
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-api-stubs</artifactId>
<version>1.9.18</version>
</dependency>
Code:
// 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());
This does essentially the same thing as
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
But for one reason or another app engine doesn't block it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With