Example #1
0
 def send_message(self, message):
     headers = {
         'Content-Type': 'application/soap+xml;charset=UTF-8',
         'Content-Length': len(message),
         'User-Agent': 'Python WinRM client'
     }
     password_manager = HTTPPasswordMgrWithDefaultRealm()
     password_manager.add_password(None, self.endpoint, self.username,
                                   self.password)
     auth_manager = HTTPBasicAuthHandler(password_manager)
     opener = build_opener(auth_manager)
     install_opener(opener)
     request = Request(self.endpoint, data=message, headers=headers)
     try:
         response = urlopen(request, timeout=self.timeout)
         # Version 1.1 of WinRM adds the namespaces in the document instead of the envelope so we have to
         # add them ourselves here. This should have no affect version 2.
         response_text = response.read()
         return response_text
         #doc = ElementTree.fromstring(response.read())
         #Ruby
         #doc = Nokogiri::XML(resp.http_body.content)
         #doc.collect_namespaces.each_pair do |k,v|
         #    doc.root.add_namespace((k.split(/:/).last),v) unless doc.namespaces.has_key?(k)
         #end
         #return doc
         #return doc
     except HTTPError as ex:
         error_message = 'Bad HTTP response returned from server. Code {0}'.format(
             ex.code)
         if ex.msg:
             error_message += ', {0}'.format(ex.msg)
         raise WinRMTransportError(error_message)
     except URLError as ex:
         raise WinRMTransportError(ex.reason)
Example #2
0
    def send_message(self, message):
        headers = self._headers.copy()
        headers['Content-Length'] = len(message)

        self._setup_opener()
        request = Request(self.endpoint, data=message, headers=headers)
        try:
            response = urlopen(request, timeout=self.timeout)
            # Version 1.1 of WinRM adds the namespaces in the document instead of the envelope so we have to
            # add them ourselves here. This should have no affect version 2.
            response_text = response.read()
            return response_text
            #doc = ElementTree.fromstring(response.read())
            #Ruby
            #doc = Nokogiri::XML(resp.http_body.content)
            #doc.collect_namespaces.each_pair do |k,v|
            #    doc.root.add_namespace((k.split(/:/).last),v) unless doc.namespaces.has_key?(k)
            #end
            #return doc
            #return doc
        except HTTPError as ex:
            error_message = 'Bad HTTP response returned from server. Code {0}'.format(ex.code)
            if ex.msg:
                error_message += ', {0}'.format(ex.msg)
            raise WinRMTransportError(error_message)
        except URLError as ex:
            raise WinRMTransportError(ex.reason)
Example #3
0
    def send_message(self, message):
        # TODO current implementation does negotiation on each HTTP request which is not efficient
        # TODO support kerberos session with message encryption
        krb_ticket = KerberosTicket(self.krb_service)
        headers = {
            'Authorization': krb_ticket.auth_header,
            'Connection': 'Keep-Alive',
            'Content-Type': 'application/soap+xml;charset=UTF-8',
            'User-Agent': 'Python WinRM client'
        }

        request = Request(self.endpoint, data=message, headers=headers)
        try:
            response = urlopen(request, timeout=self.timeout)
            krb_ticket.verify_response(response.headers['WWW-Authenticate'])
            response_text = response.read()
            return response_text
        except HTTPError as ex:
            #if ex.code == 401 and ex.headers['WWW-Authenticate'] == 'Negotiate, Basic realm="WSMAN"':
            error_message = 'Kerberos-based authentication was failed. Code {0}'.format(
                ex.code)
            if ex.msg:
                error_message += ', {0}'.format(ex.msg)
            raise WinRMTransportError(error_message)
        except URLError as ex:
            raise WinRMTransportError(ex.reason)
Example #4
0
    def send_message(self, message):
        # TODO current implementation does negotiation on each HTTP request which is not efficient
        # TODO support kerberos session with message encryption
        krb_ticket = KerberosTicket(self.krb_service)
        headers = {
            'Authorization': krb_ticket.auth_header,
            'Connection': 'Keep-Alive',
            'Content-Type': 'application/soap+xml;charset=UTF-8',
            'User-Agent': 'Python WinRM client'
        }

        request = Request(self.endpoint, data=message, headers=headers)
        try:
            response = urlopen(request, timeout=self.timeout)
            krb_ticket.verify_response(response.headers['WWW-Authenticate'])
            response_text = response.read()
            return response_text
        except HTTPError as ex:
            response_text = ex.read()
            # Per http://msdn.microsoft.com/en-us/library/cc251676.aspx rule 3,
            # should handle this 500 error and retry receiving command output.
            if 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive' in message and 'Code="2150858793"' in response_text:
                return response_text
            #if ex.code == 401 and ex.headers['WWW-Authenticate'] == 'Negotiate, Basic realm="WSMAN"':
            error_message = 'Kerberos-based authentication was failed. Code {0}'.format(
                ex.code)
            if ex.msg:
                error_message += ', {0}'.format(ex.msg)
            raise WinRMTransportError('kerberos', error_message)
        except URLError as ex:
            raise WinRMTransportError('kerberos', ex.reason)
Example #5
0
    def send_message(self, message):
        # TODO support kerberos/ntlm session with message encryption

        if not self.session:
            self.session = self.build_session()

        # urllib3 fails on SSL retries with unicode buffers- must send it a byte string
        # see https://github.com/shazow/urllib3/issues/717
        if isinstance(message, unicode_type):
            message = message.encode('utf-8')

        request = requests.Request('POST', self.endpoint, data=message)
        prepared_request = self.session.prepare_request(request)

        try:
            response = self.session.send(prepared_request, timeout=self.read_timeout_sec)
            response_text = response.text
            response.raise_for_status()
            return response_text
        except requests.HTTPError as ex:
            if ex.response.status_code == 401:
                raise InvalidCredentialsError("the specified credentials were rejected by the server")
            if ex.response.content:
                response_text = ex.response.content
            else:
                response_text = ''
            # Per http://msdn.microsoft.com/en-us/library/cc251676.aspx rule 3,
            # should handle this 500 error and retry receiving command output.
            if b'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive' in message and b'Code="2150858793"' in response_text:
                raise WinRMOperationTimeoutError()

            error_message = 'Bad HTTP response returned from server. Code {0}'.format(ex.response.status_code)

            raise WinRMTransportError('http', error_message)
    def __init__(self,
                 endpoint,
                 realm=None,
                 service='HTTP',
                 keytab=None,
                 server_cert_validation='validate'):
        """
        Uses Kerberos/GSS-API to authenticate and encrypt messages
        @param string endpoint: the WinRM webservice endpoint
        @param string realm: the Kerberos realm we are authenticating to
        @param string service: the service name, default is HTTP
        @param string keytab: the path to a keytab file if you are using one
        """
        if not HAVE_KERBEROS:
            raise WinRMTransportError('kerberos', 'kerberos is not installed')

        super(HttpKerberos, self).__init__(endpoint, None, None)
        parsed_url = urlparse(endpoint)
        self.krb_service = '{0}@{1}'.format(service, parsed_url.hostname)
        self.scheme = parsed_url.scheme
        self._server_cert_validation = server_cert_validation

        if HAVE_SSLCONTEXT and server_cert_validation == 'ignore':
            self.sslcontext = create_default_context()
            self.sslcontext.check_hostname = False
            self.sslcontext.verify_mode = CERT_NONE
        else:
            self.sslcontext = None
    def send_message(self, message):
        headers = self._headers.copy()
        headers['Content-Length'] = len(message)

        self._setup_opener()
        request = Request(self.endpoint, data=message, headers=headers)

        try:
            # install_opener is ignored in > 2.7.9 when an SSLContext is passed to urlopen, so
            # we'll have to call open manually with our stored opener chain
            response = self.opener.open(request, timeout=self.timeout)
            # Version 1.1 of WinRM adds the namespaces in the document instead
            # of the envelope so we have to
            # add them ourselves here. This should have no affect version 2.
            response_text = response.read()
            return response_text
            # doc = ElementTree.fromstring(response.read())
            # Ruby
            # doc = Nokogiri::XML(resp.http_body.content)
            # doc.collect_namespaces.each_pair do |k,v|
            #    doc.root.add_namespace((k.split(/:/).last),v)
            #    unless doc.namespaces.has_key?(k)
            # end
            # return doc
            # return doc
        except HTTPError as ex:
            if ex.code == 401:
                raise UnauthorizedError(transport='plaintext', message=ex.msg)
            response_text = ex.read()
            # Per http://msdn.microsoft.com/en-us/library/cc251676.aspx rule 3,
            # should handle this 500 error and retry receiving command output.
            if 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive' in message and 'Code="2150858793"' in response_text:  # NOQA
                # TODO raise TimeoutError here instead of just return text
                return response_text
            error_message = 'Bad HTTP response returned from server. ' \
                            ' Code {0}'.format(ex.code)
            if ex.msg:
                error_message += ', {0}'.format(ex.msg)
            raise WinRMTransportError('http', error_message)
        except URLError as ex:
            raise WinRMTransportError('http', ex.reason)
Example #8
0
    def __init__(self, endpoint, realm=None, service='HTTP', keytab=None):
        """
        Uses Kerberos/GSS-API to authenticate and encrypt messages
        @param string endpoint: the WinRM webservice endpoint
        @param string realm: the Kerberos realm we are authenticating to
        @param string service: the service name, default is HTTP
        @param string keytab: the path to a keytab file if you are using one
        """
        if not HAVE_KERBEROS:
            raise WinRMTransportError('kerberos is not installed')

        super(HttpKerberos, self).__init__(endpoint, None, None)
        self.krb_service = '{0}@{1}'.format(service, urlparse(endpoint).hostname)
Example #9
0
    def _send_message_request(self, prepared_request, message):
        try:
            response = self.session.send(prepared_request, timeout=self.read_timeout_sec)
            response.raise_for_status()
            return response
        except requests.HTTPError as ex:
            if ex.response.status_code == 401:
                raise InvalidCredentialsError("the specified credentials were rejected by the server")
            if ex.response.content:
                response_text = self._get_message_response_text(ex.response)
            else:
                response_text = ''

            raise WinRMTransportError('http', ex.response.status_code, response_text)
Example #10
0
    def send_message(self, message):
        # TODO support kerberos/ntlm session with message encryption

        if not self.session:
            self.session = self.build_session()

        # urllib3 fails on SSL retries with unicode buffers- must send it a byte string
        # see https://github.com/shazow/urllib3/issues/717
        if isinstance(message, unicode_type):
            message = message.encode('utf-8')

        request = requests.Request('POST', self.endpoint, data=message)
        prepared_request = self.session.prepare_request(request)

        try:
            response = self.session.send(prepared_request, timeout=self.read_timeout_sec)
            response_text = response.text
            response.raise_for_status()
            return response_text
        except requests.HTTPError as ex:
            if ex.response.status_code == 401:
                raise InvalidCredentialsError("the specified credentials were rejected by the server")
            if ex.response.content:
                response_text = ex.response.content
            else:
                response_text = ''
            # Per http://msdn.microsoft.com/en-us/library/cc251676.aspx rule 3,
            # should handle this 500 error and retry receiving command output.
            if b'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive' in message and b'Code="2150858793"' in response_text:
                raise WinRMOperationTimeoutError()

            error_message = 'Bad HTTP response returned from server. Code {0}'.format(ex.response.status_code)

            import xml.etree.ElementTree as ET

            if response_text:
                root = ET.fromstring(response_text)
                ns = {'s': "http://www.w3.org/2003/05/soap-envelope",
                      'a': "http://schemas.xmlsoap.org/ws/2004/08/addressing",
                      'w': "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"}

                for text in root.findall('s:Body/s:Fault/s:Reason/s:Text', ns):
                    error_message += "\n%s" % text.text

            raise WinRMTransportError('http', error_message)
Example #11
0
    def _send_message_request(self, prepared_request, message):
        try:
            response = self.session.send(prepared_request, timeout=self.read_timeout_sec)
            response.raise_for_status()
            return response
        except requests.HTTPError as ex:
            if ex.response.status_code == 401:
                raise InvalidCredentialsError("the specified credentials were rejected by the server")
            if ex.response.content:
                response_text = self._get_message_response_text(ex.response)
            else:
                response_text = ''

            # Per http://msdn.microsoft.com/en-us/library/cc251676.aspx rule 3,
            # should handle this 500 error and retry receiving command output.
            if b'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive' in message and b'Code="2150858793"' in response_text:
                raise WinRMOperationTimeoutError()

            error_message = 'Bad HTTP response returned from server. Code {0}'.format(ex.response.status_code)

            raise WinRMTransportError('http', error_message)