Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 54 additions & 5 deletions shotgun_api3/shotgun.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import urllib2 # used for image upload
import urlparse
import shutil # used for attachment download
import httplib # Used for secure file upload.

# use relative import for versions >=2.5 and package import for python versions <2.5
if (sys.version_info[0] > 2) or (sys.version_info[0] == 2 and sys.version_info[1] >= 6):
Expand Down Expand Up @@ -3034,11 +3035,15 @@ def _build_opener(self, handler):
"""
Build urllib2 opener with appropriate proxy handler.
"""
handlers = []
if self.__ca_certs and not NO_SSL_VALIDATION:

@jfboismenu jfboismenu Mar 21, 2018

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fix is only applied if __ca_certs is set, which makes it very safe as it doesn't impact any other usage of the API. The build_opener is strictly used for uploads/downloads.

In other words, if this fix has a bug somewhere inside it on certain conditions, it will only fail for people who are using SHOTGUN_API_CACERTS, who already can't download and upload at the moment anyway.

handlers.append(CACertsHTTPSHandler(self.__ca_certs))

if self.config.proxy_handler:
opener = urllib2.build_opener(self.config.proxy_handler, handler)
else:
opener = urllib2.build_opener(handler)
return opener
handlers.append(self.config.proxy_handler)

handlers.append(handler)
return urllib2.build_opener(*handlers)

def _turn_off_ssl_validation(self):
"""
Expand Down Expand Up @@ -3810,8 +3815,52 @@ def _send_form(self, url, params):

return result

# Helpers from the previous API, left as is.

class CACertsHTTPSConnection(httplib.HTTPConnection):
""""
This class allows to create an HTTPS connection that uses the custom certificates
passed in.
"""

default_port = httplib.HTTPS_PORT

def __init__(self, *args, **kwargs):
"""
:param args: Positional arguments passed down to the base class.
:param ca_certs: Path to the custom CA certs file.
:param kwargs: Keyword arguments passed down to the bas class
"""
# Pop that argument,
self.__ca_certs = kwargs.pop("ca_certs")
httplib.HTTPConnection.__init__(self, *args, **kwargs)

def connect(self):
"Connect to a host on a given (SSL) port."
httplib.HTTPConnection.connect(self)
# Now that the regular HTTP socket has been created, wrap it with our SSL certs.
self.sock = ssl.wrap_socket(
self.sock,
ca_certs=self.__ca_certs,
cert_reqs=ssl.CERT_REQUIRED
)


class CACertsHTTPSHandler(urllib2.HTTPSHandler):
"""
Handler that ensures https connections are created with the custom CA certs.
"""
def __init__(self, cacerts):
urllib2.HTTPSHandler.__init__(self)
self.__ca_certs = cacerts

def https_open(self, req):
return self.do_open(self.create_https_connection, req)

def create_https_connection(self, *args, **kwargs):
return CACertsHTTPSConnection(*args, ca_certs=self.__ca_certs, **kwargs)


# Helpers from the previous API, left as is.
# Based on http://code.activestate.com/recipes/146306/
class FormPostHandler(urllib2.BaseHandler):
"""
Expand Down