Пример #1
0
    def test_MKCOL_PUT(self):
        """
        Verify access controls during MKCOL.
        """
        for method in ("MKCOL", "PUT"):
            def work():
                for name, code in (
                    ("nobind" , responsecode.FORBIDDEN),
                    ("bind"   , responsecode.CREATED),
                    ("unbind" , responsecode.CREATED),
                ):
                    collection_path = os.path.join(self.docroot, name)
                    path = os.path.join(collection_path, "dst")

                    if os.path.isfile(path):
                        os.remove(path)
                    elif os.path.isdir(path):
                        os.rmdir(path)

                    request = SimpleRequest(self.site, method, "/" + name + "/dst")
                    _add_auth_header(request)

                    def test(response, code=code, path=path):
                        if response.code != code:
                            return self.oops(request, response, code, method, name)

                    yield (request, test)

        return serialize(self.send, work())
Пример #2
0
    def test_DELETE(self):
        """
        DELETE request
        """
        def check_result(response, path):
            response = IResponse(response)

            if response.code != responsecode.NO_CONTENT:
                self.fail("DELETE response %s != %s" % (response.code, responsecode.NO_CONTENT))

            if os.path.exists(path):
                self.fail("DELETE did not remove path %s" % (path,))

        def work():
            for filename in os.listdir(self.docroot):
                path = os.path.join(self.docroot, filename)
                uri = urllib.quote("/" + filename)

                if os.path.isdir(path): uri = uri + "/"

                def do_test(response, path=path):
                    return check_result(response, path)

                request = SimpleRequest(self.site, "DELETE", uri)

                depth = random.choice(("infinity", None))
                if depth is not None:
                    request.headers.setHeader("depth", depth)

                yield (request, do_test)

        return serialize(self.send, work())
Пример #3
0
    def test_GET_REPORT(self):
        """
        Verify access controls during GET and REPORT.
        """
        def work():
            for method in ("GET", "REPORT"):
                if method == "GET":
                    ok = responsecode.OK
                elif method == "REPORT":
                    ok = responsecode.MULTI_STATUS
                else:
                    raise AssertionError("We shouldn't be here.  (method = %r)" % (method,))

                for name, code in (
                    ("none"       , responsecode.FORBIDDEN),
                    ("read"       , ok),
                    ("read-write" , ok),
                    ("unlock"     , responsecode.FORBIDDEN),
                    ("all"        , ok),
                ):
                    path = os.path.join(self.docroot, name)

                    request = SimpleRequest(self.site, method, "/" + name)
                    if method == "REPORT":
                        request.stream = MemoryStream(element.PrincipalPropertySearch().toxml())

                    _add_auth_header(request)

                    def test(response, code=code, path=path):
                        if response.code != code:
                            return self.oops(request, response, code, method, name)

                    yield (request, test)

        return serialize(self.send, work())
Пример #4
0
    def test_MOVE_create(self):
        """
        MOVE to new resource.
        """
        def test(response, path, isfile, sum, uri, depth, dst_path):
            if response.code != responsecode.CREATED:
                self.fail("Incorrect response code for MOVE %s: %s != %s"
                          % (uri, response.code, responsecode.CREATED))

            if response.headers.getHeader("location") is None:
                self.fail("Reponse to MOVE %s with CREATE status is missing location: header."
                          % (uri,))

            if isfile:
                if not os.path.isfile(dst_path):
                    self.fail("MOVE %s produced no output file" % (uri,))
                if sum != sumFile(dst_path):
                    self.fail("MOVE %s produced different file" % (uri,))
            else:
                if not os.path.isdir(dst_path):
                    self.fail("MOVE %s produced no output directory" % (uri,))
                if sum != sumFile(dst_path):
                    self.fail("isdir %s produced different directory" % (uri,))

        return serialize(self.send, work(self, test))
Пример #5
0
    def test_DELETE(self):
        """
        Verify access controls during DELETE.
        """
        def work():
            for name, code in (
                ("nobind" , responsecode.FORBIDDEN),
                ("bind"   , responsecode.FORBIDDEN),
                ("unbind" , responsecode.NO_CONTENT),
            ):
                collection_path = os.path.join(self.docroot, name)
                path = os.path.join(collection_path, "dst")

                file(path, "w").close()

                request = SimpleRequest(self.site, "DELETE", "/" + name + "/dst")
                _add_auth_header(request)

                def test(response, code=code, path=path):
                    if response.code != code:
                        return self.oops(request, response, code, "DELETE", name)

                yield (request, test)

        return serialize(self.send, work())
Пример #6
0
    def test_PROPPATCH(self):
        """
        Verify access controls during PROPPATCH.
        """
        def work():
            for name, code in (
                ("none"       , responsecode.FORBIDDEN),
                ("read"       , responsecode.FORBIDDEN),
                ("read-write" , responsecode.MULTI_STATUS),
                ("unlock"     , responsecode.FORBIDDEN),
                ("all"        , responsecode.MULTI_STATUS),
            ):
                path = os.path.join(self.docroot, name)

                request = SimpleRequest(self.site, "PROPPATCH", "/" + name)
                request.stream = MemoryStream(
                    element.WebDAVDocument(element.PropertyUpdate()).toxml()
                )
                _add_auth_header(request)

                def test(response, code=code, path=path):
                    if response.code != code:
                        return self.oops(request, response, code, "PROPPATCH", name)

                yield (request, test)

        return serialize(self.send, work())
Пример #7
0
    def test_COPY_MOVE_dest(self):
        """
        Verify destination access controls during COPY and MOVE.
        """
        def work():
            src_path = os.path.join(self.docroot, "read")
            uri = "/" + os.path.basename(src_path)

            for method in ("COPY", "MOVE"):
                for name, code in (
                    ("nobind" , responsecode.FORBIDDEN),
                    ("bind"   , responsecode.CREATED),
                    ("unbind" , responsecode.CREATED),
                ):
                    dst_parent_path = os.path.join(self.docroot, name)
                    dst_path = os.path.join(dst_parent_path, "dst")

                    request = SimpleRequest(self.site, method, uri)
                    request.headers.setHeader("destination", "/" + name + "/dst")
                    _add_auth_header(request)

                    def test(response, code=code, dst_path=dst_path):
                        if os.path.isfile(dst_path):
                            os.remove(dst_path)

                        if response.code != code:
                            return self.oops(request, response, code, method, name)

                    yield (request, test)
                    self.restore()

        return serialize(self.send, work())
Пример #8
0
    def test_COPY_MOVE_source(self):
        """
        Verify source access controls during COPY and MOVE.
        """
        def work():
            dst_path = os.path.join(self.docroot, "copy_dst")
            dst_uri = "/" + os.path.basename(dst_path)

            for src, status in (
                ("nobind", responsecode.FORBIDDEN),
                ("bind",   responsecode.FORBIDDEN),
                ("unbind", responsecode.CREATED),
            ):
                src_path = os.path.join(self.docroot, "src_" + src)
                src_uri = "/" + os.path.basename(src_path)
                if not os.path.isdir(src_path):
                    os.mkdir(src_path)
                src_resource = self.resource_class(src_path)
                src_resource.setAccessControlList({
                    "nobind": self.grant(),
                    "bind"  : self.grant(element.Bind()),
                    "unbind": self.grant(element.Bind(), element.Unbind())
                }[src])
                for name, acl in (
                    ("none"       , self.grant()),
                    ("read"       , self.grant(element.Read())),
                    ("read-write" , self.grant(element.Read(), element.Write())),
                    ("unlock"     , self.grant(element.Unlock())),
                    ("all"        , self.grant(element.All())),
                ):
                    filename = os.path.join(src_path, name)
                    if not os.path.isfile(filename):
                        file(filename, "w").close()
                    self.resource_class(filename).setAccessControlList(acl)

                for method in ("COPY", "MOVE"):
                    for name, code in (
                        ("none"       , {"COPY": responsecode.FORBIDDEN, "MOVE": status}[method]),
                        ("read"       , {"COPY": responsecode.CREATED,   "MOVE": status}[method]),
                        ("read-write" , {"COPY": responsecode.CREATED,   "MOVE": status}[method]),
                        ("unlock"     , {"COPY": responsecode.FORBIDDEN, "MOVE": status}[method]),
                        ("all"        , {"COPY": responsecode.CREATED,   "MOVE": status}[method]),
                    ):
                        path = os.path.join(src_path, name)
                        uri = src_uri + "/" + name
    
                        request = SimpleRequest(self.site, method, uri)
                        request.headers.setHeader("destination", dst_uri)
                        _add_auth_header(request)
    
                        def test(response, code=code, path=path):
                            if os.path.isfile(dst_path):
                                os.remove(dst_path)
    
                            if response.code != code:
                                return self.oops(request, response, code, method, name)
    
                        yield (request, test)

        return serialize(self.send, work())
Пример #9
0
    def test_MOVE_no_parent(self):
        """
        MOVE to resource with no parent.
        """
        def test(response, path, isfile, sum, uri, depth, dst_path):
            if response.code != responsecode.CONFLICT:
                self.fail("Incorrect response code for MOVE with no parent %s: %s != %s"
                          % (uri, response.code, responsecode.CONFLICT))
            else:
                # FIXME: Check XML error code (2518bis)
                pass

        return serialize(self.send, work(self, test, dst=os.path.join(self.docroot, "elvislives!")))
Пример #10
0
    def test_MOVE_overwrite(self):
        """
        MOVE to existing resource with overwrite header.
        """
        def test(response, path, isfile, sum, uri, depth, dst_path):
            if response.code != responsecode.NO_CONTENT:
                self.fail("Incorrect response code for MOVE with overwrite %s: %s != %s"
                          % (uri, response.code, responsecode.NO_CONTENT))
            else:
                # FIXME: Check XML error code (2518bis)
                pass

        return serialize(self.send, work(self, test, overwrite=True))
Пример #11
0
    def test_MOVE_exists(self):
        """
        MOVE to existing resource.
        """
        def test(response, path, isfile, sum, uri, depth, dst_path):
            if response.code != responsecode.PRECONDITION_FAILED:
                self.fail("Incorrect response code for MOVE without overwrite %s: %s != %s"
                          % (uri, response.code, responsecode.PRECONDITION_FAILED))
            else:
                # FIXME: Check XML error code (2518bis)
                pass

        return serialize(self.send, work(self, test, overwrite=False))
Пример #12
0
    def test_PUT_simple(self):
        """
        PUT request
        """
        dst_path = os.path.join(self.docroot, "dst")

        def checkResult(response, path):
            response = IResponse(response)

            if response.code not in (
                responsecode.CREATED,
                responsecode.NO_CONTENT
            ):
                self.fail("PUT failed: %s" % (response.code,))

            if not os.path.isfile(dst_path):
                self.fail("PUT failed to create file %s." % (dst_path,))

            if not filecmp.cmp(path, dst_path):
                self.fail("PUT failed to preserve data for file %s in file %s." % (path, dst_path))

            etag = response.headers.getHeader("etag")
            if not etag:
                self.fail("No etag header in PUT response %r." % (response,))

        #
        # We need to serialize these request & test iterations because they can
        # interfere with each other.
        #
        def work():
            dst_uri = "/dst"

            for name in os.listdir(self.docroot):
                if name == "dst":
                    continue

                path = os.path.join(self.docroot, name)

                # Can't really PUT something you can't read
                if not os.path.isfile(path): continue
    
                def do_test(response): checkResult(response, path)
    
                request = SimpleRequest(self.site, "PUT", dst_uri)
                request.stream = FileStream(file(path, "rb"))
    
                yield (request, do_test)

        return serialize(self.send, work())
Пример #13
0
    def test_COPY_overwrite(self):
        """
        COPY to existing resource with overwrite header.
        """
        def test(response, path, isfile, sum, uri, depth, dst_path):
            if response.code != responsecode.NO_CONTENT:
                self.fail("Incorrect response code for COPY with overwrite %s: %s != %s"
                          % (uri, response.code, responsecode.NO_CONTENT))
            else:
                # FIXME: Check XML error code (2518bis)
                pass

            self.failUnless(os.path.exists(dst_path), "COPY didn't produce file: %s" % (dst_path,))

        return serialize(self.send, work(self, test, overwrite=True))
Пример #14
0
    def test_COPY_create(self):
        """
        COPY to new resource.
        """
        def test(response, path, isfile, sum, uri, depth, dst_path):
            if response.code != responsecode.CREATED:
                self.fail("Incorrect response code for COPY %s (depth=%r): %s != %s"
                          % (uri, depth, response.code, responsecode.CREATED))

            if response.headers.getHeader("location") is None:
                self.fail("Reponse to COPY %s (depth=%r) with CREATE status is missing location: header."
                          % (uri, depth))

            if os.path.isfile(path):
                if not os.path.isfile(dst_path):
                    self.fail("COPY %s (depth=%r) produced no output file" % (uri, depth))
                if not cmp(path, dst_path):
                    self.fail("COPY %s (depth=%r) produced different file" % (uri, depth))
                os.remove(dst_path)

            elif os.path.isdir(path):
                if not os.path.isdir(dst_path):
                    self.fail("COPY %s (depth=%r) produced no output directory" % (uri, depth))

                if depth in ("infinity", None):
                    if dircmp(path, dst_path):
                        self.fail("COPY %s (depth=%r) produced different directory" % (uri, depth))

                elif depth == "0":
                    for filename in os.listdir(dst_path):
                        self.fail("COPY %s (depth=%r) shouldn't copy directory contents (eg. %s)" % (uri, depth, filename))

                else: raise AssertionError("Unknown depth: %r" % (depth,))

                rmdir(dst_path)

            else:
                self.fail("Source %s is neither a file nor a directory"
                          % (path,))

        return serialize(self.send, work(self, test))
Пример #15
0
    def test_PUT_again(self):
        """
        PUT on existing resource with If-None-Match header
        """
        dst_path = os.path.join(self.docroot, "dst")
        dst_uri = "/dst"

        def work():
            for code in (
                responsecode.CREATED,
                responsecode.PRECONDITION_FAILED,
                responsecode.NO_CONTENT,
                responsecode.PRECONDITION_FAILED,
                responsecode.NO_CONTENT,
                responsecode.CREATED,
            ):
                def checkResult(response, code=code):
                    response = IResponse(response)

                    if response.code != code:
                        self.fail("Incorrect response code for PUT (%s != %s)"
                                  % (response.code, code))

                def onError(f):
                    f.trap(HTTPError)
                    return checkResult(f.value.response)

                request = SimpleRequest(self.site, "PUT", dst_uri)
                request.stream = FileStream(file(__file__, "rb"))
    
                if code == responsecode.CREATED:
                    if os.path.isfile(dst_path):
                        os.remove(dst_path)
                    request.headers.setHeader("if-none-match", ("*",))
                elif code == responsecode.PRECONDITION_FAILED:
                    request.headers.setHeader("if-none-match", ("*",))
    
                yield (request, (checkResult, onError))

        return serialize(self.send, work())
Пример #16
0
    def test_PUT_exists(self):
        """
        Verify access controls during PUT of existing file.
        """
        def work():
            for name, code in (
                ("none"       , responsecode.FORBIDDEN),
                ("read"       , responsecode.FORBIDDEN),
                ("read-write" , responsecode.NO_CONTENT),
                ("unlock"     , responsecode.FORBIDDEN),
                ("all"        , responsecode.NO_CONTENT),
            ):
                path = os.path.join(self.docroot, name)

                request = SimpleRequest(self.site, "PUT", "/" + name)
                _add_auth_header(request)

                def test(response, code=code, path=path):
                    if response.code != code:
                        return self.oops(request, response, code, "PUT", name)

                yield (request, test)

        return serialize(self.send, work())
Пример #17
0
    def test_PROPFIND_list(self):
        """
        PROPFIND with allprop, propname
        """
        def check_result(which):
            def _check_result(response):
                response = IResponse(response)

                if response.code != responsecode.MULTI_STATUS:
                    self.fail("Incorrect response code for PROPFIND (%s != %s)"
                              % (response.code, responsecode.MULTI_STATUS))

                return davXMLFromStream(response.stream).addCallback(check_xml, which)
            return _check_result

        def check_xml(doc, which):
            response = doc.root_element.childOfType(davxml.PropertyStatusResponse)

            self.failUnless(
                response.childOfType(davxml.HRef) == "/",
                "Incorrect response URI: %s != /" % (response.childOfType(davxml.HRef),)
            )

            for propstat in response.childrenOfType(davxml.PropertyStatus):
                status = propstat.childOfType(davxml.Status)
                properties = propstat.childOfType(davxml.PropertyContainer).children

                if status.code != responsecode.OK:
                    self.fail("PROPFIND failed (status %s) to locate live properties: %s"
                              % (status.code, properties))

                if which.name == "allprop":
                    properties_to_find = [p.qname() for p in self.liveProperties() if not p.hidden]
                else:
                    properties_to_find = [p.qname() for p in self.liveProperties()]

                for property in properties:
                    qname = property.qname()
                    if qname in properties_to_find:
                        properties_to_find.remove(qname)
                    elif qname[0] != dav_namespace:
                        pass
                    else:
                        self.fail("PROPFIND with %s found property we didn't expect: %r" % (which.name, property))

                    if which.name == "propname":
                        # Element should be empty
                        self.failUnless(len(property.children) == 0)
                    else:
                        # Element should have a value, unless the property exists and is empty...
                        # Verify that there is a value for live properties for which we know
                        # that this should be the case.
                        if property.namespace == dav_namespace and property.name in (
                            "getetag",
                            "getcontenttype",
                            "getlastmodified",
                            "creationdate",
                            "displayname",
                        ):
                            self.failIf(
                                len(property.children) == 0,
                                "Property has no children: %r" % (property.toxml(),)
                            )

                if properties_to_find:
                    self.fail("PROPFIND with %s failed to find properties: %r" % (which.name, properties_to_find))

            properties = propstat.childOfType(davxml.PropertyContainer).children

        def work():
            for which in (davxml.AllProperties(), davxml.PropertyName()):
                query = davxml.PropertyFind(which)

                request = SimpleRequest(self.site, "PROPFIND", "/")
                request.headers.setHeader("depth", "0")
                request.stream = MemoryStream(query.toxml())

                yield (request, check_result(which))

        return serialize(self.send, work())