Esempio n. 1
0
    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
Esempio n. 2
0
    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