예제 #1
0
    def createDocumentRoot(self):
        docroot = self.mktemp()
        os.mkdir(docroot)

        userResource = TestDAVPrincipalResource("/principals/users/user01")
        userResource.writeDeadProperty(TwistedPasswordProperty("user01"))

        principalCollection = TestPrincipalsCollection(
            "/principals/",
            children={"users": TestPrincipalsCollection(
                    "/principals/users/",
                    children={"user01": userResource})})

        rootResource = self.resource_class(
            docroot, principalCollections=(principalCollection,))

        portal = Portal(DavRealm())
        portal.registerChecker(TwistedPropertyChecker())

        credentialFactories = (basic.BasicCredentialFactory(""),)

        loginInterfaces = (IPrincipal,)

        self.site = Site(AuthenticationWrapper(
            rootResource,
            portal,
            credentialFactories,
            credentialFactories,
            loginInterfaces
        ))

        rootResource.setAccessControlList(self.grant(element.All()))

        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(docroot, name)
            if not os.path.isfile(filename):
                file(filename, "w").close()
            resource = self.resource_class(filename)
            resource.setAccessControlList(acl)

        for name, acl in (
            ("nobind" , self.grant()),
            ("bind"   , self.grant(element.Bind())),
            ("unbind" , self.grant(element.Bind(), element.Unbind())),
        ):
            dirname = os.path.join(docroot, name)
            if not os.path.isdir(dirname):
                os.mkdir(dirname)
            resource = self.resource_class(dirname)
            resource.setAccessControlList(acl)
        return docroot
예제 #2
0
        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)
예제 #3
0
    def test_Privilege_isAggregateOf(self):
        """
        Privilege.isAggregateOf()
        """
        for a, b in (
            (davxml.All(), davxml.Write()),
            (davxml.All(), davxml.ReadACL()),
            (davxml.Write(), davxml.WriteProperties()),
            (davxml.Write(), davxml.WriteContent()),
            (davxml.Write(), davxml.Bind()),
            (davxml.Write(), davxml.Unbind()),
        ):
            pa = davxml.Privilege(a)
            pb = davxml.Privilege(b)

            self.failUnless(pa.isAggregateOf(pb, davPrivilegeSet),
                            "%s contains %s" % (a.sname(), b.sname()))
            self.failIf(pb.isAggregateOf(pa, davPrivilegeSet),
                        "%s does not contain %s" % (b.sname(), a.sname()))

        for a, b in (
            (davxml.Unlock(), davxml.Write()),
            (davxml.Unlock(), davxml.WriteACL()),
            (davxml.ReadCurrentUserPrivilegeSet(), davxml.WriteProperties()),
        ):
            pa = davxml.Privilege(a)
            pb = davxml.Privilege(b)

            self.failIf(pb.isAggregateOf(pa, davPrivilegeSet),
                        "%s does not contain %s" % (b.sname(), a.sname()))
예제 #4
0
def http_MKCOL(self, request):
    """
    Respond to a MKCOL request. (RFC 2518, section 8.3)
    """
    parent = waitForDeferred(request.locateResource(parentForURL(request.uri)))
    yield parent
    parent = parent.getResult()

    x = waitForDeferred(parent.authorize(request, (davxml.Bind(), )))
    yield x
    x.getResult()

    if self.exists():
        log.error("Attempt to create collection where file exists: %s" %
                  (self, ))
        raise HTTPError(responsecode.NOT_ALLOWED)

    if not parent.isCollection():
        log.error(
            "Attempt to create collection with non-collection parent: %s" %
            (self, ))
        raise HTTPError(
            StatusResponse(responsecode.CONFLICT,
                           "Parent resource is not a collection."))

    #
    # Read request body
    #
    x = waitForDeferred(noDataFromStream(request.stream))
    yield x
    try:
        x.getResult()
    except ValueError, e:
        log.error("Error while handling MKCOL body: %s" % (e, ))
        raise HTTPError(responsecode.UNSUPPORTED_MEDIA_TYPE)
예제 #5
0
def http_PROPFIND(self, request):
    """
    Respond to a PROPFIND request. (RFC 2518, section 8.1)
    """
    if not self.exists():
        # Return 403 if parent does not allow Bind
        parentURL = parentForURL(request.uri)
        parent = (yield request.locateResource(parentURL))
        yield parent.authorize(request, (davxml.Bind(), ))

        log.error("Resource not found: %s" % (self, ))
        raise HTTPError(responsecode.NOT_FOUND)

    #
    # Check authentication and access controls
    #
    yield self.authorize(request, (davxml.Read(), ))

    #
    # Read request body
    #
    try:
        doc = (yield davXMLFromStream(request.stream))
    except ValueError, e:
        log.error("Error while handling PROPFIND body: %s" % (e, ))
        raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
예제 #6
0
파일: get.py 프로젝트: gingerkaan/serveros
def authorize(self, request):
    if self.exists():
        d = self.authorize(request, (davxml.Read(), ))
    else:
        d = request.locateResource(parentForURL(request.uri))
        d.addCallback(lambda parent: parent.authorize(request,
                                                      (davxml.Bind(), )))
    return d
예제 #7
0
def http_COPY(self, request):
    """
    Respond to a COPY request. (RFC 2518, section 8.8)
    """
    r = waitForDeferred(prepareForCopy(self, request))
    yield r
    r = r.getResult()

    destination, destination_uri, depth = r

    #
    # Check authentication and access controls
    #
    x = waitForDeferred(
        self.authorize(request, (davxml.Read(), ), recurse=True))
    yield x
    x.getResult()

    if destination.exists():
        x = waitForDeferred(
            destination.authorize(
                request, (davxml.WriteContent(), davxml.WriteProperties()),
                recurse=True))
        yield x
        x.getResult()
    else:
        destparent = waitForDeferred(
            request.locateResource(parentForURL(destination_uri)))
        yield destparent
        destparent = destparent.getResult()

        x = waitForDeferred(destparent.authorize(request, (davxml.Bind(), )))
        yield x
        x.getResult()

        # May need to add a location header
        addLocation(request, destination_uri)

    # x = waitForDeferred(copy(self.fp, destination.fp, destination_uri, depth))
    x = waitForDeferred(
        put_common.storeResource(request,
                                 source=self,
                                 source_uri=request.uri,
                                 destination=destination,
                                 destination_uri=destination_uri,
                                 deletesource=False,
                                 depth=depth))
    yield x
    yield x.getResult()
예제 #8
0
def preconditions_PUT(self, request):
    #
    # Check authentication and access controls
    #
    if self.exists():
        x = waitForDeferred(self.authorize(request, (davxml.WriteContent(), )))
        yield x
        x.getResult()
    else:
        parent = waitForDeferred(
            request.locateResource(parentForURL(request.uri)))
        yield parent
        parent = parent.getResult()

        if not parent.exists():
            raise HTTPError(
                StatusResponse(responsecode.CONFLICT,
                               "cannot PUT to non-existent parent"))
        x = waitForDeferred(parent.authorize(request, (davxml.Bind(), )))
        yield x
        x.getResult()

    #
    # HTTP/1.1 (RFC 2068, section 9.6) requires that we respond with a Not
    # Implemented error if we get a Content-* header which we don't
    # recognize and handle properly.
    #
    for header, _ignore_value in request.headers.getAllRawHeaders():
        if header.startswith("Content-") and header not in (
                # "Content-Base",     # Doesn't make sense in PUT?
                # "Content-Encoding", # Requires that we decode it?
                "Content-Language",
                "Content-Length",
                # "Content-Location", # Doesn't make sense in PUT?
                "Content-MD5",
                # "Content-Range",    # FIXME: Need to implement this
                "Content-Type",
        ):
            log.error(
                "Client sent unrecognized content header in PUT request: %s" %
                (header, ))
            raise HTTPError(
                StatusResponse(
                    responsecode.NOT_IMPLEMENTED,
                    "Unrecognized content header %r in request." % (header, )))
예제 #9
0
def http_MKCALENDAR(self, request):
    """
    Respond to a MKCALENDAR request.
    (CalDAV-access-09, section 5.3.1)
    """

    #
    # Check authentication and access controls
    #
    parent = (yield request.locateResource(parentForURL(request.uri)))
    yield parent.authorize(request, (davxml.Bind(), ))

    if self.exists():
        log.error("Attempt to create collection where resource exists: %s" %
                  (self, ))
        raise HTTPError(
            ErrorResponse(
                responsecode.FORBIDDEN,
                (davxml.dav_namespace, "resource-must-be-null"),
                "Resource already exists",
            ))

    if not parent.isCollection():
        log.error(
            "Attempt to create collection with non-collection parent: %s" %
            (self, ))
        raise HTTPError(
            ErrorResponse(
                responsecode.CONFLICT,
                (caldavxml.caldav_namespace,
                 "calendar-collection-location-ok"),
                "Cannot create calendar inside another calendar",
            ))

    #
    # Read request body
    #
    try:
        doc = (yield davXMLFromStream(request.stream))
        yield self.createCalendar(request)
    except ValueError, e:
        log.error("Error while handling MKCALENDAR: %s" % (e, ))
        raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
예제 #10
0
def http_MKCOL(self, request):

    #
    # Check authentication and access controls
    #
    parent = (yield request.locateResource(parentForURL(request.uri)))

    yield parent.authorize(request, (davxml.Bind(), ))

    if self.exists():
        log.error("Attempt to create collection where resource exists: {s!r}",
                  s=self)
        raise HTTPError(
            ErrorResponse(
                responsecode.FORBIDDEN,
                (davxml.dav_namespace, "resource-must-be-null"),
                "Resource already exists",
            ))

    if not parent.isCollection():
        log.error(
            "Attempt to create collection with non-collection parent: {s!r}",
            s=self)
        raise HTTPError(
            ErrorResponse(
                responsecode.CONFLICT,
                (davxml.dav_namespace, "collection-location-ok"),
                "Cannot create calendar inside another calendar",
            ))

    #
    # Don't allow DAV collections in a calendar or address book collection
    #

    if config.EnableCalDAV:
        parent = (yield self._checkParents(request,
                                           isPseudoCalendarCollectionResource))

        if parent is not None:
            raise HTTPError(
                StatusResponse(
                    responsecode.FORBIDDEN,
                    "Cannot create collection within calendar collection %s" %
                    (parent, )))

    if config.EnableCardDAV:
        parent = (yield self._checkParents(request,
                                           isAddressBookCollectionResource))

        if parent is not None:
            raise HTTPError(
                StatusResponse(
                    responsecode.FORBIDDEN,
                    "Cannot create collection within address book collection %s"
                    % (parent, )))

    #
    # Read request body
    #
    try:
        doc = (yield davXMLFromStream(request.stream))
    except ValueError, e:
        log.error("Error while handling MKCOL: {ex}", ex=e)
        # TODO: txweb2.dav 'MKCOL' tests demand this particular response
        # code, but should we really be looking at the XML content or the
        # content-type header?  It seems to me like this ought to be considered
        # a BAD_REQUEST if it claims to be XML but isn't, but an
        # UNSUPPORTED_MEDIA_TYPE if it claims to be something else. -glyph
        raise HTTPError(
            StatusResponse(responsecode.UNSUPPORTED_MEDIA_TYPE, str(e)))
예제 #11
0
def http_MOVE(self, request):
    """
    Respond to a MOVE request. (RFC 2518, section 8.9)
    """
    r = waitForDeferred(prepareForCopy(self, request))
    yield r
    r = r.getResult()

    destination, destination_uri, depth = r

    #
    # Check authentication and access controls
    #
    parentURL = parentForURL(request.uri)
    parent = waitForDeferred(request.locateResource(parentURL))
    yield parent
    parent = parent.getResult()

    x = waitForDeferred(parent.authorize(request, (davxml.Unbind(), )))
    yield x
    x.getResult()

    if destination.exists():
        x = waitForDeferred(
            destination.authorize(request, (davxml.Bind(), davxml.Unbind()),
                                  recurse=True))
        yield x
        x.getResult()
    else:
        destparentURL = parentForURL(destination_uri)
        destparent = waitForDeferred(request.locateResource(destparentURL))
        yield destparent
        destparent = destparent.getResult()

        x = waitForDeferred(destparent.authorize(request, (davxml.Bind(), )))
        yield x
        x.getResult()

        # May need to add a location header
        addLocation(request, destination_uri)

    #
    # RFC 2518, section 8.9 says that we must act as if the Depth header is set
    # to infinity, and that the client must omit the Depth header or set it to
    # infinity.
    #
    # This seems somewhat at odds with the notion that a bad request should be
    # rejected outright; if the client sends a bad depth header, the client is
    # broken, and section 8 suggests that a bad request should be rejected...
    #
    # Let's play it safe for now and ignore broken clients.
    #
    if self.isCollection() and depth != "infinity":
        msg = "Client sent illegal depth header value for MOVE: %s" % (depth, )
        log.error(msg)
        raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, msg))

    # Lets optimise a move within the same directory to a new resource as a simple move
    # rather than using the full transaction based storeResource api. This allows simple
    # "rename" operations to work quickly.
    if (not destination.exists()) and destparent == parent:
        x = waitForDeferred(
            move(self.fp, request.uri, destination.fp, destination_uri, depth))
    else:
        x = waitForDeferred(
            put_common.storeResource(request,
                                     source=self,
                                     source_uri=request.uri,
                                     destination=destination,
                                     destination_uri=destination_uri,
                                     deletesource=True,
                                     depth=depth))
    yield x
    yield x.getResult()