Urllib2 Certificate In Ignition Jython

I am trying to integrate a python script into my Ignition project. The script uses urllib2 library to access a 3rd party API. A certificate is required for API access. The code works in Python 2.5, but I get this error when trying to connect to the url
“in do_open raise URLError(err) urllib2.URLError: <urlopen error (-1, 'SSL handshake exception”.

I am using Ignition 7.8.5 running on a Windows 10 machine.
Is there any way to get the certificate handshaking to work in Ignition?

Here is a portion of the script. The last line is throwing the error.

			class HTTPSClientAuthHandler(urllib2.HTTPSHandler):
				def __init__(self, key, cert):
					urllib2.HTTPSHandler.__init__(self)
					self.key = key
					self.cert = cert
				def https_open(self, req):
					#Rather than pass in a reference to a connection class, we pass in
					# a reference to a function which, for all intents and purposes,
					# will behave as a constructor
					return self.do_open(self.getConnection, req)
				def getConnection(self, host, timeout=300):
					return httplib.HTTPSConnection(host,key_file=self.key,cert_file=self.cert)
		
			class HTTPSClientCertTransport(HttpTransport):
				def __init__(self, key, cert, *args, **kwargs):
					HttpTransport.__init__(self, *args, **kwargs)
					self.key = key
					self.cert = cert
				def u2open(self, u2request):
					"""
					Open a connection.
					@param u2request: A urllib2 request.
					@type u2request: urllib2.Request.
					@return: The opened file-like urllib2 object.
					@rtype: fp
					"""
					tm = self.options.timeout
					url = urllib2.build_opener(HTTPSClientAuthHandler(self.key, self.cert))
					socket.setdefaulttimeout(tm)
					return url.open(u2request)
		#These lines enable debug logging; remove them once everything works.
		#import logging
		#logging.basicConfig(level=logging.INFO)
		#logging.getLogger('suds.client').setLevel(logging.DEBUG)
		#logging.getLogger('suds.transport').setLevel(logging.DEBUG)
		client = Client(clientWSDL, location=clientLocation, transport=HTTPSClientCertTransport('C:/Key.pem','C:/Key.pem'))

Jython uses the Java SSL implementation. Plus, Java will always check the validity of the certificate, while Python just ignores it. You’ll need to either add the certificate to the keystore, or use a custom trust manager.

It took a bit of digging, and use of the Wayback Machine, but I found an article that should help you out…

The system.net.httpGet() function has a bypassCertValidation flag you can set - obviously the function is not quite as powerful as urllib, but it should be able to work with many web APIs.

1 Like

I had a similar problem with SUDS. I resolved it by implementing a custom transport which uses the system.net.http* functions to bypass certificate validation.

import StringIO
class IgnitionTransport(transport.Transport):
    def __init__(self, session=None):
        transport.Transport.__init__(self)
        self._session = session

    def open(self, request):
		response = system.net.httpGet(request.url, bypassCertValidation=True)
		return StringIO.StringIO(response)

    def send(self, request):
		response = system.net.httpPost(request.url, contentType='text/xml', 
			postData=request.message, 
			headerValues=request.headers, 
			bypassCertValidation=True, 
			throwOnError=False) 
		return transport.Reply(
		    200,
		    '',
		    response,
			)

The SUDS client can then be created by passing the custom transport:

Client(URL,transport=IgnitionTransport())