Beispiel #1
0
    def test_302_raises_exception(self):
        """
        We should not follow HTTP 302 redirects
        """
        response_headers = {'ContentLength': '0'}
        responses.add(responses.POST, 'http://server:5985',
                      adding_headers=response_headers,
                      status=302)

        service = Service('http://server:5985', 'username', 'password', False)
        with self.assertRaises(WSManException) as context:
            service.invoke('headers', 'body')
        self.assertRegexpMatches(str(context.exception), 'the remote host returned an unexpected http status code.*')
Beispiel #2
0
    def test_200_with_invalid_body_raises_exception(self):
        """
        Ensure a 200 response with an empty or non-xml response is handled
        """
        responses.add(responses.POST, 'http://server:5985',
                      body='invalid_xml_response',
                      status=200, content_type='application/soap+xml')

        service = Service('http://server:5985', 'username', 'password', False)

        with self.assertRaises(WSManException) as context:
            service.invoke('headers', 'body')
        self.assertEqual('the remote host returned an invalid soap response', str(context.exception))
Beispiel #3
0
 def test_500_raises_exception(self):
     """
     If the server fails or cannot continue it may return a 500, ensure this is handled
     :return:
     """
     response_headers = {'ContentLength': '0'}
     responses.add(responses.POST, 'http://server:5985',
                   adding_headers=response_headers,
                   status=500)
     service = Service('http://server:5985', 'username', 'password', False)
     with self.assertRaises(WSManException) as context:
         service.invoke('headers', 'body')
     self.assertRegexpMatches(str(context.exception), 'the remote host returned an unexpected http status code.*')
Beispiel #4
0
    def test_200_soap_fault_to_exception_translation(self):
        """
        SOAP Faults should be translated to WSManOperationException's
        """
        responses.add(responses.POST, 'http://server:5985',
                      body=self.response.operation_timeout,
                      status=200, content_type='application/soap+xml')

        service = Service('http://server:5985', 'username', 'password', False)

        with self.assertRaises(WSManOperationException) as context:
            service.invoke('headers', 'body')
        error = 'The WS-Management service cannot complete the operation within the time specified in OperationTimeout.'
        self.assertRegexpMatches(str(context.exception), error)
Beispiel #5
0
    def test_401_no_body_exception_translation(self):
        """
        If authentication fails a 401 is returned to requests, this should be handled
        :return:
        """
        response_headers = {'ContentLength': '0'}
        responses.add(responses.POST, 'http://server:5985',
                      adding_headers=response_headers,
                      status=401)

        service = Service('http://server:5985', 'username', 'password', False)
        with self.assertRaises(WSManAuthenticationException) as context:
            service.invoke('headers', 'body')
        self.assertEqual(str(context.exception), 'the remote host rejected authentication')
Beispiel #6
0
    def __init__(self, endpoint, username, password, **kwargs):
        # transport = Session._build_transport(endpoint, auth, username, password)

        # Store the endpoint and the service we will use to invoke it
        self.endpoint = endpoint
        # False == No CredSSP
        self.service = Service(endpoint, username, password, True)

        # The user can set override some defaults for the Session, they can also be overridden on each request
        self.max_envelope = self._build_max_envelope(kwargs.get('max_envelope_size', Session.MaxEnvelopeSize))
        self.locale = self._build_locale(kwargs.get('locale', Session.Locale))

        # The operation timeout header overrides the timeout set on the server. Some users may prefer to
        # use the servers default timeout, so this header will only be included if the user explicitly sets
        # an operation timeout.
        if 'operation_timeout' in kwargs:
            self.default_operation_timeout = self._build_operation_timeout(kwargs.get('operation_timeout'))
        else:
            self.default_operation_timeout = None
Beispiel #7
0
    def test_headers_namespaces_are_translated_to_xml(self, mock_post):
        """
        The service should translate a dictionary to xml, this is a casual test because the logic is mostly
        implemented in xmltodict
        """
        headers = {'a': 'test', 'b': 'test', 'n': 'test', 'x': 'test', 'w': 'test'}
        mock_response = mock.Mock()
        mock_response.status_code = 200
        mock_response.content = self.response.command_response
        mock_post.return_value = mock_response

        service = Service('http://server:5985', 'username', 'password', False)
        service.invoke(headers, {})

        args, kwargs = mock_post.call_args
        self.assertTrue('<a>test</a>' in kwargs['data'])
        self.assertTrue('<b>test</b>' in kwargs['data'])
        self.assertTrue('<n>test</n>' in kwargs['data'])
        self.assertTrue('<x>test</x>' in kwargs['data'])
        self.assertTrue('<w>test</w>' in kwargs['data'])
Beispiel #8
0
    def __init__(self, endpoint, username, password, **kwargs):
        # transport = Session._build_transport(endpoint, auth, username, password)

        # Store the endpoint and the service we will use to invoke it
        self.endpoint = endpoint
        # False == No CredSSP
        self.service = Service(endpoint, username, password, True)

        # The user can set override some defaults for the Session, they can also be overridden on each request
        self.max_envelope = self._build_max_envelope(kwargs.get("max_envelope_size", Session.MaxEnvelopeSize))
        self.locale = self._build_locale(kwargs.get("locale", Session.Locale))

        # The operation timeout header overrides the timeout set on the server. Some users may prefer to
        # use the servers default timeout, so this header will only be included if the user explicitly sets
        # an operation timeout.
        if "operation_timeout" in kwargs:
            self.default_operation_timeout = self._build_operation_timeout(kwargs.get("operation_timeout"))
        else:
            self.default_operation_timeout = None
Beispiel #9
0
class Session(object):
    """
    Factory object for building sessions and connection options
    """

    def __init__(self, endpoint, username, password, **kwargs):
        # transport = Session._build_transport(endpoint, auth, username, password)

        # Store the endpoint and the service we will use to invoke it
        self.endpoint = endpoint
        # False == No CredSSP
        self.service = Service(endpoint, username, password, True)

        # The user can set override some defaults for the Session, they can also be overridden on each request
        self.max_envelope = self._build_max_envelope(kwargs.get('max_envelope_size', Session.MaxEnvelopeSize))
        self.locale = self._build_locale(kwargs.get('locale', Session.Locale))

        # The operation timeout header overrides the timeout set on the server. Some users may prefer to
        # use the servers default timeout, so this header will only be included if the user explicitly sets
        # an operation timeout.
        if 'operation_timeout' in kwargs:
            self.default_operation_timeout = self._build_operation_timeout(kwargs.get('operation_timeout'))
        else:
            self.default_operation_timeout = None

    def get(self, resource, operation_timeout=None, max_envelope_size=None, locale=None):
        """
        resource can be a URL or a ResourceLocator
        """
        if isinstance(resource, str):
            resource = ResourceLocator(resource)

        headers = self._build_headers(resource, Session.GetAction, operation_timeout, max_envelope_size, locale)
        self.service.invoke.set_options(tsoapheaders=headers)
        return self.service.invoke

    def put(self, resource, obj,
            operation_timeout=None, max_envelope_size=None, locale=None):
        """
        resource can be a URL or a ResourceLocator
        """
        headers = None
        return self.service.invoke(headers, obj)

    def delete(self, resource, operation_timeout=None, max_envelope_size=None, locale=None):
        """
        resource can be a URL or a ResourceLocator
        """
        if isinstance(resource, str):
            resource = ResourceLocator(resource)

        headers = self._build_headers(resource, Session.DeleteAction,
                                      operation_timeout, max_envelope_size, locale)
        return self.service.invoke(headers, None)

    def create(self, resource, obj,
               operation_timeout=None, max_envelope_size=None, locale=None):
        """
        resource can be a URL or a ResourceLocator
        """
        if isinstance(resource, str):
            resource = ResourceLocator(resource)

        headers = self._build_headers(resource, Session.CreateAction,
                                      operation_timeout, max_envelope_size, locale)
        return self.service.invoke(headers, obj)

    def command(self, resource, obj,
                operation_timeout=None, max_envelope_size=None, locale=None):
        """
        resource can be a URL or a ResourceLocator
        """
        if isinstance(resource, str):
            resource = ResourceLocator(resource)

        headers = self._build_headers(resource, Session.CommandAction,
                                      operation_timeout, max_envelope_size, locale)
        return self.service.invoke(headers, obj)

    def recieve(self, resource, obj,
                operation_timeout=None, max_envelope_size=None, locale=None):
        """
        resource can be a URL or a ResourceLocator
        """
        if isinstance(resource, str):
            resource = ResourceLocator(resource)

        headers = self._build_headers(resource, Session.ReceiveAction,
                                      operation_timeout, max_envelope_size, locale)
        return self.service.invoke(headers, obj)

    @staticmethod
    def _build_selectors(selectors):
        # Build the WSMan SelectorSet Element from the selector dictionary
        selector_set = []
        for selector_name in selectors.iterkeys():
            selector_value = selectors[selector_name]
            selector_set.append({'#text': str(selector_value), '@Name': selector_name})
        return {'w:SelectorSet': {'w:Selector': selector_set}}

    @staticmethod
    # TODO add mustcomply attribute to element
    def _build_options(options):
        option_set = []
        for name, (value, must_comply) in options.iteritems():
            must_comply = bool(must_comply)
            option_set.append({'#text': str(value), '@Name': name})
        return {'w:OptionSet': {'w:Option': option_set}}

    def _build_operation_timeout(self, operation_timeout):
        if operation_timeout is None:
            return self.default_operation_timeout
        else:
            return {'w:OperationTimeout': 'PT{0}S'.format(operation_timeout)}

    def _build_max_envelope(self, max_envelope_size):
        if max_envelope_size is None:
            return self.max_envelope
        else:
            return {'w:MaxEnvelopeSize': '{0}'.format(max_envelope_size)}

    def _build_locale(self, locale):
        if locale is None:
            return self.locale
        else:
            return {'Locale': {"@xml:lang": "en-US"}}

    def _build_headers(self, resource, action, operation_timeout, max_envelope_size, locale):
        headers = OrderedDict([
            ('a:To', self.endpoint),
            ('a:ReplyTo', Session.Address),
            ('w:ResourceURI', resource.url),
            ('a:MessageID', format(uuid.uuid4())),
            ('a:Action', action)]
        )
        # TODO: Implement support for Microsoft XPRESS compression
        # https://social.msdn.microsoft.com/Forums/en-US/501e4f29-edfc-4240-af3b-344264060b99/
        # wsman-xpress-remote-shell-compression?forum=os_windowsprotocols

        # headers.update({'rsp:CompressionType': {'@soap:mustUnderstand': 'true', '#text': 'xpress'}})
        # only include the operation timeout if the user specified one when the class was instantiated
        # or if the user explicitly set one when invoking a method.
        if operation_timeout is not None:
            headers.update(self._build_operation_timeout(operation_timeout))
        elif self.default_operation_timeout is not None:
            headers.update(self.default_operation_timeout)

        headers.update(self._build_selectors(resource.selectors))
        headers.update(self._build_options(resource.options))
        headers.update(self._build_max_envelope(max_envelope_size))
        headers.update(self._build_locale(locale))
        return headers
Beispiel #10
0
class Session(object):
    """
    Factory object for building sessions and connection options
    """

    def __init__(self, endpoint, username, password, **kwargs):
        # transport = Session._build_transport(endpoint, auth, username, password)

        # Store the endpoint and the service we will use to invoke it
        self.endpoint = endpoint
        # False == No CredSSP
        self.service = Service(endpoint, username, password, True)

        # The user can set override some defaults for the Session, they can also be overridden on each request
        self.max_envelope = self._build_max_envelope(kwargs.get("max_envelope_size", Session.MaxEnvelopeSize))
        self.locale = self._build_locale(kwargs.get("locale", Session.Locale))

        # The operation timeout header overrides the timeout set on the server. Some users may prefer to
        # use the servers default timeout, so this header will only be included if the user explicitly sets
        # an operation timeout.
        if "operation_timeout" in kwargs:
            self.default_operation_timeout = self._build_operation_timeout(kwargs.get("operation_timeout"))
        else:
            self.default_operation_timeout = None

    def get(self, resource, operation_timeout=None, max_envelope_size=None, locale=None):
        """
        resource can be a URL or a ResourceLocator
        """
        if isinstance(resource, str):
            resource = ResourceLocator(resource)

        headers = self._build_headers(resource, Session.GetAction, operation_timeout, max_envelope_size, locale)
        self.service.invoke.set_options(tsoapheaders=headers)
        return self.service.invoke

    def put(self, resource, obj, operation_timeout=None, max_envelope_size=None, locale=None):
        """
        resource can be a URL or a ResourceLocator
        """
        headers = None
        return self.service.invoke(headers, obj)

    def delete(self, resource, operation_timeout=None, max_envelope_size=None, locale=None):
        """
        resource can be a URL or a ResourceLocator
        """
        if isinstance(resource, str):
            resource = ResourceLocator(resource)

        headers = self._build_headers(resource, Session.DeleteAction, operation_timeout, max_envelope_size, locale)
        return self.service.invoke(headers, None)

    def create(self, resource, obj, operation_timeout=None, max_envelope_size=None, locale=None):
        """
        resource can be a URL or a ResourceLocator
        """
        if isinstance(resource, str):
            resource = ResourceLocator(resource)

        headers = self._build_headers(resource, Session.CreateAction, operation_timeout, max_envelope_size, locale)
        return self.service.invoke(headers, obj)

    def command(self, resource, obj, operation_timeout=None, max_envelope_size=None, locale=None):
        """
        resource can be a URL or a ResourceLocator
        """
        if isinstance(resource, str):
            resource = ResourceLocator(resource)

        headers = self._build_headers(resource, Session.CommandAction, operation_timeout, max_envelope_size, locale)
        return self.service.invoke(headers, obj)

    def recieve(self, resource, obj, operation_timeout=None, max_envelope_size=None, locale=None):
        """
        resource can be a URL or a ResourceLocator
        """
        if isinstance(resource, str):
            resource = ResourceLocator(resource)

        headers = self._build_headers(resource, Session.ReceiveAction, operation_timeout, max_envelope_size, locale)
        return self.service.invoke(headers, obj)

    @staticmethod
    def _build_selectors(selectors):
        # Build the WSMan SelectorSet Element from the selector dictionary
        selector_set = []
        for selector_name in selectors.iterkeys():
            selector_value = selectors[selector_name]
            selector_set.append({"#text": str(selector_value), "@Name": selector_name})
        return {"w:SelectorSet": {"w:Selector": selector_set}}

    @staticmethod
    # TODO add mustcomply attribute to element
    def _build_options(options):
        option_set = []
        for name, (value, must_comply) in options.iteritems():
            must_comply = bool(must_comply)
            option_set.append({"#text": str(value), "@Name": name})
        return {"w:OptionSet": {"w:Option": option_set}}

    def _build_operation_timeout(self, operation_timeout):
        if operation_timeout is None:
            return self.default_operation_timeout
        else:
            return {"w:OperationTimeout": "PT{0}S".format(operation_timeout)}

    def _build_max_envelope(self, max_envelope_size):
        if max_envelope_size is None:
            return self.max_envelope
        else:
            return {"w:MaxEnvelopeSize": "{0}".format(max_envelope_size)}

    def _build_locale(self, locale):
        if locale is None:
            return self.locale
        else:
            return {"Locale": {"@xml:lang": "en-US"}}

    def _build_headers(self, resource, action, operation_timeout, max_envelope_size, locale):
        headers = OrderedDict(
            [
                ("a:To", self.endpoint),
                ("a:ReplyTo", Session.Address),
                ("w:ResourceURI", resource.url),
                ("a:MessageID", format(uuid.uuid4())),
                ("a:Action", action),
            ]
        )
        # TODO: Implement support for Microsoft XPRESS compression
        # https://social.msdn.microsoft.com/Forums/en-US/501e4f29-edfc-4240-af3b-344264060b99/
        # wsman-xpress-remote-shell-compression?forum=os_windowsprotocols

        # headers.update({'rsp:CompressionType': {'@soap:mustUnderstand': 'true', '#text': 'xpress'}})
        # only include the operation timeout if the user specified one when the class was instantiated
        # or if the user explicitly set one when invoking a method.
        if operation_timeout is not None:
            headers.update(self._build_operation_timeout(operation_timeout))
        elif self.default_operation_timeout is not None:
            headers.update(self.default_operation_timeout)

        headers.update(self._build_selectors(resource.selectors))
        headers.update(self._build_options(resource.options))
        headers.update(self._build_max_envelope(max_envelope_size))
        headers.update(self._build_locale(locale))
        return headers