import logging
import rfc822
import ssl
+import functools
# Manage Python2/3 different modules
# pylint: disable=F0401
import BaseHTTPServer as server
# pylint: enable=F0401
-from . import acl, config, webdav, xmlutils, paths, gssapi
+from . import acl, config, webdav, xmlutils, paths, gssapi, principal
log = logging.getLogger()
ch = logging.StreamHandler()
owner = user = password = None
negotiate_success = False
- if request._collection:
+ if request._resource:
+ owner = request._resource.owner
+ elif request._collection:
owner = request._collection.owner
authorization = request.headers.get("Authorization", None)
("user-agent", "x-client", "origin")
if name in request.headers])
+ # bound privilege checker that can be used by principals etc in discovery too
+ has_right = functools.partial(request.server.acl.has_right, user=user, password=password)
+
# Also send UNAUTHORIZED if there's no collection. Otherwise one
# could probe the server for (non-)existing collections.
- if request.server.acl.has_right(owner, user, password) or negotiate_success:
- function(request, context={"user": user, "client_info": client_info})
+ if has_right(owner) or negotiate_success:
+ function(request, context={
+ "user": user,
+ "client_info": client_info,
+ "has_right": has_right})
else:
request.send_calypso_response(client.UNAUTHORIZED, 0)
if negotiate.enabled():
CollectionHTTPHandler.collections[path] = webdav.Collection(path)
return CollectionHTTPHandler.collections[path]
+def identify_resource(path):
+ """Return a Resource object corresponding to the path (this is used for
+ everything that is not a collection, like Principal and HomeSet objects)"""
+
+ try:
+ left, right = config.get('server', 'user_principal').split('%(user)s')
+ except ValueError:
+ raise ValueError("user_principal setting must contain %(user)s.")
+
+ if not path.startswith(left):
+ return None
+
+ remainder = path[len(left):]
+ if right not in remainder:
+ return None
+
+ username = remainder[:remainder.index(right)]
+ remainder = remainder[remainder.index(right)+len(right):]
+
+ if remainder == principal.AddressbookHomeSet.type_dependent_suffix + "/":
+ return principal.AddressbookHomeSet(username)
+ elif remainder == principal.CalendarHomeSet.type_dependent_suffix + "/":
+ return principal.CalendarHomeSet(username)
+ elif remainder == "":
+ return principal.Principal(username)
+ else:
+ return None
+
class CollectionHTTPHandler(server.BaseHTTPRequestHandler):
"""HTTP requests handler for WebDAV collections."""
_encoding = config.get("encoding", "request")
"""The ``webdav.Collection`` object corresponding to the given path."""
return collection_singleton(self.path)
+ @property
+ def _resource(self):
+ return identify_resource(self.path)
+
def _decode(self, text):
"""Try to decode text according to various parameters."""
# List of charsets to try
xml_request = self.xml_request
log.debug("PROPFIND %s", xml_request)
self._answer = xmlutils.propfind(
- self.path, xml_request, self._collection,
+ self.path, xml_request, self._collection, self._resource,
self.headers.get("depth", "infinity"),
context)
log.debug("PROPFIND ANSWER %s", self._answer)
"""If self can respond to a propfind request on a tag, update the
prepared response element with child nodes."""
- def propfind_children(self, depth):
+ def propfind_children(self, depth, context):
"""Return a list of resources / collections / items that are to be
responded with to a propfind of a given depth"""
return [self]
self.username = username
self.urlpath = config.get("server", "user_principal") % {"user": self.username} # it's currently hardcoded anyway
+ owner = property(lambda self: self.username)
+
def propfind(self, tag, element):
super(Principal, self).propfind(tag, element)
self.username = username
self.urlpath = config.get("server", "user_principal") % {"user": self.username} + self.type_dependent_suffix + "/" # it's currently hardcoded anyway
- def propfind_children(self, depth):
+ owner = property(lambda self: self.username)
+
+ def propfind_children(self, depth, context):
# FIXME ignoring depth
collection_name = paths.collection_from_path(self.username + "/" + self.single_collection)
import logging
from . import client, config, webdav, paths, principal
+from .xmlutils_generic import _tag
__package__ = 'calypso.xmlutils'
-NAMESPACES = {
- "C": "urn:ietf:params:xml:ns:caldav",
- "A": "urn:ietf:params:xml:ns:carddav",
- "D": "DAV:",
- "E": "http://apple.com/ns/ical/",
- "CS": "http://calendarserver.org/ns/"}
-
log = logging.getLogger(__name__)
-def _tag(short_name, local):
- """Get XML Clark notation {uri(``short_name``)}``local``."""
- return "{%s}%s" % (NAMESPACES[short_name], local)
-
def _response(code):
"""Return full W3C names from HTTP status codes."""
return ET.tostring(multistatus, config.get("encoding", "request"))
-def identify_resource(path):
- """Return a Resource object corresponding to the path (this is used for
- everything that is not a collection, like Principal and HomeSet objects)"""
-
- try:
- left, right = config.get('server', 'user_principal').split('%(user)s')
- except ValueError:
- raise ValueError("user_principal setting must contain %(user)s.")
-
- if not path.startswith(left):
- return None
-
- remainder = path[len(left):]
- if right not in remainder:
- return None
-
- username = remainder[:remainder.index(right)]
- remainder = remainder[remainder.index(right)+len(right):]
-
- if remainder == principal.AddressbookHomeSet.type_dependent_suffix + "/":
- return principal.AddressbookHomeSet(username)
- elif remainder == principal.CalendarHomeSet.type_dependent_suffix + "/":
- return principal.CalendarHomeSet(username)
- elif remainder == "":
- return principal.Principal(username)
- else:
- return None
-
-def propfind(path, xml_request, collection, depth, context):
+def propfind(path, xml_request, collection, resource, depth, context):
"""Read and answer PROPFIND requests.
Read rfc4918-9.1 for info.
# Writing answer
multistatus = ET.Element(_tag("D", "multistatus"))
- resource = identify_resource(path)
-
if resource is not None:
- items = resource.propfind_children(depth)
+ items = resource.propfind_children(depth, context)
elif collection:
if item_name:
item = collection.get_item(item_name)
--- /dev/null
+NAMESPACES = {
+ "C": "urn:ietf:params:xml:ns:caldav",
+ "A": "urn:ietf:params:xml:ns:carddav",
+ "D": "DAV:",
+ "E": "http://apple.com/ns/ical/",
+ "CS": "http://calendarserver.org/ns/"}
+
+
+def _tag(short_name, local):
+ """Get XML Clark notation {uri(``short_name``)}``local``."""
+ return "{%s}%s" % (NAMESPACES[short_name], local)