Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Parameter for additional verifiy locations for Server Certificates during connect #380

Closed
@AndyXan

Description

@AndyXan

Is your feature request related to a problem? Please describe.
The Splunk Python SDK lacks the possibility to provide a custom ca certificate that is not installed in the local system certificates storage for server certificate validation.

The possible arguments (key_file, cert_file) are for client authentifaction - not for server certificate verficitation.

The problematic Code snippet is (current upstream):
binding.py::1354

def handler(key_file=None, cert_file=None, timeout=None, verify=False):
    """This class returns an instance of the default HTTP request handler using
    the values you provide.

    :param `key_file`: A path to a PEM (Privacy Enhanced Mail) formatted file containing your private key (optional).
    :type key_file: ``string``
    :param `cert_file`: A path to a PEM (Privacy Enhanced Mail) formatted file containing a certificate chain file (optional).
    :type cert_file: ``string``
    :param `timeout`: The request time-out period, in seconds (optional).
    :type timeout: ``integer`` or "None"
    :param `verify`: Set to False to disable SSL verification on https connections.
    :type verify: ``Boolean``
    """

    def connect(scheme, host, port):
        **kwargs = {} <-----**
        if timeout is not None: kwargs['timeout'] = timeout
        if scheme == "http":
            return six.moves.http_client.HTTPConnection(host, port, **kwargs)
        if scheme == "https":
            if key_file is not None: kwargs['key_file'] = key_file
            if cert_file is not None: kwargs['cert_file'] = cert_file

            if not verify:
                kwargs['context'] = ssl._create_unverified_context()
            
            return six.moves.http_client.HTTPSConnection(host, port, **kwargs) <-----------------
        raise ValueError("unsupported scheme: %s" % scheme)

So, if verification is enabled - a default SSL Context is created and CA's .pem file have to be present in the system certificate storage. Otherwise it's an error like that:

import http.client
c = http.client.HTTPSConnection("my-splunk-host", "8000")
c.request("GET", "/")

[Out] SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] 

What's actually desired is to provide additional ssl lookup definitions:

import ssl
import http.client
context = ssl.create_default_context()
context.load_verify_locations("my-root-ca.pem")
c = http.client.HTTPSConnection("my-splunk-host", "8000", context=context)
test = c.request("GET", "/")

Or in the above snippet from the original code in binding.py

    def connect(scheme, host, port):
        kwargs = {}
        if timeout is not None: kwargs['timeout'] = timeout
        if scheme == "http":
            return six.moves.http_client.HTTPConnection(host, port, **kwargs)
        if scheme == "https":
            if key_file is not None: kwargs['key_file'] = key_file
            if cert_file is not None: kwargs['cert_file'] = cert_file

            if not verify:
                kwargs['context'] = ssl._create_unverified_context()
            else: 
                   context = ssl.create_default_context() <--------------------
                   context.load_verify_locations("my-root-ca.pem") <--------------------
                   kwargs['context'] = context <--------------------

            return six.moves.http_client.HTTPSConnection(host, port, **kwargs)
        raise ValueError("unsupported scheme: %s" % scheme)

Describe the solution you'd like

With the pull request, a User can optionally provide the entire SSLContext object with verify locations and all other settings, such as TLS-Version. A user can fully control the transport channel, which a user should be able to do.

import ssl
import splunklib.client as client
context = ssl.create_default_context()
context.load_verify_locations("my-root-ca-cert.pem")
self.service = client.connect(host=self.host, app='my-app', port=8089,
       username=self.username, scheme='https', password=self.password, verify=True, context=context)

The following parts of the code are slightly changes (details, see Pull Request).

Simply add a new argument that either allows the passing of a entire SSL-Context object or the CA-Verify-Locations at:

  • client.py :: def connect(**kwargs): (kwargs covers that already, no changes needed - just documentation)
  • client.py :: 401 :: Service(**kwargs): (kwargs covers that already, no changes needed - just documentation)
  • binding.py :: 472 init
        self.http = HttpLib(handler, kwargs.get("verify", False), key_file=kwargs.get("key_file"),
                            cert_file=kwargs.get("cert_file"))  # Default to False for backward compat

pass the new argument to HttpLib (either context or verify location)

  • binding.py :: 1142 -> self.handler = handler(verify=verify, key_file=key_file, cert_file=cert_file) -> pass the argument
  • binding.py :: 1354 -> Final change (see code above)
            if not verify:
                kwargs['context'] = ssl._create_unverified_context()
            else: 
                context = ssl.create_default_context()
                context.load_verify_locations(verify_path)
                kwargs['context'] = context

It's not a big change - I am going to create a pull request tomorrow with the option to pass an entire SSLContext object to HTTPSConnection(...), thus enabling the user to specify custom ca certficates, tls versions and so on. I think the user should have the possibility to fully control the transport channel, if desired.

Best Regards

Describe alternatives you've considered
The only alternative is to install custom ca certificates on the local system beforehand. This is suboptimal for certificates shipped with a packaged application and varies depending on the Operating System.

Additional context
Add any other context or screenshots about the feature request here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions