Example #1
0
 def test_unwrap_small_spnego_without_end_hyphens(self):
     expected = b"plaintext"
     encryption = WinRMEncryption(MockAuthSPNEGO(), WinRMEncryption.SPNEGO)
     bwrapped = b"--Encrypted Boundary\r\n\tContent-Type: application" \
                b"/HTTP-SPNEGO-session-encrypted\r\n\tOriginalContent: " \
                b"type=application/soap+xml;charset=UTF-8;Length=9\r\n" \
                b"--Encrypted Boundary\r\n\tContent-Type: application/" \
                b"octet-stream\r\n\x10\x00\x00\x00reallylongheaderplaintext-" \
                b"encrypted--Encrypted Boundary\r\n"
     actual = encryption.unwrap_message(bwrapped, "Encrypted Boundary")
     assert expected == actual
Example #2
0
    def test_unwrap_large_kerberos(self):
        expected = b"a" * 20000
        encryption = WinRMEncryption(MockAuth(), WinRMEncryption.KERBEROS)
        bwrapped = (b"--Encrypted Boundary\r\n\tContent-Type: application"
                    b"/HTTP-Kerberos-session-encrypted\r\n\tOriginalContent: "
                    b"type=application/soap+xml;charset=UTF-8;Length=20000"
                    b"\r\n--Encrypted Boundary\r\n\tContent-Type: application"
                    b"/octet-stream\r\n\x10\x00\x00\x00reallylongheader" +
                    expected + b"-encrypted--Encrypted Boundary--\r\n")
        actual = encryption.unwrap_message(bwrapped, "Encrypted Boundary")

        assert expected == actual
Example #3
0
    def test_unwrap_large_spnego(self):
        expected = b"a" * 20000
        encryption = WinRMEncryption(MockAuthSPNEGO(), WinRMEncryption.SPNEGO)
        bwrapped = b"--Encrypted Boundary\r\n\tContent-Type: application" \
                   b"/HTTP-SPNEGO-session-encrypted\r\n\tOriginalContent: " \
                   b"type=application/soap+xml;charset=UTF-8;Length=20000" \
                   b"\r\n--Encrypted Boundary\r\n\tContent-Type: application" \
                   b"/octet-stream\r\n\x10\x00\x00\x00reallylongheader" + expected + \
                   b"-encrypted--Encrypted Boundary--\r\n"
        actual = encryption.unwrap_message(bwrapped, "Encrypted Boundary")

        assert expected == actual
Example #4
0
    def test_unwrap_small_credsp(self):
        expected = b"plaintext"
        encryption = WinRMEncryption(MockAuthCREDSSP(),
                                     WinRMEncryption.CREDSSP)
        bwrapped = b"--Encrypted Boundary2\r\n\tContent-Type: application" \
                   b"/HTTP-CredSSP-session-encrypted\r\n\tOriginalContent: " \
                   b"type=application/soap+xml;charset=UTF-8;Length=9\r\n" \
                   b"--Encrypted Boundary2\r\n\tContent-Type: application/" \
                   b"octet-stream\r\n\x10\x00\x00\x00plaintext-encrypted" \
                   b"--Encrypted Boundary2--\r\n"
        actual = encryption.unwrap_message(bwrapped, "Encrypted Boundary2")

        assert expected == actual
Example #5
0
    def test_wrap_large_spnego(self):
        plaintext = b"a" * 20000
        encryption = WinRMEncryption(MockAuthSPNEGO(), WinRMEncryption.SPNEGO)
        expected = b"--Encrypted Boundary\r\n\tContent-Type: application" \
                   b"/HTTP-SPNEGO-session-encrypted\r\n\tOriginalContent: " \
                   b"type=application/soap+xml;charset=UTF-8;Length=20000" \
                   b"\r\n--Encrypted Boundary\r\n\tContent-Type: application" \
                   b"/octet-stream\r\n\x10\x00\x00\x00reallylongheader" + plaintext + \
                   b"-encrypted--Encrypted Boundary--\r\n"
        actual_type, actual = encryption.wrap_message(plaintext)

        assert "multipart/encrypted" == actual_type
        assert expected == actual
Example #6
0
    def test_unwrap_small_kerberos(self):
        expected = b"plaintext"
        encryption = WinRMEncryption(MockAuthSPNEGO(),
                                     WinRMEncryption.KERBEROS)

        # The spaces after -- on each boundary is on purpose, some MS implementations do this.
        bwrapped = b"-- Encrypted Boundary\r\n\tContent-Type: application" \
                   b"/HTTP-Kerberos-session-encrypted\r\n\tOriginalContent: " \
                   b"type=application/soap+xml;charset=UTF-8;Length=9\r\n" \
                   b"-- Encrypted Boundary\r\n\tContent-Type: application/" \
                   b"octet-stream\r\n\x10\x00\x00\x00reallylongheaderplaintext-" \
                   b"encrypted-- Encrypted Boundary--\r\n"
        actual = encryption.unwrap_message(bwrapped, "Encrypted Boundary")
        assert expected == actual
Example #7
0
    def test_wrap_small_credsp(self):
        plaintext = b"plaintext"
        encryption = WinRMEncryption(MockAuthCREDSSP(),
                                     WinRMEncryption.CREDSSP)
        expected = b"--Encrypted Boundary\r\n\tContent-Type: application" \
                   b"/HTTP-CredSSP-session-encrypted\r\n\tOriginalContent: " \
                   b"type=application/soap+xml;charset=UTF-8;Length=9\r\n" \
                   b"--Encrypted Boundary\r\n\tContent-Type: application/" \
                   b"octet-stream\r\n\x10\x00\x00\x00plaintext-encrypted" \
                   b"--Encrypted Boundary--\r\n"
        actual_type, actual = encryption.wrap_message(plaintext)

        assert "multipart/encrypted" == actual_type
        assert expected == actual
Example #8
0
    def test_wrap_small_spnego(self):
        plaintext = b"plaintext"
        encryption = WinRMEncryption(MockAuth(MockAuthSPNEGO()),
                                     WinRMEncryption.SPNEGO)
        expected = b"--Encrypted Boundary\r\n\tContent-Type: application" \
                   b"/HTTP-SPNEGO-session-encrypted\r\n\tOriginalContent: " \
                   b"type=application/soap+xml;charset=UTF-8;Length=9\r\n" \
                   b"--Encrypted Boundary\r\n\tContent-Type: application/" \
                   b"octet-stream\r\n\x07\x00\x00\x00header plaintext-" \
                   b"encrypted--Encrypted Boundary--\r\n"
        actual_type, actual = encryption.wrap_message(plaintext, "hostname")

        assert "multipart/encrypted" == actual_type
        assert expected == actual
Example #9
0
    def test_wrap_small_kerberos(self):
        plaintext = b"plaintext"
        encryption = WinRMEncryption(MockAuthSPNEGO(),
                                     WinRMEncryption.KERBEROS)
        expected = b"--Encrypted Boundary\r\n\tContent-Type: application" \
                   b"/HTTP-Kerberos-session-encrypted\r\n\tOriginalContent: " \
                   b"type=application/soap+xml;charset=UTF-8;Length=9\r\n" \
                   b"--Encrypted Boundary\r\n\tContent-Type: application/" \
                   b"octet-stream\r\n\x10\x00\x00\x00reallylongheaderplaintext-" \
                   b"encrypted--Encrypted Boundary--\r\n"
        actual_type, actual = encryption.wrap_message(plaintext)

        assert "multipart/encrypted" == actual_type
        assert expected == actual
Example #10
0
    def test_wrap_spnego_padded(self):
        plaintext = b"plaintext"
        encryption = WinRMEncryption(MockAuth(padding=True),
                                     WinRMEncryption.SPNEGO)
        expected = (
            b"--Encrypted Boundary\r\n\tContent-Type: application"
            b"/HTTP-SPNEGO-session-encrypted\r\n\tOriginalContent: "
            b"type=application/soap+xml;charset=UTF-8;Length=10\r\n"
            b"--Encrypted Boundary\r\n\tContent-Type: application/"
            b"octet-stream\r\n\x10\x00\x00\x00reallylongheaderplaintext-"
            b"encrypted--Encrypted Boundary--\r\n")
        actual_type, actual = encryption.wrap_message(plaintext)

        assert "multipart/encrypted" == actual_type
        assert expected == actual
Example #11
0
    def test_unwrap_length_mismatch(self):
        encryption = WinRMEncryption(MockAuthSPNEGO(), WinRMEncryption.SPNEGO)
        bwrapped = b"--Encrypted Boundary\r\n\tContent-Type: application" \
                   b"/HTTP-SPNEGO-session-encrypted\r\n\tOriginalContent: " \
                   b"type=application/soap+xml;charset=UTF-8;Length=9\r\n" \
                   b"--Encrypted Boundary\r\n\tContent-Type: application/" \
                   b"octet-stream\r\n\x10\x00\x00\x00reallylongheaderplain-" \
                   b"encrypted--Encrypted Boundary--\r\n"

        with pytest.raises(WinRMError) as err:
            encryption.unwrap_message(bwrapped, "Encrypted Boundary")

        assert str(err.value) == \
            "The encrypted length from the server does not match the " \
            "expected length, decryption failed, actual: 5 != expected: 9"
Example #12
0
    def send(self, message):
        hostname = get_hostname(self.endpoint)
        if self.session is None:
            self.session = self._build_session()

            # need to send an initial blank message to setup the security
            # context required for encryption
            if self.wrap_required:
                request = requests.Request('POST', self.endpoint, data=None)
                prep_request = self.session.prepare_request(request)
                self._send_request(prep_request)

                protocol = WinRMEncryption.SPNEGO
                if isinstance(self.session.auth, HttpCredSSPAuth):
                    protocol = WinRMEncryption.CREDSSP
                elif self.session.auth.contexts[
                        hostname].response_auth_header == 'kerberos':
                    # When Kerberos (not Negotiate) was used, we need to send a special protocol value and not SPNEGO.
                    protocol = WinRMEncryption.KERBEROS

                self.encryption = WinRMEncryption(
                    self.session.auth.contexts[hostname], protocol)

        log.debug("Sending message: %s" % message)
        # for testing, keep commented out
        # self._test_messages.append({"request": message.decode('utf-8'),
        #                             "response": None})

        headers = self.session.headers
        if self.wrap_required:
            content_type, payload = self.encryption.wrap_message(message)
            type_header = '%s;protocol="%s";boundary="Encrypted Boundary"' \
                          % (content_type, self.encryption.protocol)
            headers.update({
                'Content-Type': type_header,
                'Content-Length': str(len(payload)),
            })
        else:
            payload = message
            headers['Content-Type'] = "application/soap+xml;charset=UTF-8"

        request = requests.Request('POST',
                                   self.endpoint,
                                   data=payload,
                                   headers=headers)
        prep_request = self.session.prepare_request(request)
        return self._send_request(prep_request)
Example #13
0
    def send(self, message: bytes) -> bytes:
        hostname = get_hostname(self.endpoint)
        if self.session is None:
            self.session = self._build_session()

            # need to send an initial blank message to setup the security
            # context required for encryption
            if self.wrap_required:
                request = requests.Request("POST", self.endpoint, data=None)
                prep_request = self.session.prepare_request(request)
                self._send_request(prep_request)

                protocol = WinRMEncryption.SPNEGO
                if isinstance(self.session.auth, HttpCredSSPAuth):
                    protocol = WinRMEncryption.CREDSSP
                elif self.session.auth.contexts[hostname].response_auth_header == "kerberos":  # type: ignore[union-attr] # This should not happen
                    # When Kerberos (not Negotiate) was used, we need to send a special protocol value and not SPNEGO.
                    protocol = WinRMEncryption.KERBEROS

                self.encryption = WinRMEncryption(self.session.auth.contexts[hostname], protocol)  # type: ignore[union-attr] # This should not happen

        if log.isEnabledFor(logging.DEBUG):
            log.debug("Sending message: %s" % message.decode("utf-8"))
        # for testing, keep commented out
        # self._test_messages.append({"request": message.decode('utf-8'),
        #                             "response": None})

        headers = self.session.headers
        if self.wrap_required:
            content_type, payload = self.encryption.wrap_message(message)  # type: ignore[union-attr] # This should not happen
            protocol = self.encryption.protocol if self.encryption else WinRMEncryption.SPNEGO
            type_header = '%s;protocol="%s";boundary="Encrypted Boundary"' % (content_type, protocol)
            headers.update(
                {
                    "Content-Type": type_header,
                    "Content-Length": str(len(payload)),
                }
            )
        else:
            payload = message
            headers["Content-Type"] = "application/soap+xml;charset=UTF-8"

        request = requests.Request("POST", self.endpoint, data=payload, headers=headers)
        prep_request = self.session.prepare_request(request)
        return self._send_request(prep_request)
Example #14
0
    def _build_auth_negotiate(self, session, auth_provider="auto"):
        kwargs = self._get_auth_kwargs('negotiate')

        session.auth = HTTPNegotiateAuth(username=self.username,
                                         password=self.password,
                                         auth_provider=auth_provider,
                                         wrap_required=self.wrap_required,
                                         **kwargs)
        self.encryption = WinRMEncryption(session.auth, WinRMEncryption.SPNEGO)
Example #15
0
    def test_unwrap_large_credsp(self):
        expected = b"a" * 20000
        encryption = WinRMEncryption(MockAuthCREDSSP(),
                                     WinRMEncryption.CREDSSP)
        bwrapped = b"--Encrypted Boundary\r\n\tContent-Type: application" \
                   b"/HTTP-CredSSP-session-encrypted\r\n\tOriginalContent: " \
                   b"type=application/soap+xml;charset=UTF-8;Length=16384" \
                   b"\r\n--Encrypted Boundary\r\n\tContent-Type: application" \
                   b"/octet-stream\r\n\x10\x00\x00\x00" + b"a" * 16384 + \
                   b"-encrypted--Encrypted Boundary\r\n\tContent-Type: " \
                   b"application/HTTP-CredSSP-session-encrypted\r\n" \
                   b"\tOriginalContent: type=application/soap+xml;" \
                   b"charset=UTF-8;Length=3616\r\n--Encrypted Boundary\r\n" \
                   b"\tContent-Type: application/octet-stream\r\n" \
                   b"\x10\x00\x00\x00" + b"a" * 3616 + \
                   b"-encrypted--Encrypted Boundary--\r\n"
        actual = encryption.unwrap_message(bwrapped, "Encrypted Boundary")

        assert expected == actual
Example #16
0
    def test_wrap_large_credsp(self):
        plaintext = b"a" * 20000
        encryption = WinRMEncryption(MockAuth(MockAuthCREDSSP()),
                                     WinRMEncryption.CREDSSP)
        expected = b"--Encrypted Boundary\r\n\tContent-Type: application" \
                   b"/HTTP-CredSSP-session-encrypted\r\n\tOriginalContent: " \
                   b"type=application/soap+xml;charset=UTF-8;Length=16384" \
                   b"\r\n--Encrypted Boundary\r\n\tContent-Type: application" \
                   b"/octet-stream\r\n\x10\x00\x00\x00" + b"a" * 16384 + \
                   b"-encrypted--Encrypted Boundary\r\n\tContent-Type: " \
                   b"application/HTTP-CredSSP-session-encrypted\r\n" \
                   b"\tOriginalContent: type=application/soap+xml;" \
                   b"charset=UTF-8;Length=3616\r\n--Encrypted Boundary\r\n" \
                   b"\tContent-Type: application/octet-stream\r\n" \
                   b"\x10\x00\x00\x00" + b"a" * 3616 + \
                   b"-encrypted--Encrypted Boundary--\r\n"
        actual_type, actual = encryption.wrap_message(plaintext, "hostname")

        assert "multipart/x-multi-encrypted" == actual_type
        assert expected == actual
Example #17
0
    def _build_auth_credssp(self, session):
        if not HAS_CREDSSP:
            raise ImportError("Cannot use CredSSP auth as requests-credssp is "
                              "not installed: %s" % str(CREDSSP_IMP_ERR))

        if self.username is None:
            raise ValueError("For credssp auth, the username must be "
                             "specified")
        if self.password is None:
            raise ValueError("For credssp auth, the password must be "
                             "specified")

        kwargs = self._get_auth_kwargs('credssp')
        session.auth = HttpCredSSPAuth(username=self.username,
                                       password=self.password,
                                       **kwargs)
        self.encryption = WinRMEncryption(session.auth,
                                          WinRMEncryption.CREDSSP)
Example #18
0
    def test_get_credssp_trailer_length(self, cipher, expected):
        encryption = WinRMEncryption(None, WinRMEncryption.CREDSSP)
        actual = encryption._credssp_trailer(30, cipher)

        assert expected == actual
Example #19
0
class _TransportHTTP(object):
    def __init__(self,
                 server,
                 port=None,
                 username=None,
                 password=None,
                 ssl=True,
                 path="wsman",
                 auth="negotiate",
                 cert_validation=True,
                 connection_timeout=30,
                 encryption='auto',
                 proxy=None,
                 no_proxy=False,
                 read_timeout=30,
                 reconnection_retries=0,
                 reconnection_backoff=2.0,
                 **kwargs):
        self.server = server
        self.port = port if port is not None else (5986 if ssl else 5985)
        self.username = username
        self.password = password
        self.ssl = ssl
        self.path = path

        if auth not in SUPPORTED_AUTHS:
            raise ValueError("The specified auth '%s' is not supported, "
                             "please select one of '%s'" %
                             (auth, ", ".join(SUPPORTED_AUTHS)))
        self.auth = auth
        self.cert_validation = cert_validation
        self.connection_timeout = connection_timeout
        self.read_timeout = read_timeout
        self.reconnection_retries = reconnection_retries
        self.reconnection_backoff = reconnection_backoff

        # determine the message encryption logic
        if encryption not in ["auto", "always", "never"]:
            raise ValueError("The encryption value '%s' must be auto, "
                             "always, or never" % encryption)
        enc_providers = ["credssp", "kerberos", "negotiate", "ntlm"]
        if ssl:
            # msg's are automatically encrypted with TLS, we only want message
            # encryption if always was specified
            self.wrap_required = encryption == "always"
            if self.wrap_required and self.auth not in enc_providers:
                raise ValueError(
                    "Cannot use message encryption with auth '%s', either set "
                    "encryption='auto' or use one of the following auth "
                    "providers: %s" % (self.auth, ", ".join(enc_providers)))
        else:
            # msg's should always be encrypted when not using SSL, unless the
            # user specifies to never encrypt
            self.wrap_required = not encryption == "never"
            if self.wrap_required and self.auth not in enc_providers:
                raise ValueError(
                    "Cannot use message encryption with auth '%s', either set "
                    "encryption='never', use ssl=True or use one of the "
                    "following auth providers: %s" %
                    (self.auth, ", ".join(enc_providers)))
        self.encryption = None

        self.proxy = proxy
        self.no_proxy = no_proxy

        for kwarg_list in AUTH_KWARGS.values():
            for kwarg in kwarg_list:
                setattr(self, kwarg, kwargs.get(kwarg, None))

        self.endpoint = self._create_endpoint(self.ssl, self.server, self.port,
                                              self.path)
        log.debug("Initialising HTTP transport for endpoint: %s, auth: %s, "
                  "user: %s" % (self.endpoint, self.username, self.auth))
        self.session = None

        # used when building tests, keep commented out
        # self._test_messages = []

    def close(self):
        if self.session:
            self.session.close()

    def send(self, message):
        hostname = get_hostname(self.endpoint)
        if self.session is None:
            self.session = self._build_session()

            # need to send an initial blank message to setup the security
            # context required for encryption
            if self.wrap_required:
                request = requests.Request('POST', self.endpoint, data=None)
                prep_request = self.session.prepare_request(request)
                self._send_request(prep_request)

                protocol = WinRMEncryption.SPNEGO
                if isinstance(self.session.auth, HttpCredSSPAuth):
                    protocol = WinRMEncryption.CREDSSP
                elif self.session.auth.contexts[
                        hostname].response_auth_header == 'kerberos':
                    # When Kerberos (not Negotiate) was used, we need to send a special protocol value and not SPNEGO.
                    protocol = WinRMEncryption.KERBEROS

                self.encryption = WinRMEncryption(
                    self.session.auth.contexts[hostname], protocol)

        log.debug("Sending message: %s" % message)
        # for testing, keep commented out
        # self._test_messages.append({"request": message.decode('utf-8'),
        #                             "response": None})

        headers = self.session.headers
        if self.wrap_required:
            content_type, payload = self.encryption.wrap_message(message)
            type_header = '%s;protocol="%s";boundary="Encrypted Boundary"' \
                          % (content_type, self.encryption.protocol)
            headers.update({
                'Content-Type': type_header,
                'Content-Length': str(len(payload)),
            })
        else:
            payload = message
            headers['Content-Type'] = "application/soap+xml;charset=UTF-8"

        request = requests.Request('POST',
                                   self.endpoint,
                                   data=payload,
                                   headers=headers)
        prep_request = self.session.prepare_request(request)
        return self._send_request(prep_request)

    def _send_request(self, request):
        response = self.session.send(request,
                                     timeout=(self.connection_timeout,
                                              self.read_timeout))

        content_type = response.headers.get('content-type', "")
        if content_type.startswith(
                "multipart/encrypted;") or content_type.startswith(
                    "multipart/x-multi-encrypted;"):
            boundary = re.search('boundary=['
                                 '|\\"](.*)['
                                 '|\\"]',
                                 response.headers['content-type']).group(1)
            response_content = self.encryption.unwrap_message(
                response.content, to_unicode(boundary))
            response_text = to_string(response_content)
        else:
            response_content = response.content
            response_text = response.text if response_content else ''

        log.debug("Received message: %s" % response_text)
        # for testing, keep commented out
        # self._test_messages[-1]['response'] = response_text
        try:
            response.raise_for_status()
        except requests.HTTPError as err:
            response = err.response
            if response.status_code == 401:
                raise AuthenticationError("Failed to authenticate the user %s "
                                          "with %s" %
                                          (self.username, self.auth))
            else:
                code = response.status_code
                raise WinRMTransportError('http', code, response_text)

        return response_content

    def _build_session(self):
        log.debug("Building requests session with auth %s" % self.auth)
        self._suppress_library_warnings()

        session = requests.Session()
        session.headers['User-Agent'] = "Python PSRP Client"

        # requests defaults to 'Accept-Encoding: gzip, default' which normally doesn't matter on vanila WinRM but for
        # Exchange endpoints hosted on IIS they actually compress it with 1 of the 2 algorithms. By explicitly setting
        # identity we are telling the server not to transform (compress) the data using the HTTP methods which we don't
        # support. https://tools.ietf.org/html/rfc7231#section-5.3.4
        session.headers['Accept-Encoding'] = 'identity'

        # get the env requests settings
        session.trust_env = True
        settings = session.merge_environment_settings(url=self.endpoint,
                                                      proxies={},
                                                      stream=None,
                                                      verify=None,
                                                      cert=None)

        # set the proxy config
        orig_proxy = session.proxies
        session.proxies = settings['proxies']
        if self.proxy is not None:
            proxy_key = 'https' if self.ssl else 'http'
            session.proxies = {proxy_key: self.proxy}
        elif self.no_proxy:
            session.proxies = orig_proxy

        # Retry on connection errors, with a backoff factor
        retry_kwargs = {
            'total': self.reconnection_retries,
            'connect': self.reconnection_retries,
            'status': self.reconnection_retries,
            'read': 0,
            'backoff_factor': self.reconnection_backoff,
            'status_forcelist': (425, 429, 503),
        }
        try:
            retries = Retry(**retry_kwargs)
        except TypeError:
            # Status was added in urllib3 >= 1.21 (Requests >= 2.14.0), remove
            # the status retry counter and try again. The user should upgrade
            # to a newer version
            log.warning(
                "Using an older requests version that without support "
                "for status retries, ignoring.",
                exc_info=True)
            del retry_kwargs['status']
            retries = Retry(**retry_kwargs)

        session.mount('http://',
                      requests.adapters.HTTPAdapter(max_retries=retries))
        session.mount('https://',
                      requests.adapters.HTTPAdapter(max_retries=retries))

        # set cert validation config
        session.verify = self.cert_validation

        # if cert_validation is a bool (no path specified), not False and there
        # are env settings for verification, set those env settings
        if isinstance(self.cert_validation, bool) and self.cert_validation \
                and settings['verify'] is not None:
            session.verify = settings['verify']

        build_auth = getattr(self, "_build_auth_%s" % self.auth)
        build_auth(session)
        return session

    def _build_auth_basic(self, session):
        if self.username is None:
            raise ValueError("For basic auth, the username must be specified")
        if self.password is None:
            raise ValueError("For basic auth, the password must be specified")

        session.auth = requests.auth.HTTPBasicAuth(username=self.username,
                                                   password=self.password)

    def _build_auth_certificate(self, session):
        if self.certificate_key_pem is None:
            raise ValueError("For certificate auth, the path to the "
                             "certificate key pem file must be specified with "
                             "certificate_key_pem")
        if self.certificate_pem is None:
            raise ValueError("For certificate auth, the path to the "
                             "certificate pem file must be specified with "
                             "certificate_pem")
        if self.ssl is False:
            raise ValueError("For certificate auth, SSL must be used")

        session.cert = (self.certificate_pem, self.certificate_key_pem)
        session.headers['Authorization'] = "http://schemas.dmtf.org/wbem/" \
                                           "wsman/1/wsman/secprofile/" \
                                           "https/mutual"

    def _build_auth_credssp(self, session):
        if self.username is None:
            raise ValueError("For credssp auth, the username must be "
                             "specified")
        if self.password is None:
            raise ValueError("For credssp auth, the password must be "
                             "specified")

        kwargs = self._get_auth_kwargs('credssp')
        session.auth = HttpCredSSPAuth(username=self.username,
                                       password=self.password,
                                       **kwargs)

    def _build_auth_kerberos(self, session):
        self._build_auth_negotiate(session, "kerberos")

    def _build_auth_negotiate(self, session, auth_provider="negotiate"):
        kwargs = self._get_auth_kwargs('negotiate')

        session.auth = HTTPNegotiateAuth(username=self.username,
                                         password=self.password,
                                         auth_provider=auth_provider,
                                         wrap_required=self.wrap_required,
                                         **kwargs)

    def _build_auth_ntlm(self, session):
        self._build_auth_negotiate(session, "ntlm")

    def _get_auth_kwargs(self, auth_provider):
        kwargs = {}
        for kwarg in AUTH_KWARGS[auth_provider]:
            kwarg_value = getattr(self, kwarg, None)
            if kwarg_value is not None:
                kwarg_key = kwarg[len(auth_provider) + 1:]
                kwargs[kwarg_key] = kwarg_value

        return kwargs

    def _suppress_library_warnings(self):
        # try to suppress known warnings from requests if possible
        try:
            from requests.packages.urllib3.exceptions import \
                InsecurePlatformWarning
            warnings.simplefilter('ignore', category=InsecurePlatformWarning)
        except:  # NOQA: E722; # pragma: no cover
            pass

        try:
            from requests.packages.urllib3.exceptions import SNIMissingWarning
            warnings.simplefilter('ignore', category=SNIMissingWarning)
        except:  # NOQA: E722; # pragma: no cover
            pass

        # if we're explicitly ignoring validation, try to suppress
        # InsecureRequestWarning, since the user opted-in
        if self.cert_validation is False:
            try:
                from requests.packages.urllib3.exceptions import \
                    InsecureRequestWarning
                warnings.simplefilter('ignore',
                                      category=InsecureRequestWarning)
            except:  # NOQA: E722; # pragma: no cover
                pass

    @staticmethod
    def _create_endpoint(ssl, server, port, path):
        scheme = "https" if ssl else "http"

        # Check if the server is an IPv6 Address, enclose in [] if it is
        try:
            address = ipaddress.IPv6Address(to_unicode(server))
        except ipaddress.AddressValueError:
            pass
        else:
            server = "[%s]" % address.compressed

        endpoint = "%s://%s:%s/%s" % (scheme, server, port, path)
        return endpoint