Skip to content

October 7, 2010

5

Trusting All Certificates In Jython

I had a little application I was writing to check some information on a VMware vSphere server. I was sending SSL HTTP requests to the server to get data. Everything was working fine under python. I had one function that needs to use Jython (which is fine because I am running everything under Jython most of the time anyway, Python is just faster to start up for testing). However, when I ran it in Jython I was getting socket.sslerror SSL handshake exceptions. This is known behavior in Jython because by default Java will automatically check the validity of certificates while Python just disregards the SSL certificates.

There are a couple of ways to get around this and they are documented here http://wiki.python.org/jython/NewSocketModule#SSLSupport. However, I didn’t like any of those approaches.

The first option requires messing with your certificate store in the JVM which means all Java processes doing anything will have your certificate added. This may or may not be what you want, but if you go to another machine or use a different JVM you will lose the ability to connect to your SSL host again.

Option 2, creating your own Security Provider looked a little more appealing because I don’t have to worry about importing each certificate and could enable this at runtime. However, it has the drawback of having to be compiled outside of Jython, and has to be put on the class path. Again, this makes it a little less portable (but not too bad). It also has the affect of trusting all certificates for every single SSL connection made, which is good because it matches up to what Python does but what if you want to only trust invalid certificates in certain parts of your code?

I started digging and came up with a way that would let me trust all certificates, be written completely in Jython, and have the ability to dynamically switch between trusting all certificates or not.

# Check if running in Jython
if 'java' in sys.platform:
    from javax.net.ssl import TrustManager, X509TrustManager
    from jarray import array
    from javax.net.ssl import SSLContext
    class TrustAllX509TrustManager(X509TrustManager):
        '''Define a custom TrustManager which will blindly accept all certificates'''
 
            def checkClientTrusted(self, chain, auth):
                pass
 
            def checkServerTrusted(self, chain, auth):
                pass
 
            def getAcceptedIssuers(self):
                return None
    # Create a static reference to an SSLContext which will use
    # our custom TrustManager
    trust_managers = array([TrustAllX509TrustManager()], TrustManager)
    TRUST_ALL_CONTEXT = SSLContext.getInstance("SSL")
    TRUST_ALL_CONTEXT.init(None, trust_managers, None)
    # Keep a static reference to the JVM's default SSLContext for restoring
    # at a later time
    DEFAULT_CONTEXT = SSLContext.getDefault()
 
def trust_all_certificates(f):
    '''Decorator function that will make it so the context of the decorated method
    will run with our TrustManager that accepts all certificates'''
    def wrapped(*args, **kwargs):
        # Only do this if running under Jython
        if 'java' in sys.platform:
            from javax.net.ssl import SSLContext
            SSLContext.setDefault(TRUST_ALL_CONTEXT)
            try:
                res = f(*args, **kwargs)
                return res
            finally:
                SSLContext.setDefault(DEFAULT_CONTEXT)
        else:
            return f(*args, **kwargs)
    return wrapped

Thats it. Now I can do things like:

@trust_all_certificates
def connect_to_untrusted_host(host):
        conn = httplib.HTTPSConnection(host)
        conn.request('GET', '/index.html')
        response = conn.getresponse()

And the connection will succeed. If I have another method that is not decorated then it will automatically verify the certificates validity.

Note that this decorator is not thread safe. Setting the SSLContext default is a global operation, so if another thread is running it could reset the SSLContext to the default before another method tries to make an SSL connection.

You can also use this without the decorator function. Just use the code prior to the decorator and set the SSLContext default wherever you need to.

If you happen to also need to verify the hostname of a certificate, which is the case if you use an HttpsURLConnection, then you will also need to create a HostnameVerifier. You can do this as follows:

 

from javax.net.ssl import HostnameVerifier, HttpsURLConnection
class AllHostsVerifier(HostnameVerifier):
    def verify(self, urlHostname, session):
        return True
HttpsURLConnection.setDefaultHostnameVerifier(AllHostsVerifier())

 

Hope that helps. It’s nice to have a pure Jython implementation of this and have it be transportable.

5 Comments Post a comment
  1. Oct 8 2010

    Hi Brandon,

    If you don’t mind, I’ll just include a link to my original article about this, in case there any problems with the jython.

    http://jython.xhaus.com/installing-an-all-trusting-security-provider-on-java-and-jython/

    All the best,

    Alan.

  2. Jun 8 2011

    Thanks for the jython version, like you I didn’t really want to have a java file sitting around just because I had to.

    I would recommend making your decorator conditionally wrap the function it is decorating rather than unconditionally:
    def trust_all_certs(f):
    try: from javax.net.ssl import SSLContext
    except ImportError: return f

    def w(*args, **kargs):
    …stuff in the “if ‘java’ in sys.platform” block…

    In addition *I* would personally use the try except ImportError rather than using the “if ‘java’ in sys.platform” because if it’s able to import the modules I would assume it is the correct platform (and I feel it’s more pythonic)

  3. ked
    Jan 9 2012

    I’d like to use your code but when I try to use SSLContext.getDefault(), I get an AttributeError : type object ‘javax.net.ssl.SSLContext’ has no attribute ‘getDefault’. Do you know how to deal with this ?

    (I use Jython 2.5.2)

  4. Brandon
    Jan 9 2012

    Strange, I don’t know what is going on there. Using Jython 2.5.2 and Java 1.6:

    xxx@xxx:~$ jython
    Jython 2.5.2 (Release_2_5_2:7206, Mar 2 2011, 23:12:06)
    [Java HotSpot(TM) 64-Bit Server VM (Sun Microsystems Inc.)] on java1.6.0_26
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from javax.net.ssl import SSLContext
    >>> SSLContext.getDefault()
    javax.net.ssl.SSLContext@21b38cdc
    >>>

  5. Ki
    Jun 17 2013

    After successfully connecting the server, how can I get around 401 Unauthorized error?

Share your thoughts, post a comment.

(required)
(required)

Note: HTML is allowed. Your email address will never be published.

Subscribe to comments