Exemple #1
0
    def check_write_permission(self, url, depth, tokenList, principal):
        """Check, if <principal> can modify <url>, otherwise raise HTTP_LOCKED.

        If modifying <url> is prevented by a lock, DAVError(HTTP_LOCKED) is
        raised. An embedded DAVErrorCondition contains the conflicting locks.

        <url> may be modified by <principal>, if it is not currently locked
        directly or indirectly (i.e. by a locked parent).
        For depth-infinity operations, <url> also must not have locked children.

        It is not enough to check whether a lock is owned by <principal>, but
        also the token must be passed with the request. Because <principal> may
        run two different applications.

        See http://www.webdav.org/specs/rfc4918.html#lock-model
            http://www.webdav.org/specs/rfc4918.html#rfc.section.7.4

        TODO: verify assumptions:
        - Parent locks WILL NOT be conflicting, if they are depth-0.
        - Exclusive child locks WILL be conflicting, even if they are owned by <principal>.

        @param url: URL that shall be modified, created, moved, or deleted
        @param depth: "0"|"infinity"
        @param tokenList: list of lock tokens, that the principal submitted in If: header
        @param principal: name of the principal requesting a lock

        @return: None or raise error
        """
        assert compat.is_native(url)
        assert depth in ("0", "infinity")
        _logger.debug("check_write_permission({}, {}, {}, {})".format(
            url, depth, tokenList, principal))

        # Error precondition to collect conflicting URLs
        errcond = DAVErrorCondition(PRECONDITION_CODE_LockConflict)

        self._lock.acquire_read()
        try:
            # Check url and all parents for conflicting locks
            u = url
            while u:
                ll = self.get_url_lock_list(u)
                _logger.debug("  checking {}".format(u))
                for l in ll:
                    _logger.debug("     l={}".format(lock_string(l)))
                    if u != url and l["depth"] != "infinity":
                        # We only consider parents with Depth: inifinity
                        continue
                    elif principal == l["principal"] and l[
                            "token"] in tokenList:
                        # User owns this lock
                        continue
                    else:
                        # Token is owned by principal, but not passed with lock list
                        _logger.debug(
                            " -> DENIED due to locked parent {}".format(
                                lock_string(l)))
                        errcond.add_href(l["root"])
                u = util.get_uri_parent(u)

            if depth == "infinity":
                # Check child URLs for conflicting locks
                childLocks = self.storage.get_lock_list(url,
                                                        includeRoot=False,
                                                        includeChildren=True,
                                                        tokenOnly=False)

                for l in childLocks:
                    assert util.is_child_uri(url, l["root"])
                    #                    if util.is_child_uri(url, l["root"]):
                    _logger.debug(" -> DENIED due to locked child {}".format(
                        lock_string(l)))
                    errcond.add_href(l["root"])
        finally:
            self._lock.release()

        # If there were conflicts, raise HTTP_LOCKED for <url>, and pass
        # conflicting resource with 'no-conflicting-lock' precondition
        if len(errcond.hrefs) > 0:
            raise DAVError(HTTP_LOCKED, errcondition=errcond)
        return
Exemple #2
0
    def check_write_permission(self, url, depth, token_list, principal):
        """Check, if <principal> can modify <url>, otherwise raise HTTP_LOCKED.

        If modifying <url> is prevented by a lock, DAVError(HTTP_LOCKED) is
        raised. An embedded DAVErrorCondition contains the conflicting locks.

        <url> may be modified by <principal>, if it is not currently locked
        directly or indirectly (i.e. by a locked parent).
        For depth-infinity operations, <url> also must not have locked children.

        It is not enough to check whether a lock is owned by <principal>, but
        also the token must be passed with the request. Because <principal> may
        run two different applications.

        See http://www.webdav.org/specs/rfc4918.html#lock-model
            http://www.webdav.org/specs/rfc4918.html#rfc.section.7.4

        TODO: verify assumptions:
        - Parent locks WILL NOT be conflicting, if they are depth-0.
        - Exclusive child locks WILL be conflicting, even if they are owned by <principal>.

        @param url: URL that shall be modified, created, moved, or deleted
        @param depth: "0"|"infinity"
        @param token_list: list of lock tokens, that the principal submitted in If: header
        @param principal: name of the principal requesting a lock

        @return: None or raise error
        """
        assert compat.is_native(url)
        assert depth in ("0", "infinity")
        _logger.debug(
            "check_write_permission({}, {}, {}, {})".format(
                url, depth, token_list, principal
            )
        )

        # Error precondition to collect conflicting URLs
        errcond = DAVErrorCondition(PRECONDITION_CODE_LockConflict)

        self._lock.acquire_read()
        try:
            # Check url and all parents for conflicting locks
            u = url
            while u:
                ll = self.get_url_lock_list(u)
                _logger.debug("  checking {}".format(u))
                for l in ll:
                    _logger.debug("     l={}".format(lock_string(l)))
                    if u != url and l["depth"] != "infinity":
                        # We only consider parents with Depth: inifinity
                        continue
                    elif principal == l["principal"] and l["token"] in token_list:
                        # User owns this lock
                        continue
                    else:
                        # Token is owned by principal, but not passed with lock list
                        _logger.debug(
                            " -> DENIED due to locked parent {}".format(lock_string(l))
                        )
                        errcond.add_href(l["root"])
                u = util.get_uri_parent(u)

            if depth == "infinity":
                # Check child URLs for conflicting locks
                childLocks = self.storage.get_lock_list(
                    url, include_root=False, include_children=True, token_only=False
                )

                for l in childLocks:
                    assert util.is_child_uri(url, l["root"])
                    #                    if util.is_child_uri(url, l["root"]):
                    _logger.debug(
                        " -> DENIED due to locked child {}".format(lock_string(l))
                    )
                    errcond.add_href(l["root"])
        finally:
            self._lock.release()

        # If there were conflicts, raise HTTP_LOCKED for <url>, and pass
        # conflicting resource with 'no-conflicting-lock' precondition
        if len(errcond.hrefs) > 0:
            raise DAVError(HTTP_LOCKED, err_condition=errcond)
        return
Exemple #3
0
    def _check_lock_permission(self, url, locktype, lockscope, lockdepth,
                               tokenList, principal):
        """Check, if <principal> can lock <url>, otherwise raise an error.

        If locking <url> would create a conflict, DAVError(HTTP_LOCKED) is
        raised. An embedded DAVErrorCondition contains the conflicting resource.

        @see http://www.webdav.org/specs/rfc4918.html#lock-model

        - Parent locks WILL NOT be conflicting, if they are depth-0.
        - Exclusive depth-infinity parent locks WILL be conflicting, even if
          they are owned by <principal>.
        - Child locks WILL NOT be conflicting, if we request a depth-0 lock.
        - Exclusive child locks WILL be conflicting, even if they are owned by
          <principal>. (7.7)
        - It is not enough to check whether a lock is owned by <principal>, but
          also the token must be passed with the request. (Because <principal>
          may run two different applications on his client.)
        - <principal> cannot lock-exclusive, if he holds a parent shared-lock.
          (This would only make sense, if he was the only shared-lock holder.)
        - TODO: litmus tries to acquire a shared lock on one resource twice
          (locks: 27 'double_sharedlock') and fails, when we return HTTP_LOCKED.
          So we allow multi shared locks on a resource even for the same
          principal.

        @param url: URL that shall be locked
        @param locktype: "write"
        @param lockscope: "shared"|"exclusive"
        @param lockdepth: "0"|"infinity"
        @param tokenList: list of lock tokens, that the user submitted in If: header
        @param principal: name of the principal requesting a lock

        @return: None (or raise)
        """
        assert locktype == "write"
        assert lockscope in ("shared", "exclusive")
        assert lockdepth in ("0", "infinity")

        _logger.debug("checkLockPermission({}, {}, {}, {})".format(
            url, lockscope, lockdepth, principal))

        # Error precondition to collect conflicting URLs
        errcond = DAVErrorCondition(PRECONDITION_CODE_LockConflict)

        self._lock.acquire_read()
        try:
            # Check url and all parents for conflicting locks
            u = url
            while u:
                ll = self.get_url_lock_list(u)
                for l in ll:
                    _logger.debug("    check parent {}, {}".format(
                        u, lock_string(l)))
                    if u != url and l["depth"] != "infinity":
                        # We only consider parents with Depth: infinity
                        continue
                    elif l["scope"] == "shared" and lockscope == "shared":
                        # Only compatible with shared locks (even by same
                        # principal)
                        continue
                    # Lock conflict
                    _logger.debug(" -> DENIED due to locked parent {}".format(
                        lock_string(l)))
                    errcond.add_href(l["root"])
                u = util.get_uri_parent(u)

            if lockdepth == "infinity":
                # Check child URLs for conflicting locks
                childLocks = self.storage.get_lock_list(url,
                                                        includeRoot=False,
                                                        includeChildren=True,
                                                        tokenOnly=False)

                for l in childLocks:
                    assert util.is_child_uri(url, l["root"])
                    #                    if util.is_child_uri(url, l["root"]):
                    _logger.debug(" -> DENIED due to locked child {}".format(
                        lock_string(l)))
                    errcond.add_href(l["root"])
        finally:
            self._lock.release()

        # If there were conflicts, raise HTTP_LOCKED for <url>, and pass
        # conflicting resource with 'no-conflicting-lock' precondition
        if len(errcond.hrefs) > 0:
            raise DAVError(HTTP_LOCKED, errcondition=errcond)
        return
Exemple #4
0
    def _check_lock_permission(
        self, url, lock_type, lock_scope, lock_depth, token_list, principal
    ):
        """Check, if <principal> can lock <url>, otherwise raise an error.

        If locking <url> would create a conflict, DAVError(HTTP_LOCKED) is
        raised. An embedded DAVErrorCondition contains the conflicting resource.

        @see http://www.webdav.org/specs/rfc4918.html#lock-model

        - Parent locks WILL NOT be conflicting, if they are depth-0.
        - Exclusive depth-infinity parent locks WILL be conflicting, even if
          they are owned by <principal>.
        - Child locks WILL NOT be conflicting, if we request a depth-0 lock.
        - Exclusive child locks WILL be conflicting, even if they are owned by
          <principal>. (7.7)
        - It is not enough to check whether a lock is owned by <principal>, but
          also the token must be passed with the request. (Because <principal>
          may run two different applications on his client.)
        - <principal> cannot lock-exclusive, if he holds a parent shared-lock.
          (This would only make sense, if he was the only shared-lock holder.)
        - TODO: litmus tries to acquire a shared lock on one resource twice
          (locks: 27 'double_sharedlock') and fails, when we return HTTP_LOCKED.
          So we allow multi shared locks on a resource even for the same
          principal.

        @param url: URL that shall be locked
        @param lock_type: "write"
        @param lock_scope: "shared"|"exclusive"
        @param lock_depth: "0"|"infinity"
        @param token_list: list of lock tokens, that the user submitted in If: header
        @param principal: name of the principal requesting a lock

        @return: None (or raise)
        """
        assert lock_type == "write"
        assert lock_scope in ("shared", "exclusive")
        assert lock_depth in ("0", "infinity")

        _logger.debug(
            "checkLockPermission({}, {}, {}, {})".format(
                url, lock_scope, lock_depth, principal
            )
        )

        # Error precondition to collect conflicting URLs
        errcond = DAVErrorCondition(PRECONDITION_CODE_LockConflict)

        self._lock.acquire_read()
        try:
            # Check url and all parents for conflicting locks
            u = url
            while u:
                ll = self.get_url_lock_list(u)
                for l in ll:
                    _logger.debug("    check parent {}, {}".format(u, lock_string(l)))
                    if u != url and l["depth"] != "infinity":
                        # We only consider parents with Depth: infinity
                        continue
                    elif l["scope"] == "shared" and lock_scope == "shared":
                        # Only compatible with shared locks (even by same
                        # principal)
                        continue
                    # Lock conflict
                    _logger.debug(
                        " -> DENIED due to locked parent {}".format(lock_string(l))
                    )
                    errcond.add_href(l["root"])
                u = util.get_uri_parent(u)

            if lock_depth == "infinity":
                # Check child URLs for conflicting locks
                childLocks = self.storage.get_lock_list(
                    url, include_root=False, include_children=True, token_only=False
                )

                for l in childLocks:
                    assert util.is_child_uri(url, l["root"])
                    #                    if util.is_child_uri(url, l["root"]):
                    _logger.debug(
                        " -> DENIED due to locked child {}".format(lock_string(l))
                    )
                    errcond.add_href(l["root"])
        finally:
            self._lock.release()

        # If there were conflicts, raise HTTP_LOCKED for <url>, and pass
        # conflicting resource with 'no-conflicting-lock' precondition
        if len(errcond.hrefs) > 0:
            raise DAVError(HTTP_LOCKED, err_condition=errcond)
        return