def report_DAV__principal_search_property_set(self, request,
                                              principal_search_property_set):
    """
    Generate a principal-search-property-set REPORT. (RFC 3744, section 9.5)
    """
    # Verify root element
    if not isinstance(principal_search_property_set,
                      davxml.PrincipalSearchPropertySet):
        raise ValueError("%s expected as root element, not %s." %
                         (davxml.PrincipalSearchPropertySet.sname(),
                          principal_search_property_set.sname()))

    # Only handle Depth: 0
    depth = request.headers.getHeader("depth", "0")
    if depth != "0":
        log.error(
            "Error in principal-search-property-set REPORT, Depth set to %s" %
            (depth, ))
        raise HTTPError(
            StatusResponse(responsecode.BAD_REQUEST,
                           "Depth %s not allowed" % (depth, )))

    # Get details from the resource
    result = self.principalSearchPropertySet()
    if result is None:
        log.error(
            "Error in principal-search-property-set REPORT not supported on: %s"
            % (self, ))
        raise HTTPError(
            StatusResponse(responsecode.BAD_REQUEST,
                           "Not allowed on this resource"))

    yield Response(code=responsecode.OK, stream=MemoryStream(result.toxml()))
Ejemplo n.º 2
0
    def http_GET(self, request):
        """
        The iSchedule GET method.
        """

        if not request.args or self._podding:
            # Do normal GET behavior
            return self.render(request)

        action = request.args.get("action", ("", ))
        if len(action) != 1:
            raise HTTPError(
                StatusResponse(
                    responsecode.BAD_REQUEST,
                    "Invalid action parameter",
                ))
        action = action[0]

        action = {
            "capabilities": self.doCapabilities,
        }.get(action, None)

        if action is None:
            raise HTTPError(
                StatusResponse(
                    responsecode.BAD_REQUEST,
                    "Unknown action action parameter",
                ))

        return action(request)
Ejemplo n.º 3
0
    def http_POST(self, request):
        """
        POST method with JSON body is used for control.
        """

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

        contentType = request.headers.getHeader("content-type")
        # Check content first
        if "{}/{}".format(contentType.mediaType, contentType.mediaSubtype) != "application/json":
            self.log.error("MIME type {mime} not allowed in request", mime=contentType)
            raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, "MIME type {} not allowed in request".format(contentType)))

        body = (yield allDataFromStream(request.stream))
        try:
            j = json.loads(body)
        except (ValueError, TypeError) as e:
            self.log.error("Invalid JSON data in request: {ex}\n{body}", ex=e, body=body)
            raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, "Invalid JSON data in request: {}\n{}".format(e, body)))

        try:
            action = j["action"]
        except KeyError:
            self._error("error", "No 'action' member in root JSON object.")

        method = "action_{}".format(action)
        if not hasattr(self, method):
            self._error("error", "The action '{}' is not supported.".format(action))

        result = yield getattr(self, method)(j)
        returnValue(result)
Ejemplo n.º 4
0
def report_urn_ietf_params_xml_ns_caldav_free_busy_query(self, request, freebusy):
    """
    Generate a free-busy REPORT.
    (CalDAV-access-09, section 7.8)
    """
    if not self.isCollection():
        log.error("freebusy report is only allowed on collection resources {s!r}", s=self)
        raise HTTPError(StatusResponse(responsecode.FORBIDDEN, "Not a calendar collection"))

    if freebusy.qname() != (caldavxml.caldav_namespace, "free-busy-query"):
        raise ValueError("{CalDAV:}free-busy-query expected as root element, not %s." % (freebusy.sname(),))

    timerange = freebusy.timerange
    if not timerange.valid():
        raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, "Invalid time-range specified"))

    fbset = []

    accepted_type = bestAcceptType(request.headers.getHeader("accept"), Component.allowedTypes())
    if accepted_type is None:
        raise HTTPError(StatusResponse(responsecode.NOT_ACCEPTABLE, "Cannot generate requested data type"))

    def getCalendarList(calresource, uri):  # @UnusedVariable
        """
        Store the calendars that match the query in L{fbset} which will then be used with the
        freebusy query.

        @param calresource: the L{CalDAVResource} for a calendar collection.
        @param uri: the uri for the calendar collection resource.
        """

        fbset.append(calresource._newStoreObject)
        return succeed(True)

    # Run report taking depth into account
    depth = request.headers.getHeader("depth", "0")
    yield report_common.applyToCalendarCollections(self, request, request.uri, depth, getCalendarList, (caldavxml.ReadFreeBusy(),))

    # Do the actual freebusy query against the set of matched calendars
    principal = yield self.resourceOwnerPrincipal(request)
    organizer = recipient = LocalCalendarUser(principal.canonicalCalendarUserAddress(), principal.record)
    timerange = Period(timerange.start, timerange.end)
    try:
        fbresult = yield FreebusyQuery(organizer=organizer, recipient=recipient, timerange=timerange).generateAttendeeFreeBusyResponse(fbset=fbset, method=None)
    except NumberOfMatchesWithinLimits:
        log.error("Too many matching components in free-busy report")
        raise HTTPError(ErrorResponse(
            responsecode.FORBIDDEN,
            davxml.NumberOfMatchesWithinLimits(),
            "Too many components"
        ))
    except TimeRangeLowerLimit, e:
        raise HTTPError(ErrorResponse(
            responsecode.FORBIDDEN,
            caldavxml.MinDateTime(),
            "Time-range value too far in the past. Must be on or after %s." % (str(e.limit),)
        ))
Ejemplo n.º 5
0
def _prepareForCopy(destination, destination_uri, request, depth):
    #
    # Destination must be a DAV resource
    #

    try:
        destination = IDAVResource(destination)
    except TypeError:
        log.error("Attempt to %s to a non-DAV resource: (%s) %s" %
                  (request.method, destination.__class__, destination_uri))
        raise HTTPError(
            StatusResponse(
                responsecode.FORBIDDEN,
                "Destination %s is not a WebDAV resource." %
                (destination_uri, )))

    #
    # FIXME: Right now we don't know how to copy to a non-DAVFile resource.
    # We may need some more API in IDAVResource.
    # So far, we need: .exists(), .fp.parent()
    #

    if not isinstance(destination, txweb2.dav.static.DAVFile):
        log.error(
            "DAV copy between non-DAVFile DAV resources isn't implemented")
        raise HTTPError(
            StatusResponse(
                responsecode.NOT_IMPLEMENTED,
                "Destination %s is not a DAVFile resource." %
                (destination_uri, )))

    #
    # Check for existing destination resource
    #

    overwrite = request.headers.getHeader("overwrite", True)

    if destination.exists() and not overwrite:
        log.error(
            "Attempt to %s onto existing file without overwrite flag enabled: %s"
            % (request.method, destination))
        raise HTTPError(
            StatusResponse(
                responsecode.PRECONDITION_FAILED,
                "Destination %s already exists." % (destination_uri, )))

    #
    # Make sure destination's parent exists
    #

    if not destination.parent().isCollection():
        log.error("Attempt to %s to a resource with no parent: %s" %
                  (request.method, destination.fp.path))
        raise HTTPError(
            StatusResponse(responsecode.CONFLICT, "No parent collection."))

    return destination, destination_uri, depth
Ejemplo n.º 6
0
    def linkedResource(self, request):

        if not hasattr(self, "_linkedResource"):
            if self.linkURL in self.loopDetect:
                raise HTTPError(StatusResponse(responsecode.LOOP_DETECTED, "Recursive link target: %s" % (self.linkURL,)))
            else:
                self.loopDetect.add(self.linkURL)
            self._linkedResource = (yield request.locateResource(self.linkURL))
            self.loopDetect.remove(self.linkURL)

        if self._linkedResource is None:
            raise HTTPError(StatusResponse(responsecode.NOT_FOUND, "Missing link target: %s" % (self.linkURL,)))

        returnValue(self._linkedResource)
Ejemplo n.º 7
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)))
Ejemplo n.º 8
0
def http_ACL(self, request):
    """
    Respond to a ACL request. (RFC 3744, section 8.1)
    """
    if not self.exists():
        log.error("File not found: %s" % (self,))
        yield responsecode.NOT_FOUND
        return

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

    #
    # Read request body
    #
    doc = waitForDeferred(davXMLFromStream(request.stream))
    yield doc
    try:
        doc = doc.getResult()
    except ValueError, e:
        log.error("Error while handling ACL body: %s" % (e,))
        raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
Ejemplo n.º 9
0
    def finalChecks(self):
        """
        Final checks before doing the actual scheduling.
        """

        # With implicit scheduling only certain types of iTIP operations are allowed for POST.

        if self.doingPOST:
            # Freebusy requests always processed
            if self.checkForFreeBusy():
                return

            # COUNTER and DECLINE-COUNTER allowed
            if self.calendar.propertyValue("METHOD") in ("COUNTER",
                                                         "DECLINECOUNTER"):
                return

            # Anything else is not allowed. However, for compatibility we will optionally
            # return a success response for all attendees.
            if config.Scheduling.CalDAV.OldDraftCompatibility:
                self.fakeTheResult = True
            else:
                raise HTTPError(
                    StatusResponse(
                        responsecode.BAD_REQUEST,
                        "Invalid iTIP message for implicit scheduling"))
Ejemplo n.º 10
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)
Ejemplo n.º 11
0
    def locateChild(self, req, segments):
        """
        See L{IResource}C{.locateChild}.
        """
        # If getChild() finds a child resource, return it
        try:
            child = self.getChild(segments[0])
            if child is not None:
                return (child, segments[1:])
        except InsecurePath:
            raise HTTPError(
                StatusResponse(responsecode.FORBIDDEN, "Invalid URL path"))

        # If we're not backed by a directory, we have no children.
        # But check for existance first; we might be a collection resource
        # that the request wants created.
        self.fp.restat(False)
        if self.fp.exists() and not self.fp.isdir():
            return (None, ())

        # OK, we need to return a child corresponding to the first segment
        path = segments[0]

        if path == "":
            # Request is for a directory (collection) resource
            return (self, ())

        return (self.createSimilarFile(self.fp.child(path).path), segments[1:])
Ejemplo n.º 12
0
 def __init__(self, qname):
     HTTPError.__init__(
         self,
         StatusResponse(
             responsecode.NOT_FOUND,
             "No such property: %s" % encodeXMLName(*qname)
         )
     )
Ejemplo n.º 13
0
    def setGroupMemberSet(self, new_members, request):
        # FIXME: as defined right now it is not possible to specify a
        # calendar-user-proxy group as a member of any other group since the
        # directory service does not know how to lookup these special resource
        # UIDs.
        #
        # Really, c-u-p principals should be treated the same way as any other
        # principal, so they should be allowed as members of groups.
        #
        # This implementation now raises an exception for any principal it
        # cannot find.

        # Break out the list into a set of URIs.
        members = [str(h) for h in new_members.children]

        # Map the URIs to principals and a set of UIDs.
        principals = []
        newUIDs = set()
        for uri in members:
            principal = yield self.pcollection._principalForURI(uri)
            # Invalid principals MUST result in an error.
            if principal is None or principal.principalURL() != uri:
                raise HTTPError(StatusResponse(
                    responsecode.BAD_REQUEST,
                    "Attempt to use a non-existent principal %s "
                    "as a group member of %s." % (uri, self.principalURL(),)
                ))
            principals.append(principal)
            newUIDs.add(principal.principalUID())

        # Get the old set of expanded UIDs
        oldUIDs = set()
        oldPrincipals = yield self.groupMembers()
        oldUIDs.update([p.principalUID() for p in oldPrincipals])
        oldPrincipals = yield self.expandedGroupMembers()
        oldUIDs.update([p.principalUID() for p in oldPrincipals])

        # Change membership
        yield self.setGroupMemberSetPrincipals(principals)

        # Get the new set of UIDs
        newUIDs = set()
        newPrincipals = yield self.groupMembers()
        newUIDs.update([p.principalUID() for p in newPrincipals])
        newPrincipals = yield self.expandedGroupMembers()
        newUIDs.update([p.principalUID() for p in newPrincipals])

        # Invalidate the primary principal's cache, and any principal's whose
        # membership status changed
        yield self.parent.cacheNotifier.changed()

        changedUIDs = newUIDs.symmetric_difference(oldUIDs)
        for uid in changedUIDs:
            principal = yield self.pcollection.principalForUID(uid)
            if principal:
                yield principal.cacheNotifier.changed()

        returnValue(True)
Ejemplo n.º 14
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, )))
    def renderHTTP(self, request):
        if not self.directory:
            raise HTTPError(
                StatusResponse(responsecode.SERVICE_UNAVAILABLE,
                               "Service is starting up"))

        response = (yield maybeDeferred(
            super(DirectoryBackedAddressBookResource, self).renderHTTP,
            request))
        returnValue(response)
Ejemplo n.º 16
0
    def get(self, qname):
        try:
            property = self._dict[qname]
        except KeyError:
            raise HTTPError(
                StatusResponse(
                    responsecode.NOT_FOUND,
                    "No such property: %s" % (encodeXMLName(*qname), )))

        doc = element.WebDAVDocument.fromString(property)
        return doc.root_element
Ejemplo n.º 17
0
class ReadOnlyWritePropertiesResourceMixIn(object):
    """
    Read only that will allow writing of properties resource.
    """
    readOnlyResponse = StatusResponse(responsecode.FORBIDDEN,
                                      "Resource is read only.")

    def _forbidden(self, request):
        return self.readOnlyResponse

    http_DELETE = _forbidden
    http_MOVE = _forbidden
    http_PUT = _forbidden
Ejemplo n.º 18
0
    def renderHTTP(self, request):
        """
        Do the reverse proxy request and return the response.

        @param request: the incoming request that needs to be proxied.
        @type request: L{Request}

        @return: Deferred L{Response}
        """

        self.log.info("{method} {poolID}:{uri} {proto}", method=request.method, poolID=self.poolID, uri=request.uri, proto="HTTP/{}.{}".format(*request.clientproto))

        # Check for multi-hop
        if not self.allowMultiHop:
            x_server = request.headers.getHeader("x-forwarded-server")
            if x_server:
                for item in x_server:
                    if item.lower() == config.ServerHostName.lower():
                        self.log.error("ReverseProxy loop detected: x-forwarded-server:{xfs}", xfs=str(x_server))
                        raise HTTPError(StatusResponse(responsecode.BAD_GATEWAY, "Too many x-forwarded-server hops"))

        clientPool = getHTTPClientPool(self.poolID)
        proxyRequest = ClientRequest(request.method, request.uri, request.headers, request.stream)

        # Need x-forwarded-(for|host|server) headers. First strip any existing ones out, then add ours
        proxyRequest.headers.removeHeader("x-forwarded-host")
        proxyRequest.headers.removeHeader("x-forwarded-for")
        proxyRequest.headers.removeHeader("x-forwarded-server")
        proxyRequest.headers.addRawHeader("x-forwarded-host", request.host)
        proxyRequest.headers.addRawHeader("x-forwarded-for", request.remoteAddr.host)
        proxyRequest.headers.addRawHeader("x-forwarded-server", config.ServerHostName)

        try:
            response = yield clientPool.submitRequest(proxyRequest)
        except Exception as e:
            self.log.error("ReverseProxy failed: {exc}", exc=str(e))
            raise HTTPError(StatusResponse(responsecode.BAD_GATEWAY, "Cannot connect via poolID={poolID}".format(poolID=self.poolID)))

        returnValue(response)
Ejemplo n.º 19
0
def prepareForCopy(self, request):
    #
    # Get the depth
    #

    depth = request.headers.getHeader("depth", "infinity")

    if depth not in ("0", "infinity"):
        msg = ("Client sent illegal depth header value: %s" % (depth,))
        log.error(msg)
        raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, msg))

    #
    # Verify this resource exists
    #

    if not self.exists():
        log.error("File not found: %s" % (self,))
        raise HTTPError(StatusResponse(
            responsecode.NOT_FOUND,
            "Source resource %s not found." % (request.uri,)
        ))

    #
    # Get the destination
    #

    destination_uri = request.headers.getHeader("destination")

    if not destination_uri:
        msg = "No destination header in %s request." % (request.method,)
        log.error(msg)
        raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, msg))

    d = request.locateResource(destination_uri)
    d.addCallback(_prepareForCopy, destination_uri, request, depth)

    return d
Ejemplo n.º 20
0
    def get(self, qname, uid=None):
        """
        Retrieve the value of a property stored as an extended attribute on the
        wrapped path.

        @param qname: The property to retrieve as a two-tuple of namespace URI
            and local name.

        @param uid: The per-user identifier for per user properties.

        @raise HTTPError: If there is no value associated with the given
            property.

        @return: A L{WebDAVDocument} representing the value associated with the
            given property.
        """

        try:
            data = self.attrs.get(self._encode(qname, uid))
        except KeyError:
            raise HTTPError(
                StatusResponse(
                    responsecode.NOT_FOUND,
                    "No such property: %s" % (encodeXMLName(*qname), )))
        except IOError, e:
            if e.errno in _ATTR_MISSING or e.errno == errno.ENOENT:
                raise HTTPError(
                    StatusResponse(
                        responsecode.NOT_FOUND,
                        "No such property: %s" % (encodeXMLName(*qname), )))
            else:
                raise HTTPError(
                    StatusResponse(
                        statusForFailure(Failure()),
                        "Unable to read property: %s" %
                        (encodeXMLName(*qname), )))
Ejemplo n.º 21
0
def http_REPORT(self, request):
    """
    Respond to a REPORT request. (RFC 3253, section 3.6)
    """
    if not self.exists():
        log.error("Resource not found: %s" % (self,))
        raise HTTPError(responsecode.NOT_FOUND)

    #
    # Read request body
    #
    try:
        doc = (yield davXMLFromStream(request.stream))
    except ValueError, e:
        log.error("Error while handling REPORT body: {err}", err=str(e))
        raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
Ejemplo n.º 22
0
    def renderHTTP(self, request):

        try:
            _ignore_authnUser, authzUser = yield self.authenticate(request)
        except Exception:
            authzUser = None

        # Turn 404 into 401
        if authzUser is None:
            response = (yield UnauthorizedResponse.makeResponse(
                request.credentialFactories, request.remoteAddr))
            returnValue(response)
        else:
            response = StatusResponse(responsecode.NOT_FOUND,
                                      "Resource not found")
            returnValue(response)
Ejemplo n.º 23
0
        def get(self, qname, uid=None, cache=True):
            if cache:
                propertyCache = self.propertyCache()
                qnameuid = qname + (uid, )
                if qnameuid in propertyCache:
                    return propertyCache[qnameuid]
                else:
                    raise HTTPError(
                        StatusResponse(
                            responsecode.NOT_FOUND, "No such property: %s%s" %
                            (uid if uid else "", encodeXMLName(*qname))))

            self.log.debug("Read for %s%s on %s" %
                           (("{%s}:" % (uid, )) if uid else "", qname,
                            self.childPropertyStore.resource.fp.path))
            return self.childPropertyStore.get(qname, uid=uid)
Ejemplo n.º 24
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)))
Ejemplo n.º 25
0
    def readProperty(self, property, request):
        if type(property) is tuple:
            qname = property
        else:
            qname = property.qname()

        namespace, name = qname

        if namespace == dav_namespace:
            if name == "resourcetype":
                rtype = self.resourceType()
                returnValue(rtype)

        elif namespace == calendarserver_namespace:
            if name == "expanded-group-member-set":
                principals = (yield self.expandedGroupMembers())
                returnValue(customxml.ExpandedGroupMemberSet(
                    *[element.HRef(p.principalURL()) for p in principals]
                ))

            elif name == "expanded-group-membership":
                principals = (yield self.expandedGroupMemberships())
                returnValue(customxml.ExpandedGroupMembership(
                    *[element.HRef(p.principalURL()) for p in principals]
                ))

            elif name == "record-type":
                if hasattr(self, "record"):
                    returnValue(
                        customxml.RecordType(
                            self.record.service.recordTypeToOldName(
                                self.record.recordType
                            )
                        )
                    )
                else:
                    raise HTTPError(StatusResponse(
                        responsecode.NOT_FOUND,
                        "Property %s does not exist." % (qname,)
                    ))

        result = (yield super(DAVPrincipalResource, self).readProperty(property, request))
        returnValue(result)
Ejemplo n.º 26
0
def extractCalendarServerPrincipalSearchData(doc):
    """
    Extract relevant info from a CalendarServerPrincipalSearch document

    @param doc: CalendarServerPrincipalSearch object to extract info from
    @return: A tuple containing:
        the list of tokens
        the context string
        the applyTo boolean
        the clientLimit integer
        the propElement containing the properties to return
    """
    context = doc.attributes.get("context", None)
    applyTo = False
    tokens = []
    clientLimit = None
    for child in doc.children:
        if child.qname() == (dav_namespace, "prop"):
            propElement = child

        elif child.qname() == (dav_namespace,
                               "apply-to-principal-collection-set"):
            applyTo = True

        elif child.qname() == (calendarserver_namespace, "search-token"):
            tokenValue = child.toString().strip()
            if tokenValue:
                tokens.append(tokenValue)

        elif child.qname() == (calendarserver_namespace, "limit"):
            try:
                nresults = child.childOfType(customxml.NResults)
                clientLimit = int(str(nresults))
            except (
                    TypeError,
                    ValueError,
            ):
                msg = "Bad XML: unknown value for <limit> element"
                log.warn(msg)
                raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, msg))

    return tokens, context, applyTo, clientLimit, propElement
Ejemplo n.º 27
0
    def list(self, uid=None, filterByUID=True):
        """
        Enumerate the property names stored in extended attributes of the
        wrapped path.

        @param uid: The per-user identifier for per user properties.

        @return: A C{list} of property names as two-tuples of namespace URI and
            local name.
        """

        prefix = self.deadPropertyXattrPrefix
        try:
            attrs = iter(self.attrs)
        except IOError, e:
            if e.errno == errno.ENOENT:
                return []
            raise HTTPError(
                StatusResponse(statusForFailure(Failure()),
                               "Unable to list properties: %s",
                               (self.resource.fp.path, )))
Ejemplo n.º 28
0
            def do(action, property, removing=False):
                """
                Perform action(property, request) while maintaining an
                undo queue.
                """
                has = waitForDeferred(self.hasProperty(property, request))
                yield has
                has = has.getResult()

                if has:
                    oldProperty = waitForDeferred(
                        self.readProperty(property, request))
                    yield oldProperty
                    oldProperty = oldProperty.getResult()

                    def undo():
                        return self.writeProperty(oldProperty, request)
                else:

                    def undo():
                        return self.removeProperty(property, request)

                try:
                    x = waitForDeferred(action(property, request))
                    yield x
                    x.getResult()
                except KeyError, e:
                    # Removing a non-existent property is OK according to WebDAV
                    if removing:
                        responses.add(responsecode.OK, property)
                        yield True
                        return
                    else:
                        # Convert KeyError exception into HTTPError
                        responses.add(
                            Failure(exc_value=HTTPError(
                                StatusResponse(responsecode.FORBIDDEN, str(
                                    e)))), property)
                        yield False
                        return
Ejemplo n.º 29
0
    def renderHTTP(self, request):
        """
        Do the reverse proxy request and return the response.

        @param request: the incoming request that needs to be proxied.
        @type request: L{Request}

        @return: Deferred L{Response}
        """

        self.log.info("{method} {uri} {proto}",
                      method=request.method,
                      uri=request.uri,
                      proto="HTTP/%s.%s" % request.clientproto)

        # Check for multi-hop
        if not self.allowMultiHop:
            x_server = request.headers.getHeader("x-forwarded-server")
            if x_server:
                for item in x_server:
                    if item.lower() == config.ServerHostName.lower():
                        raise HTTPError(
                            StatusResponse(responsecode.BAD_GATEWAY,
                                           "Too many x-forwarded-server hops"))

        clientPool = getHTTPClientPool(self.poolID)
        proxyRequest = ClientRequest(request.method, request.uri,
                                     request.headers, request.stream)

        # Need x-forwarded-(for|host|server) headers. First strip any existing ones out, then add ours
        proxyRequest.headers.removeHeader("x-forwarded-host")
        proxyRequest.headers.removeHeader("x-forwarded-for")
        proxyRequest.headers.removeHeader("x-forwarded-server")
        proxyRequest.headers.addRawHeader("x-forwarded-host", request.host)
        proxyRequest.headers.addRawHeader("x-forwarded-for",
                                          request.remoteAddr.host)
        proxyRequest.headers.addRawHeader("x-forwarded-server",
                                          config.ServerHostName)

        return clientPool.submitRequest(proxyRequest)
Ejemplo n.º 30
0
def http_PROPPATCH(self, request):
    """
    Respond to a PROPPATCH request. (RFC 2518, section 8.2)
    """
    if not self.exists():
        log.error("File not found: %s" % (self,))
        raise HTTPError(responsecode.NOT_FOUND)

    x = waitForDeferred(self.authorize(request, (davxml.WriteProperties(),)))
    yield x
    x.getResult()

    #
    # Read request body
    #
    try:
        doc = waitForDeferred(davXMLFromStream(request.stream))
        yield doc
        doc = doc.getResult()
    except ValueError, e:
        log.error("Error while handling PROPPATCH body: %s" % (e,))
        raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))