Beispiel #1
0
 def _collect_allowed_items(self, items, user):
     """Get items from request that user is allowed to access."""
     for item in items:
         if isinstance(item, storage.BaseCollection):
             path = pathutils.unstrip_path(item.path, True)
             if item.get_meta("tag"):
                 permissions = rights.intersect(
                     self._rights.authorization(user, path), "rw")
                 target = "collection with tag %r" % item.path
             else:
                 permissions = rights.intersect(
                     self._rights.authorization(user, path), "RW")
                 target = "collection %r" % item.path
         else:
             path = pathutils.unstrip_path(item.collection.path, True)
             permissions = rights.intersect(
                 self._rights.authorization(user, path), "rw")
             target = "item %r from %r" % (item.href, item.collection.path)
         if rights.intersect(permissions, "Ww"):
             permission = "w"
             status = "write"
         elif rights.intersect(permissions, "Rr"):
             permission = "r"
             status = "read"
         else:
             permission = ""
             status = "NO"
         logger.debug("%s has %s access to %s",
                      repr(user) if user else "anonymous user", status,
                      target)
         if permission:
             yield item, permission
Beispiel #2
0
 def _access(self, user, path, permission, item=None):
     if permission not in "rw":
         raise ValueError("Invalid permission argument: %r" % permission)
     if not item:
         permissions = permission + permission.upper()
         parent_permissions = permission
     elif isinstance(item, storage.BaseCollection):
         if item.get_meta("tag"):
             permissions = permission
         else:
             permissions = permission.upper()
         parent_permissions = ""
     else:
         permissions = ""
         parent_permissions = permission
     if permissions and rights.intersect(
             self._rights.authorization(user, path), permissions):
         return True
     if parent_permissions:
         parent_path = pathutils.unstrip_path(
             posixpath.dirname(pathutils.strip_path(path)), True)
         if rights.intersect(self._rights.authorization(user, parent_path),
                             parent_permissions):
             return True
     return False
Beispiel #3
0
 def check(self, permission, item=None):
     if permission not in "rw":
         raise ValueError("Invalid permission argument: %r" % permission)
     if not item:
         permissions = permission + permission.upper()
         parent_permissions = permission
     elif isinstance(item, storage.BaseCollection):
         if item.get_meta("tag"):
             permissions = permission
         else:
             permissions = permission.upper()
         parent_permissions = ""
     else:
         permissions = ""
         parent_permissions = permission
     return bool(rights.intersect(self.permissions, permissions) or (
         self.path != self.parent_path and
         rights.intersect(self.parent_permissions, parent_permissions)))
Beispiel #4
0
 def do_MKCOL(self, environ, base_prefix, path, user, context=None):
     """Manage MKCOL request."""
     permissions = self._rights.authorization(user, path)
     if not rights.intersect(permissions, "Ww"):
         return httputils.NOT_ALLOWED
     try:
         xml_content = self._read_xml_request_body(environ)
     except RuntimeError as e:
         logger.warning("Bad MKCOL request on %r: %s",
                        path,
                        e,
                        exc_info=True)
         return httputils.BAD_REQUEST
     except socket.timeout:
         logger.debug("Client timed out", exc_info=True)
         return httputils.REQUEST_TIMEOUT
     # Prepare before locking
     props = xmlutils.props_from_request(xml_content)
     props = {k: v for k, v in props.items() if v is not None}
     try:
         radicale_item.check_and_sanitize_props(props)
     except ValueError as e:
         logger.warning("Bad MKCOL request on %r: %s",
                        path,
                        e,
                        exc_info=True)
         return httputils.BAD_REQUEST
     if (props.get("tag") and "w" not in permissions
             or not props.get("tag") and "W" not in permissions):
         return httputils.NOT_ALLOWED
     with self._storage.acquire_lock("w", user):
         item = next(self._storage.discover(path), None)
         if item:
             return httputils.METHOD_NOT_ALLOWED
         parent_path = pathutils.unstrip_path(
             posixpath.dirname(pathutils.strip_path(path)), True)
         parent_item = next(self._storage.discover(parent_path), None)
         if not parent_item:
             return httputils.CONFLICT
         if (not isinstance(parent_item, storage.BaseCollection)
                 or parent_item.get_meta("tag")):
             return httputils.FORBIDDEN
         try:
             self._storage.create_collection(path, props=props)
         except ValueError as e:
             logger.warning("Bad MKCOL request on %r: %s",
                            path,
                            e,
                            exc_info=True)
             return httputils.BAD_REQUEST
         return client.CREATED, {}, None
Beispiel #5
0
    def do_PUT(self, environ, base_prefix, path, user):
        """Manage PUT request."""
        if not self._access(user, path, "w"):
            return httputils.NOT_ALLOWED
        try:
            content = self._read_content(environ)
        except RuntimeError as e:
            logger.warning("Bad PUT request on %r: %s", path, e, exc_info=True)
            return httputils.BAD_REQUEST
        except socket.timeout:
            logger.debug("client timed out", exc_info=True)
            return httputils.REQUEST_TIMEOUT
        # Prepare before locking
        content_type = environ.get("CONTENT_TYPE", "").split(";")[0]
        parent_path = pathutils.unstrip_path(
            posixpath.dirname(pathutils.strip_path(path)), True)
        permissions = rights.intersect(
            self._rights.authorization(user, path), "Ww")
        parent_permissions = rights.intersect(
            self._rights.authorization(user, parent_path), "w")
        try:
            vobject_items = tuple(vobject.readComponents(content or ""))
        except Exception as e:
            logger.warning(
                "Bad PUT request on %r: %s", path, e, exc_info=True)
            return httputils.BAD_REQUEST
        (prepared_items, prepared_tag, prepared_write_whole_collection,
         prepared_props, prepared_exc_info) = prepare(
             vobject_items, path, content_type, permissions,
             parent_permissions)

        with self._storage.acquire_lock("w", user):
            item = next(self._storage.discover(path), None)
            parent_item = next(self._storage.discover(parent_path), None)
            if not parent_item:
                return httputils.CONFLICT

            write_whole_collection = (
                isinstance(item, storage.BaseCollection) or
                not parent_item.get_meta("tag"))

            if write_whole_collection:
                tag = prepared_tag
            else:
                tag = parent_item.get_meta("tag")

            if write_whole_collection:
                if ("w" if tag else "W") not in self._rights.authorization(
                        user, path):
                    return httputils.NOT_ALLOWED
            elif "w" not in self._rights.authorization(user, parent_path):
                return httputils.NOT_ALLOWED

            etag = environ.get("HTTP_IF_MATCH", "")
            if not item and etag:
                # Etag asked but no item found: item has been removed
                return httputils.PRECONDITION_FAILED
            if item and etag and item.etag != etag:
                # Etag asked but item not matching: item has changed
                return httputils.PRECONDITION_FAILED

            match = environ.get("HTTP_IF_NONE_MATCH", "") == "*"
            if item and match:
                # Creation asked but item found: item can't be replaced
                return httputils.PRECONDITION_FAILED

            if (tag != prepared_tag or
                    prepared_write_whole_collection != write_whole_collection):
                (prepared_items, prepared_tag, prepared_write_whole_collection,
                 prepared_props, prepared_exc_info) = prepare(
                     vobject_items, path, content_type, permissions,
                     parent_permissions, tag, write_whole_collection)
            props = prepared_props
            if prepared_exc_info:
                logger.warning(
                    "Bad PUT request on %r: %s", path, prepared_exc_info[1],
                    exc_info=prepared_exc_info)
                return httputils.BAD_REQUEST

            if write_whole_collection:
                try:
                    etag = self._storage.create_collection(
                        path, prepared_items, props).etag
                except ValueError as e:
                    logger.warning(
                        "Bad PUT request on %r: %s", path, e, exc_info=True)
                    return httputils.BAD_REQUEST
            else:
                prepared_item, = prepared_items
                if (item and item.uid != prepared_item.uid or
                        not item and parent_item.has_uid(prepared_item.uid)):
                    return self._webdav_error_response("%s:no-uid-conflict" % (
                        "C" if tag == "VCALENDAR" else "CR"))

                href = posixpath.basename(pathutils.strip_path(path))
                try:
                    etag = parent_item.upload(href, prepared_item).etag
                except ValueError as e:
                    logger.warning(
                        "Bad PUT request on %r: %s", path, e, exc_info=True)
                    return httputils.BAD_REQUEST

            headers = {"ETag": etag}
            return client.CREATED, headers, None