4

I am developing a google app engine application, and I need to connect to a webservice using SOAP. I'm using pysimplesoap (patched with the code found here) to parse the xml, and fire a request with a client-side certificate. When I do this in a simple unit test from my local environment, it works, and I get a proper response from the webservice. However, when I run the exact same code from within app engine, I get this:

  File "/Users/me/Documents/workspace/blixem/model/communicate/communication_channel.py", line 60, in generate_soap_message_pysimplesoap
    response = client.SendDocument('LA.XML', 'TESTCASE', 'data')
  File "/Users/me/Documents/workspace/blixem/lib/pysimplesoap/client.py", line 152, in <lambda>
    return lambda *args, **kwargs: self.wsdl_call(attr,*args,**kwargs)
  File "/Users/me/Documents/workspace/blixem/lib/pysimplesoap/client.py", line 320, in wsdl_call
    response = self.call(method, *params)
  File "/Users/me/Documents/workspace/blixem/lib/pysimplesoap/client.py", line 215, in call
    self.xml_response = self.send(method, self.xml_request)
  File "/Users/me/Documents/workspace/blixem/lib/pysimplesoap/client.py", line 241, in send
    location,"POST", body=xml, headers=headers )
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/httplib2/httplib2/__init__.py", line 1457, in request
    self.disable_ssl_certificate_validation)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/httplib2/httplib2/__init__.py", line 1143, in __init__
    strict, timeout, proxy_info, ca_certs, disable_ssl_certificate_validation)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/httplib2/httplib2/__init__.py", line 1092, in __init__
    raise NotSupportedOnThisPlatform()
NotSupportedOnThisPlatform

I did some reading, and discovered that client side certificates were not supported yet in the urlfetch service. Is this still the case? If so, is there a work-around?

Aliaksandr Belik
  • 12,725
  • 6
  • 64
  • 90
  • Thanx Ingo, I'll look into this Outbound Sockets Support feature. Too bad client certificates are not supported. – user1734726 Feb 06 '13 at 16:17
  • Ingo, I would like to up-vote your comment, but Im fairly new to asking questions on stackoverflow, so please tell me how to do this up-voting on your comment (shouldn't we be up-voting answers instead of comments?) – user1734726 Feb 06 '13 at 20:50
  • You are right. I removed the comment and added it as an answer :) – Ingo Feb 06 '13 at 21:02

3 Answers3

2

Client side certificates are currently not supported by GAE. You can use the URLFetch service over HTTPS. But you cannot use client certificates. You should try the Outbound Sockets Support feature which is currently available in the trusted tester program. It might whitelist the functionality you are looking for. I asked a similar question for GAE/J before.

If you really need it already either go with the outbound socket feature or run a proxy in EC2.

Community
  • 1
  • 1
Ingo
  • 1,552
  • 10
  • 31
1

To expand on BooTooMany's answer, it's now possible to do this with the excellent requests library as long as the underlying code is using sockets. Follow these steps to use it:

  1. Sockets are only available to paid apps. Make sure your app has billing enabled.
  2. Install requests into your lib/ directory. I'm currently using v2.21.0. Make sure not to monkeypatch requests to use the AppEngine adapters provided by requests-toolbelt, despite that being recommended by the docs. This makes requests use urlfetch instead of sockets, which is available for free apps but does not currently support client-side certificates.
  3. In your app.yaml, enable the SSL library:
libraries:
- name: ssl
  version: latest
  1. In your app.yaml, enable sockets for the development server:
env_variables:
  GAE_USE_SOCKETS_HTTPLIB: 'yes'

Now you're ready to make requests with client certificates:

import requests

def make_request(url):
    cert = ('cert_file.pem', 'key_file.pem')
    server_cert_file = 'server_cert_file.pem'
    return requests.get(url=url, cert=cert, verify=server_cert_file)
David Pärsson
  • 6,038
  • 2
  • 37
  • 52
0

Python SSL is now supported on GAE - see https://cloud.google.com/appengine/docs/standard/python/sockets/ssl_support

So it's now possible to use client-side certificates. From that webpage:

 # Example of a dynamic key and cert.
  datastore_record_k = ndb.Key('Employee', 'asalieri', 'Address', 1)
  datastore_record = datastore_record_k.get()
  key_str = datastore_record.key_str
  cert_str = datastore_record.cert
  ssl_server = ssl.wrap_socket(server_sock,
                              server_side=False,
                              keyfile=StringIO.StringIO(key_str),
                              certfile=StringIO.StringIO(cert_str),
                              cert_reqs=ssl.CERT_REQUIRED,
                              ssl_version=ssl.PROTOCOL_SSLv23,
                              ca_certs=CERTIFICATE_FILE)
BooTooMany
  • 1,192
  • 12
  • 19
  • How would one go about to create a HTTPS request with `ssl.wrap_socket`, as the question mentions? Would that require implementing a lot of low-level HTTP communication logic, or could [`requests`](http://python-requests.org/) or another library use this somehow? – David Pärsson Aug 04 '19 at 19:22