def proxy_ssl(self, host=None, port=None): if host and port: host = "%s:%d" % (host, port) else: host = "%s:%d" % (self.host, self.port) # Seems properly to use timeout for connect too timeout = self.http_connection_kwargs.get("timeout") if timeout is not None: sock = socket.create_connection((self.proxy, int(self.proxy_port)), timeout) else: sock = socket.create_connection((self.proxy, int(self.proxy_port))) mssapi.log.debug("Proxy connection: CONNECT %s HTTP/1.0\r\n", host) sock.sendall("CONNECT %s HTTP/1.0\r\n" % host) sock.sendall("User-Agent: %s\r\n" % UserAgent) if self.proxy_user and self.proxy_pass: for k, v in self.get_proxy_auth_header().items(): sock.sendall("%s: %s\r\n" % (k, v)) # See discussion about this config option at # https://groups.google.com/forum/?fromgroups#!topic/mssapi-dev/teenFvOq2Cc if config.getbool("Mssapi", "send_crlf_after_proxy_auth_headers", False): sock.sendall("\r\n") else: sock.sendall("\r\n") resp = http_client.HTTPResponse(sock, strict=True, debuglevel=self.debug) resp.begin() if resp.status != 200: # Fake a socket error, use a code that make it obvious it hasn't # been generated by the socket library raise socket.error( -71, "Error talking to HTTP proxy %s:%s: %s (%s)" % (self.proxy, self.proxy_port, resp.status, resp.reason), ) # We can safely close the response, it duped the original socket resp.close() h = http_client.HTTPConnection(host) if self.https_validate_certificates and HAVE_HTTPS_CONNECTION: msg = "wrapping ssl socket for proxied connection; " if self.ca_certificates_file: msg += "CA certificate file=%s" % self.ca_certificates_file else: msg += "using system provided SSL certs" mssapi.log.debug(msg) key_file = self.http_connection_kwargs.get("key_file", None) cert_file = self.http_connection_kwargs.get("cert_file", None) sslSock = ssl.wrap_socket( sock, keyfile=key_file, certfile=cert_file, cert_reqs=ssl.CERT_REQUIRED, ca_certs=self.ca_certificates_file, ) cert = sslSock.getpeercert() hostname = self.host.split(":", 0)[0] if not https_connection.ValidateCertificateHostname(cert, hostname): raise https_connection.InvalidCertificateException(hostname, cert, "hostname mismatch") else: # Fallback for old Python without ssl.wrap_socket if hasattr(http_client, "ssl"): sslSock = http_client.ssl.SSLSocket(sock) else: sslSock = socket.ssl(sock, None, None) sslSock = http_client.FakeSocket(sock, sslSock) # This is a bit unclean h.sock = sslSock return h
def __init__( self, host, aws_access_key_id=None, aws_secret_access_key=None, is_secure=True, port=None, proxy=None, proxy_port=None, proxy_user=None, proxy_pass=None, debug=0, https_connection_factory=None, path="/", provider="aws", security_token=None, suppress_consec_slashes=True, validate_certs=True, profile_name=None, ): """ :type host: str :param host: The host to make the connection to :keyword str aws_access_key_id: Your AWS Access Key ID (provided by Amazon). If none is specified, the value in your ``AWS_ACCESS_KEY_ID`` environmental variable is used. :keyword str aws_secret_access_key: Your AWS Secret Access Key (provided by Amazon). If none is specified, the value in your ``AWS_SECRET_ACCESS_KEY`` environmental variable is used. :keyword str security_token: The security token associated with temporary credentials issued by STS. Optional unless using temporary credentials. If none is specified, the environment variable ``AWS_SECURITY_TOKEN`` is used if defined. :type is_secure: boolean :param is_secure: Whether the connection is over SSL :type https_connection_factory: list or tuple :param https_connection_factory: A pair of an HTTP connection factory and the exceptions to catch. The factory should have a similar interface to L{http_client.HTTPSConnection}. :param str proxy: Address/hostname for a proxy server :type proxy_port: int :param proxy_port: The port to use when connecting over a proxy :type proxy_user: str :param proxy_user: The username to connect with on the proxy :type proxy_pass: str :param proxy_pass: The password to use when connection over a proxy. :type port: int :param port: The port to use to connect :type suppress_consec_slashes: bool :param suppress_consec_slashes: If provided, controls whether consecutive slashes will be suppressed in key paths. :type validate_certs: bool :param validate_certs: Controls whether SSL certificates will be validated or not. Defaults to True. :type profile_name: str :param profile_name: Override usual Credentials section in config file to use a named set of keys instead. """ self.suppress_consec_slashes = suppress_consec_slashes self.num_retries = 6 # Override passed-in is_secure setting if value was defined in config. if config.has_option("Mssapi", "is_secure"): is_secure = config.getboolean("Mssapi", "is_secure") self.is_secure = is_secure # Whether or not to validate server certificates. # The default is now to validate certificates. This can be # overridden in the mssapi config file are by passing an # explicit validate_certs parameter to the class constructor. self.https_validate_certificates = config.getbool("Mssapi", "https_validate_certificates", validate_certs) if self.https_validate_certificates and not HAVE_HTTPS_CONNECTION: raise MssapiClientError( "SSL server certificate validation is enabled in mssapi " "configuration, but Python dependencies required to " "support this feature are not available. Certificate " "validation is only supported when running under Python " "2.6 or later." ) certs_file = config.get_value("Mssapi", "ca_certificates_file", DEFAULT_CA_CERTS_FILE) if certs_file == "system": certs_file = None self.ca_certificates_file = certs_file if port: self.port = port else: self.port = PORTS_BY_SECURITY[is_secure] self.handle_proxy(proxy, proxy_port, proxy_user, proxy_pass) # define exceptions from http_client that we want to catch and retry self.http_exceptions = (http_client.HTTPException, socket.error, socket.gaierror, http_client.BadStatusLine) # define subclasses of the above that are not retryable. self.http_unretryable_exceptions = [] if HAVE_HTTPS_CONNECTION: self.http_unretryable_exceptions.append(https_connection.InvalidCertificateException) # define values in socket exceptions we don't want to catch self.socket_exception_values = (errno.EINTR,) if https_connection_factory is not None: self.https_connection_factory = https_connection_factory[0] self.http_exceptions += https_connection_factory[1] else: self.https_connection_factory = None if is_secure: self.protocol = "https" else: self.protocol = "http" self.host = host self.path = path # if the value passed in for debug if not isinstance(debug, six.integer_types): debug = 0 self.debug = config.getint("Mssapi", "debug", debug) self.host_header = None # Timeout used to tell http_client how long to wait for socket timeouts. # Default is to leave timeout unchanged, which will in turn result in # the socket's default global timeout being used. To specify a # timeout, set http_socket_timeout in Mssapi config. Regardless, # timeouts will only be applied if Python is 2.6 or greater. self.http_connection_kwargs = {} if (sys.version_info[0], sys.version_info[1]) >= (2, 6): # If timeout isn't defined in mssapi config file, use 70 second # default as recommended by self.http_connection_kwargs["timeout"] = config.getint("Mssapi", "http_socket_timeout", 70) if isinstance(provider, Provider): # Allow overriding Provider self.provider = provider else: self._provider_type = provider self.provider = Provider( self._provider_type, aws_access_key_id, aws_secret_access_key, security_token, profile_name ) # Allow config file to override default host, port, and host header. if self.provider.host: self.host = self.provider.host if self.provider.port: self.port = self.provider.port if self.provider.host_header: self.host_header = self.provider.host_header self._pool = ConnectionPool() self._connection = (self.host, self.port, self.is_secure) self._last_rs = None self._auth_handler = auth.get_auth_handler(host, config, self.provider, self._required_auth_capability()) if getattr(self, "AuthServiceName", None) is not None: self.auth_service_name = self.AuthServiceName self.request_hook = None