15

We need to implement two-way SSL on Google App Engine, where we send out web service requests using JAX-WS to a server requring 2-way SSL authentication.

How can we set up 2-way SSL for our outgoing web service requests?

We know that javax.net.ssl* is forbidden in the App Engine environment.

Here's an example of our code:

@WebService(name="ListenerSoap", targetNamespace = "http://example.com/Listener.Wsdl")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface ListenerSoap {

    @WebMethod(operationName = "Ping", action="http://example.com/Listener.Wsdl#Ping")
    public void ping();
}

@WebServiceClient(name="Listener", targetNamespace="http://example.com/Listener.Wsdl", wsdlLocation = "https://example.com/Listener.asmx?WSDL")
public class Listener extends Service
{
  public ListenerSoap getListenerSoap() {
   return super.getPort(new QName("http://example.com/Listener.Wsdl", 
                       "ListenerSoap"), ListenerSoap.class);
  }
}

And an example of above code in use:

ListenerSoap soap = new Listener().getListenerSoap();
soap.ping();

I figure we can store the keystores or any certs needed in the DataStore as binary objects (though how to upload them is still a lil' vague to me).

How can we go about setting the necessary values needed for this web service to authenticate using 2-way SSL?

Thanks for any help

Update:

Through research I've seen this is how it can be done on a traditional server (one with filesystem access):

ListenerSoap soap = new Listener().getListenerSoap();
((BindingProvider) soap).getRequestContext().put("javax.net.ssl.keyStore", "client_cert.p12"

However, in this approach, client_cert.p12 is expected to be on the filesystem.

Additionally, SSLSocketFactory, SSLContext, KeyManager, and KeyManagerFactory all aren't allowed on GAE.

Update:

As of GAE SDK version 1.7.7. this should now be possible:

Similarly, Java developers can now use the javax.net.ssl package to make outbound SSL connections.

GAE 1.7.7 SDK Release Notes

Cuga
  • 17,668
  • 31
  • 111
  • 166
  • 6
    There's an open feature request for supporting client certificates in the URLFetch service: http://code.google.com/p/googleappengine/issues/detail?id=3719 – Adam Thomason Jul 05 '12 at 20:33

7 Answers7

2

From my restricted knowledge about SSL authorization, it seems you may be missing something of vital importance here; the certificates. Two-way SSL requires the client and server certificates to be in your keystore, which can be either a self-signed certificate( a pkcs12 or pem file, which you can easily generate with a few commands through shell) or a proprietary certificate issued by an authorized company like Thawte or Verisign. Although I am not sure if that is the problem you are facing, but its good to check it out. (Also, I am a newbie so please don't downvote my answer, just trying to suggest possible options.)

Setafire
  • 719
  • 2
  • 9
  • 21
  • 1
    Thanks. We have all the keys and certificates. The issue was being able to supply the certificates in the GAE environment, which wasn't possible at the time but today looks like it would be possible with the recent whitelists on Google's part. – Cuga Aug 10 '13 at 00:31
1
ListenerSoap soap = new Listener().getListenerSoap();

Hope it improves

Thanks

EdChum
  • 376,765
  • 198
  • 813
  • 562
syed
  • 19
  • 1
  • Yes, that's even included in the post... the question is how to get 2-way SSL working on GAE-- a task which appears not-doable. – Cuga Dec 14 '12 at 13:28
1

I know you might not want to hear this, but using SSL is expensive and problematic for two way communication. Depending on how much control you have over the server/client ends, I prefer a simple bi-directional pipe like web sockets and a data packet protocol that can simply implement AES. It really depends on the problem you are trying to solve.

Mike Trader
  • 8,564
  • 13
  • 55
  • 66
  • 2
    I think the OP is talking about two-way *authorization* (authentication, actually). – Andrew Barber Feb 22 '13 at 06:29
  • 1
    The *communication* is secure in both directions; the public/private keys are used to trade symmetric keys which both sides use for encryption. This question is about using a certificate on *both* the client *and* server, to authenticate each one to the other. – Andrew Barber Feb 22 '13 at 06:34
  • Yes, we need this for authentication and for our partner's software requirements. If the choice were mine, I'd do simple SSL, which isallowed on GAE. – Cuga Feb 26 '13 at 16:33
  • 1
    maybe you can follow a different arch. if its not allowed -> use another site for the 2 ways ssl (there a few java providers from $10 a month) and have that site talk to GAE where you can verify the IP address. suggestion if you cant get 2 ways ssl and cant leave google app engine – tgkprog Apr 20 '13 at 12:30
  • @tgkprog Just saw your comment now - this is exactly the solution we eventually took, setting up a proxy on our internal network which was able to handle the authentication. – Cuga Aug 10 '13 at 00:30
  • :) nice which cert did you get? just curious cause i need to buy one in a few weeks – tgkprog Aug 10 '13 at 15:39
1

It sounds like there is confusion over simple connection over SSL (https://...) and what is known as "mutual authentication" or "public key infrastructure (PKI)". You can actually do both or one independent of another. With the latter (what I think the original question is referring to), when you make a request to the server, the server will respond to you asking for a certificate which you must present to authenticate yourself.

To answer the specific question above (loading a keystore from binary data), I don't think that is really possible, since it's the Java runtime that picks up on your keystore. The only think you could do is load the bits from your datastore and temporarily write it to disk. Optionally delete it when the application exists. This I have done before and works fairly well. If you do this, I'd recommend using a location likely to be writable (such as System.getProperty("java.io.tmpdir"));), then after writing the file to disk, set the JVM properties (e.g. System.getProperties().put( "javax.net.ssl.keyStore","...");)

Domenic D.
  • 5,276
  • 4
  • 30
  • 41
  • The other option (if you can't write to disk nor use javax.net.ssl.*) is to do the connection manually (i.e. using Apache HTTP Client), to add a keystore. Then you would just to regular HTTP POST to the endpoint and parse the response. See: http://stackoverflow.com/questions/5206010/using-apache-httpclient-for-https – Domenic D. Feb 27 '13 at 16:09
  • As mentioned in the update to the original post, it's not possible to set `javax.net.ssl` on GAE due to a blacklist of those packages. It's also not possible to write to any file disk. We've set up PKI on other servers using that, but GAE won't allow it. – Cuga Feb 27 '13 at 21:01
  • Got it. I'm not all the familiar with GAE. Looks like your only choice is to not use the JAX-WS code, rather use something a little lower level like Apache HTTPClient where you can set all that security information. It's not pretty, but I've used something like Velocity to template a SOAP message and use Apache HC to POST it to the server. Downside is that you have to parse the response manually (no fancy POJO mapping that you'd get with JAX-WS generated code). – Domenic D. Feb 28 '13 at 01:10
1

You will need App Engine's Socket API for this. This API is in trusted tester mode, so it's not available for everyone.

You can ask for an access gere : https://docs.google.com/spreadsheet/viewform?formkey=dF9QR3pnQ2pNa0dqalViSTZoenVkcHc6MQ#gid=0

David
  • 5,481
  • 2
  • 20
  • 33
1

2-way SSL (from app hosted in GAE to outside world) is not supported as far as I know. I tried a sample app few months ago and was frustrated to find GAE does n't even support this basic feature.. and the documentations are n't clear either. You won't be able to present client cert when you contact a web-service.. there is no place to store it, the keystore cannot be accessed.

  • I haven't tried it yet, but as of GAE SDK v1.7.7 it might be possible to do this now, since they've whitelisted the `javax.net.ssl` packages, which should now let us specify the cert via `((BindingProvider) soap).getRequestContext().put("javax.net.ssl.keyStore"...` – Cuga May 10 '13 at 17:53
0

For what i know about two way SSL, you will have no link with Java EE code: two way SSL is a transport layer security: when your client application will try to create a secured HTTP connection (HTTPS) with the serve, the server will ask for a certificate and will approve or not this certificate. If the client certificate is approved, then a secured connection will be established on parties and they are allow to exchange some messages through this tunnel. But this process is done on the transport layer. Your code (on application layer) will never be informed of this process. In order to established two way SSL, the setup is done on the application server setup for the SSL port.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
omartin
  • 135
  • 1
  • 16
  • 4
    This is absolutely not true. It's entirely possible to establish a two-way SSL connection via the application code, such as setting the `systemProps.put("javax.net.ssl.keyStore", keyStorePath);` for instance. The issue is GAE blacklists the `java.net.ssl*` packages and so it's impossible to do this on GAE at the time of writing for this reason. – Cuga Sep 24 '12 at 13:05
  • i should admit that i was wrong. Here a sammple code on how to implement two way SSL in a java code: https://sites.google.com/site/ssljavaguide/example-code/2-way-ssl – omartin Dec 06 '12 at 09:01
  • That still won't work on GAE because all classes are blacklisted under the `javax.net.ssl.*` packages, including `SSLSocket` and `SSLSocketFactory` – Cuga Dec 06 '12 at 13:11