[CalendarServer-changes] [1810]
CalendarServer/branches/release/CalendarServer-1.0-dev
source_changes at macosforge.org
source_changes at macosforge.org
Mon Aug 20 19:22:47 PDT 2007
Revision: 1810
http://trac.macosforge.org/projects/calendarserver/changeset/1810
Author: wsanchez at apple.com
Date: 2007-08-20 19:22:46 -0700 (Mon, 20 Aug 2007)
Log Message:
-----------
Pulled up r1745, r1748, r1757, r1758
Modified Paths:
--------------
CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts-test.xml
CalendarServer/branches/release/CalendarServer-1.0-dev/conf/caldavd-test.plist
CalendarServer/branches/release/CalendarServer-1.0-dev/lib-patches/Twisted/twisted.web2.dav.method.report_principal_match.patch
CalendarServer/branches/release/CalendarServer-1.0-dev/lib-patches/Twisted/twisted.web2.dav.resource.patch
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/calendaruserproxy.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/principal.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_principal.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlaccountsparser.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlfile.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/root.py
CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/test/test_root.py
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts-test.xml
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts-test.xml 2007-08-21 00:35:50 UTC (rev 1809)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/conf/accounts-test.xml 2007-08-21 02:22:46 UTC (rev 1810)
@@ -21,29 +21,34 @@
<accounts realm="Test Realm">
<user>
<uid>admin</uid>
+ <guid>admin</guid>
<password>admin</password>
<name>Super User</name>
</user>
<user repeat="99">
<uid>user%02d</uid>
+ <guid>user%02d</guid>
<password>user%02d</password>
<name>User %02d</name>
<cuaddr>mailto:user%02d at example.com</cuaddr>
</user>
<user repeat="10">
<uid>public%02d</uid>
+ <guid>public%02d</guid>
<password>public%02d</password>
<name>Public %02d</name>
<cuaddr>mailto:public%02d at example.com</cuaddr>
</user>
<location repeat="10">
<uid>location%02d</uid>
+ <guid>location%02d</guid>
<password>location%02d</password>
<name>Room %02d</name>
<auto-schedule/>
</location>
<resource repeat="10">
<uid>resource%02d</uid>
+ <guid>resource%02d</guid>
<password>resource%02d</password>
<name>Resource %02d</name>
<auto-schedule/>
@@ -53,6 +58,7 @@
</resource>
<group>
<uid>group01</uid>
+ <guid>group01</guid>
<password>group01</password>
<name>Group 01</name>
<members>
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/conf/caldavd-test.plist
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/conf/caldavd-test.plist 2007-08-21 00:35:50 UTC (rev 1809)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/conf/caldavd-test.plist 2007-08-21 02:22:46 UTC (rev 1810)
@@ -186,7 +186,7 @@
<!-- Principals with "DAV:all" access (relative URLs) -->
<key>AdminPrincipals</key>
<array>
- <string>/principals/users/admin/</string>
+ <string>/principals/__uids__/admin/</string>
</array>
<!-- Principals that can pose as other principals -->
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/lib-patches/Twisted/twisted.web2.dav.method.report_principal_match.patch
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/lib-patches/Twisted/twisted.web2.dav.method.report_principal_match.patch 2007-08-21 00:35:50 UTC (rev 1809)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/lib-patches/Twisted/twisted.web2.dav.method.report_principal_match.patch 2007-08-21 02:22:46 UTC (rev 1810)
@@ -2,7 +2,7 @@
===================================================================
--- twisted/web2/dav/method/report_principal_match.py (revision 19773)
+++ twisted/web2/dav/method/report_principal_match.py (working copy)
-@@ -89,40 +89,53 @@
+@@ -89,40 +89,61 @@
responses = []
matchcount = 0
@@ -25,6 +25,10 @@
- for child, uri in children:
- if isPrincipalResource(child) and child.principalMatch(selfPrincipal):
+- # Check size of results is within limit
+- matchcount += 1
+- if matchcount > max_number_of_matches:
+- raise NumberOfMatchesWithinLimits
+ # Find the set of principals that represent "self".
+
+ # First add "self"
@@ -39,26 +43,31 @@
+ # Now add each principal found to the response provided the principal resource is a child of
+ # the current resource.
+ for principal in selfItems:
-+ if principal.principalURL().startswith(request.uri):
- # Check size of results is within limit
- matchcount += 1
- if matchcount > max_number_of_matches:
- raise NumberOfMatchesWithinLimits
--
-+
- d = waitForDeferred(prop_common.responseForHref(
- request,
- responses,
-- davxml.HRef.fromString(uri),
-- child,
-+ davxml.HRef.fromString(principal.principalURL()),
-+ principal,
- propertiesForResource,
- propElement
- ))
- yield d
- d.getResult()
- else:
++ # Get all the URIs that point to the principal resource
++ # FIXME: making the assumption that the principalURL() is the URL of the resource we found
++ principal_uris = [principal.principalURL()]
++ principal_uris.extend(principal.alternateURIs())
++
++ # Compare each one to the request URI and return at most one that matches
++ for uri in principal_uris:
++ if uri.startswith(request.uri):
++ # Check size of results is within limit
++ matchcount += 1
++ if matchcount > max_number_of_matches:
++ raise NumberOfMatchesWithinLimits
++
++ d = waitForDeferred(prop_common.responseForHref(
++ request,
++ responses,
++ davxml.HRef.fromString(uri),
++ principal,
++ propertiesForResource,
++ propElement
++ ))
++ yield d
++ d.getResult()
++ break
++ else:
+ # Do some optimisation of access control calculation by determining any inherited ACLs outside of
+ # the child resource loop and supply those to the checkPrivileges on each child.
+ filteredaces = waitForDeferred(self.inheritedACEsforChildren(request))
@@ -70,11 +79,22 @@
+ privileges=(davxml.Read(),), inherited_aces=filteredaces))
+ yield d
+ d.getResult()
-+
+
+- d = waitForDeferred(prop_common.responseForHref(
+- request,
+- responses,
+- davxml.HRef.fromString(uri),
+- child,
+- propertiesForResource,
+- propElement
+- ))
+- yield d
+- d.getResult()
+- else:
for child, uri in children:
# Try to read the requested property from this resource
try:
-@@ -137,7 +150,7 @@
+@@ -137,7 +158,7 @@
yield principal
principal = principal.getResult()
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/lib-patches/Twisted/twisted.web2.dav.resource.patch
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/lib-patches/Twisted/twisted.web2.dav.resource.patch 2007-08-21 00:35:50 UTC (rev 1809)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/lib-patches/Twisted/twisted.web2.dav.resource.patch 2007-08-21 02:22:46 UTC (rev 1810)
@@ -517,7 +517,27 @@
return False
-@@ -1432,7 +1523,7 @@
+@@ -1351,11 +1442,16 @@
+ @return C{True} if C{href_principal} is valid, C{False} otherwise.
+
+ This implementation tests for a href element that corresponds to
+- a principal resource.
++ a principal resource and matches the principal-URL.
+ """
+- # Must have the principal resource type
++
++ # Must have the principal resource type and must match the principal-URL
++
++ def _matchPrincipalURL(resource):
++ return isPrincipalResource(resource) and resource.principalURL() == str(href_principal)
++
+ d = request.locateResource(str(href_principal))
+- d.addCallback(isPrincipalResource)
++ d.addCallback(_matchPrincipalURL)
+ return d
+
+ def resolvePrincipal(self, principal, request):
+@@ -1432,7 +1528,7 @@
log.err("DAV:self ACE is set on non-principal resource %r" % (self,))
yield None
return
@@ -526,7 +546,7 @@
if isinstance(principal, davxml.HRef):
yield principal
-@@ -1517,6 +1608,270 @@
+@@ -1517,6 +1613,270 @@
return None
##
@@ -797,7 +817,7 @@
# HTTP
##
-@@ -1567,7 +1922,7 @@
+@@ -1567,7 +1927,7 @@
def findChildren(self, depth, request, callback, privileges=None, inherited_aces=None):
return succeed(None)
@@ -806,7 +826,7 @@
"""
Resource representing a WebDAV principal. (RFC 3744, section 2)
"""
-@@ -1577,7 +1932,7 @@
+@@ -1577,7 +1937,7 @@
# WebDAV
##
@@ -815,7 +835,7 @@
(dav_namespace, "alternate-URI-set"),
(dav_namespace, "principal-URL" ),
(dav_namespace, "group-member-set" ),
-@@ -1585,14 +1940,11 @@
+@@ -1585,14 +1945,11 @@
)
def davComplianceClasses(self):
@@ -831,7 +851,7 @@
def readProperty(self, property, request):
def defer():
if type(property) is tuple:
-@@ -1610,10 +1962,10 @@
+@@ -1610,10 +1967,10 @@
return davxml.PrincipalURL(davxml.HRef(self.principalURL()))
if name == "group-member-set":
@@ -844,7 +864,7 @@
if name == "resourcetype":
if self.isCollection():
-@@ -1677,8 +2029,27 @@
+@@ -1677,8 +2034,27 @@
if self.principalURL() == uri:
return True
else:
@@ -873,7 +893,7 @@
class AccessDeniedError(Exception):
def __init__(self, errors):
"""
-@@ -1718,6 +2089,37 @@
+@@ -1718,6 +2094,37 @@
davxml.registerElement(TwistedACLInheritable)
davxml.ACE.allowed_children[(twisted_dav_namespace, "inheritable")] = (0, 1)
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/calendaruserproxy.py 2007-08-21 00:35:50 UTC (rev 1809)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/calendaruserproxy.py 2007-08-21 02:22:46 UTC (rev 1810)
@@ -24,6 +24,8 @@
"CalendarUserProxyPrincipalResource",
]
+from cgi import escape
+
from twisted.internet.defer import succeed
from twisted.python import log
from twisted.python.failure import Failure
@@ -91,15 +93,20 @@
@param parent: the parent of this resource.
@param proxyType: a C{str} containing the name of the resource.
"""
- super(CalendarUserProxyPrincipalResource, self).__init__(path, joinURL(parent.principalURL(), proxyType))
-
- self.parent = parent
- self.pcollection = self.parent.parent.parent
- self.proxyType = proxyType
- self._url = joinURL(parent.principalURL(), proxyType)
if self.isCollection():
- self._url += "/"
+ slash = "/"
+ else:
+ slash = ""
+ url = joinURL(parent.principalURL(), proxyType) + slash
+
+ super(CalendarUserProxyPrincipalResource, self).__init__(path, url)
+
+ self.parent = parent
+ self.proxyType = proxyType
+ self.pcollection = self.parent.parent.parent # FIXME: if this is supposed to be public, it needs a better name
+ self._url = url
+
# Not terribly useful at present because we don't have a way
# to map a GUID back to the correct principal.
#self.guid = uuidFromName(self.parent.principalUID(), proxyType)
@@ -108,10 +115,19 @@
# can easily map back to a principal.
self.uid = "%s#%s" % (self.parent.principalUID(), proxyType)
+ self._alternate_urls = tuple(
+ joinURL(url, proxyType) + slash
+ for url in parent.alternateURIs()
+ if url.startswith("/")
+ )
+
# Provision in __init__() because principals are used prior to request
# lookups.
self.provision()
+ def __str__(self):
+ return "%s [%s]" % (self.parent, self.proxyType)
+
def _index(self):
"""
Return the SQL database for this group principal.
@@ -169,7 +185,7 @@
for uri in members:
principal = self.pcollection._principalForURI(uri)
# Invalid principals MUST result in an error.
- if principal is None:
+ 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(),)
@@ -187,6 +203,8 @@
##
def renderDirectoryBody(self, request):
+ # FIXME: Too much code duplication here from principal.py
+
def format_list(items, *args):
def genlist():
try:
@@ -204,6 +222,12 @@
def link(url):
return """<a href="%s">%s</a>""" % (url, url)
+ def format_principals(principals):
+ return format_list(
+ """<a href="%s">%s</a>""" % (principal.principalURL(), escape(str(principal)))
+ for principal in principals
+ )
+
def gotSuper(output):
return "".join((
"""<div class="directory-listing">"""
@@ -228,9 +252,10 @@
#"""GUID: %s\n""" % (self.guid,),
"""Principal UID: %s\n""" % (self.principalUID(),),
"""Principal URL: %s\n""" % (link(self.principalURL()),),
- """\nAlternate URIs:\n""" , format_list(self.alternateURIs()),
- """\nGroup members (%s):\n""" % ({False:"Locked", True:"Editable"}[self.hasEditableMembership()]), format_list(link(p.principalURL()) for p in self.groupMembers()),
- """\nGroup memberships:\n""" , format_list(link(p.principalURL()) for p in self.groupMemberships()),
+ """\nAlternate URIs:\n""" , format_list(link(u) for u in self.alternateURIs()),
+ """\nGroup members (%s):\n""" % ({False:"Locked", True:"Editable"}[self.hasEditableMembership()])
+ , format_principals(self.groupMembers()),
+ """\nGroup memberships:\n""" , format_principals(self.groupMemberships()),
"""</pre></blockquote></div>""",
output
))
@@ -252,7 +277,7 @@
def alternateURIs(self):
# FIXME: Add API to IDirectoryRecord for getting a record URI?
- return ()
+ return self._alternate_urls
def principalURL(self):
return self._url
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/principal.py 2007-08-21 00:35:50 UTC (rev 1809)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/principal.py 2007-08-21 02:22:46 UTC (rev 1810)
@@ -22,10 +22,11 @@
__all__ = [
"DirectoryPrincipalProvisioningResource",
- "DirectoryPrincipalTypeResource",
+ "DirectoryPrincipalTypeProvisioningResource",
"DirectoryPrincipalResource",
]
+from cgi import escape
from urllib import unquote
from urlparse import urlparse
@@ -46,6 +47,9 @@
from twistedcaldav.static import AutoProvisioningFileMixIn
from twistedcaldav.directory.idirectory import IDirectoryService
+# Use __underbars__ convention to avoid conflicts with directory resource types.
+uidsResourceName = "__uids__"
+
# FIXME: These should not be tied to DAVFile
# The reason that they is that web2.dav only implements DAV methods on
# DAVFile instead of DAVResource. That should change.
@@ -64,30 +68,35 @@
CalendarPrincipalCollectionResource,
DAVFile,
):
- def principalForShortName(self, type, name):
- raise NotImplementedError("Subclass must implement principalForShortName()")
+ def __init__(self, path, url, directory):
+ """
+ @param path: the path to the file which will back the resource.
+ @param url: the canonical URL for the resource.
+ @param directory: an L{IDirectoryService} to provision principals from.
+ """
+ assert url.endswith("/"), "Collection URL must end in '/'"
+ CalendarPrincipalCollectionResource.__init__(self, url)
+ DAVFile.__init__(self, path)
+
+ self.directory = IDirectoryService(directory)
+
+ def principalForShortName(self, recordType, name):
+ return self.principalForRecord(self.directory.recordWithShortName(recordType, name))
+
def principalForUser(self, user):
return self.principalForShortName(DirectoryService.recordType_users, user)
def principalForGUID(self, guid):
- record = self.directory.recordWithGUID(guid)
- if record:
- return self.principalForRecord(record)
- else:
- return None
+ return self.principalForUID(guid)
def principalForUID(self, uid):
- if "#" in uid:
- # This UID belongs to a sub-principal
- parent_uid, subType = uid.split("#")
- return self.principalForGUID(parent_uid).getChild(subType)
- else:
- # This UID belongs to a primary principal (UID == GUID)
- return self.principalForGUID(uid)
+ raise NotImplementedError("Subclass must implement principalForUID()")
def principalForRecord(self, record):
- return self.principalForShortName(record.recordType, record.shortName)
+ if record is None:
+ return None
+ return self.principalForGUID(record.guid)
def principalForCalendarUserAddress(self, address):
raise NotImplementedError("Subclass must implement principalForCalendarUserAddress()")
@@ -97,31 +106,22 @@
Collection resource which provisions directory principals as its children.
"""
def __init__(self, path, url, directory):
- """
- @param path: the path to the file which will back the resource.
- @param url: the canonical URL for the resource.
- @param directory: an L{IDirectoryService} to provision principals from.
- """
- assert url.endswith("/"), "Collection URL must end in '/'"
+ DirectoryProvisioningResource.__init__(self, path, url, directory)
- CalendarPrincipalCollectionResource.__init__(self, url)
- DAVFile.__init__(self, path)
-
- self.directory = IDirectoryService(directory)
-
# FIXME: Smells like a hack
self.directory.principalCollection = self
+ #
# Create children
+ #
for recordType in self.directory.recordTypes():
- self.putChild(recordType, DirectoryPrincipalTypeResource(self.fp.child(recordType).path, self, recordType))
+ self.putChild(recordType, DirectoryPrincipalTypeProvisioningResource(self, recordType))
- def principalForShortName(self, type, name):
- typeResource = self.getChild(type)
- if typeResource is None:
- return None
- return typeResource.getChild(name)
+ self.putChild(uidsResourceName, DirectoryPrincipalUIDProvisioningResource(self))
+ def principalForUID(self, uid):
+ return self.getChild(uidsResourceName).getChild(uid)
+
def _principalForURI(self, uri):
scheme, netloc, path, params, query, fragment = urlparse(uri)
@@ -196,10 +196,13 @@
def getChild(self, name):
self.provision()
- return self.putChildren.get(name, None)
+ if name == "":
+ return self
+ else:
+ return self.putChildren.get(name, None)
def listChildren(self):
- return self.putChildren.keys()
+ return self.directory.recordTypes()
##
# ACL
@@ -208,25 +211,29 @@
def principalCollections(self):
return (self,)
-class DirectoryPrincipalTypeResource (DirectoryProvisioningResource):
+class DirectoryPrincipalTypeProvisioningResource (DirectoryProvisioningResource):
"""
- Collection resource which provisions directory principals of a specific type as its children.
+ Collection resource which provisions directory principals of a
+ specific type as its children, indexed by short name.
"""
- def __init__(self, path, parent, recordType):
+ def __init__(self, parent, recordType):
"""
@param path: the path to the file which will back the resource.
- @param directory: an L{IDirectoryService} to provision calendars from.
+ @param parent: the parent L{DirectoryPrincipalProvisioningResource}.
@param recordType: the directory record type to provision.
"""
- CalendarPrincipalCollectionResource.__init__(self, joinURL(parent.principalCollectionURL(), recordType) + "/")
- DAVFile.__init__(self, path)
+ DirectoryProvisioningResource.__init__(
+ self,
+ parent.fp.child(recordType).path,
+ joinURL(parent.principalCollectionURL(), recordType) + "/",
+ parent.directory
+ )
- self.directory = parent.directory
self.recordType = recordType
self.parent = parent
- def principalForShortName(self, type, name):
- return self.parent.principalForShortName(type, name)
+ def principalForUID(self, uid):
+ return self.parent.principalForUID(uid)
def principalForCalendarUserAddress(self, address):
return self.parent.principalForCalendarUserAddress(address)
@@ -239,24 +246,86 @@
log.err("Attempt to create clone %r of resource %r" % (path, self))
raise HTTPError(responsecode.NOT_FOUND)
- def getChild(self, name, record=None):
+ def getChild(self, name):
self.provision()
if name == "":
return self
+ else:
+ return self.principalForShortName(self.recordType, name)
+ def listChildren(self):
+ return (record.shortName for record in self.directory.listRecords(self.recordType))
+
+ ##
+ # ACL
+ ##
+
+ def principalCollections(self):
+ return self.parent.principalCollections()
+
+class DirectoryPrincipalUIDProvisioningResource (DirectoryProvisioningResource):
+ """
+ Collection resource which provisions directory principals indexed
+ by UID.
+ """
+ # FIXME: Remove path argument
+ def __init__(self, parent):
+ """
+ @param path: the path to the file which will back the resource.
+ @param directory: an L{IDirectoryService} to provision calendars from.
+ @param recordType: the directory record type to provision.
+ """
+ DirectoryProvisioningResource.__init__(
+ self,
+ parent.fp.child(uidsResourceName).path,
+ joinURL(parent.principalCollectionURL(), uidsResourceName) + "/",
+ parent.directory
+ )
+
+ self.parent = parent
+
+ def principalForUID(self, uid):
+ return self.parent.principalForUID(uid)
+
+ def principalForCalendarUserAddress(self, address):
+ return self.parent.principalForCalendarUserAddress(address)
+
+ ##
+ # Static
+ ##
+
+ def createSimilarFile(self, path):
+ log.err("Attempt to create clone %r of resource %r" % (path, self))
+ raise HTTPError(responsecode.NOT_FOUND)
+
+ def getChild(self, name):
+ self.provision()
+ if name == "":
+ return self
+
+ if "#" in name:
+ # This UID belongs to a sub-principal
+ primaryUID, subType = name.split("#")
+ else:
+ primaryUID = name
+ subType = None
+
+ record = self.directory.recordWithGUID(primaryUID)
+
if record is None:
- record = self.directory.recordWithShortName(self.recordType, name)
- if record is None:
- #log.err("No directory record (%s)%s; cannot create principal resource." % (self.recordType, name))
- return None
+ log.err("No principal found for UID: %s" % (name,))
+ return None
+
+ primaryPrincipal = DirectoryPrincipalResource(self.fp.child(name).path, self, record)
+
+ if subType is None:
+ return primaryPrincipal
else:
- assert name is None
- name = record.shortName
+ return primaryPrincipal.getChild(subType)
- return DirectoryPrincipalResource(self.fp.child(name).path, self, record)
-
def listChildren(self):
- return (record.shortName for record in self.directory.listRecords(self.recordType))
+ # Not a listable collection
+ raise HTTPError(responsecode.FORBIDDEN)
##
# ACL
@@ -275,18 +344,32 @@
@param parent: the parent of this resource.
@param record: the L{IDirectoryRecord} that this resource represents.
"""
- super(DirectoryPrincipalResource, self).__init__(path, joinURL(parent.principalCollectionURL(), record.shortName))
+ if self.isCollection():
+ slash = "/"
+ else:
+ slash = ""
+ assert record is not None, "Principal must have a directory record: %s" % (path,)
+
+ url = joinURL(parent.principalCollectionURL(), record.guid) + slash
+
+ super(DirectoryPrincipalResource, self).__init__(path, url)
+
self.record = record
self.parent = parent
- self._url = joinURL(parent.principalCollectionURL(), record.shortName)
- if self.isCollection():
- self._url += "/"
+ self._url = url
+ self._alternate_urls = (
+ joinURL(parent.parent.principalCollectionURL(), record.recordType, record.shortName) + slash,
+ )
+
# Provision in __init__() because principals are used prior to request
# lookups.
self.provision()
+ def __str__(self):
+ return "(%s) %s" % (self.record.recordType, self.record.shortName)
+
##
# HTTP
##
@@ -306,6 +389,12 @@
yield " ** %s **: %s\n" % (e.__class__.__name__, e)
return "".join(genlist())
+ def format_principals(principals):
+ return format_list(
+ """<a href="%s">%s</a>""" % (principal.principalURL(), escape(str(principal)))
+ for principal in principals
+ )
+
def link(url):
return """<a href="%s">%s</a>""" % (url, url)
@@ -327,9 +416,9 @@
"""Full name: %s\n""" % (self.record.fullName,),
"""Principal UID: %s\n""" % (self.principalUID(),),
"""Principal URL: %s\n""" % (link(self.principalURL()),),
- """\nAlternate URIs:\n""" , format_list(self.alternateURIs()),
- """\nGroup members:\n""" , format_list(link(p.principalURL()) for p in self.groupMembers()),
- """\nGroup memberships:\n""" , format_list(link(p.principalURL()) for p in self.groupMemberships()),
+ """\nAlternate URIs:\n""" , format_list(link(u) for u in self.alternateURIs()),
+ """\nGroup members:\n""" , format_principals(self.groupMembers()),
+ """\nGroup memberships:\n""" , format_principals(self.groupMemberships()),
"""\nCalendar homes:\n""" , format_list(link(u) for u in self.calendarHomeURLs()),
"""\nCalendar user addresses:\n""" , format_list(link(a) for a in self.calendarUserAddresses()),
"""</pre></blockquote></div>""",
@@ -356,7 +445,7 @@
def alternateURIs(self):
# FIXME: Add API to IDirectoryRecord for getting a record URI?
- return ()
+ return self._alternate_urls
def principalURL(self):
return self._url
@@ -374,11 +463,8 @@
myRecordType = self.record.recordType
for relative in getattr(record, method)():
if relative not in records:
- if relative.recordType == myRecordType:
- found = self.parent.getChild(None, record=relative)
- else:
- found = self.parent.parent.getChild(relative.recordType).getChild(None, record=relative)
-
+ found = self.parent.principalForRecord(relative)
+
if proxy:
found = found.getChild("calendar-proxy-write")
relatives.add(found)
@@ -434,14 +520,18 @@
return self.record.guid
def calendarUserAddresses(self):
- # Add the principal URL and GUID to whatever calendar user addresses
- # the directory record provides.
+ # Get any CUAs defined by the directory implementation.
addresses = set(self.record.calendarUserAddresses)
- addresses.add(self.principalURL())
- if config.HTTPPort:
- addresses.add("http://%s:%s%s" % (config.ServerHostName, config.HTTPPort, self.principalURL(),))
- if config.SSLPort:
- addresses.add("https://%s:%s%s" % (config.ServerHostName, config.SSLPort, self.principalURL(),))
+
+ # Add the principal URL and alternate URIs to the list.
+ for uri in ((self.principalURL(),) + tuple(self.alternateURIs())):
+ addresses.add(uri)
+ if config.HTTPPort:
+ addresses.add("http://%s:%s%s" % (config.ServerHostName, config.HTTPPort, uri))
+ if config.SSLPort:
+ addresses.add("https://%s:%s%s" % (config.ServerHostName, config.SSLPort, uri))
+
+ # Add a UUID URI based on the record's GUID to the list.
addresses.add("urn:uuid:%s" % (self.record.guid,))
return addresses
@@ -515,7 +605,7 @@
log.err("Attempt to create clone %r of resource %r" % (path, self))
raise HTTPError(responsecode.NOT_FOUND)
- def getChild(self, name, record=None):
+ def getChild(self, name):
if name == "":
return self
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_principal.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_principal.py 2007-08-21 00:35:50 UTC (rev 1809)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/test/test_principal.py 2007-08-21 02:22:46 UTC (rev 1810)
@@ -38,7 +38,7 @@
from twistedcaldav.directory.xmlfile import XMLDirectoryService
from twistedcaldav.directory.test.test_xmlfile import xmlFile
from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
-from twistedcaldav.directory.principal import DirectoryPrincipalTypeResource
+from twistedcaldav.directory.principal import DirectoryPrincipalTypeProvisioningResource
from twistedcaldav.directory.principal import DirectoryPrincipalResource
import twistedcaldav.test.util
@@ -80,10 +80,10 @@
DirectoryPrincipalProvisioningResource.principalCollectionURL(),
DirectoryPrincipalProvisioningResource.principalCollections()
- DirectoryPrincipalTypeResource.listChildren(),
- DirectoryPrincipalTypeResource.getChildren(),
- DirectoryPrincipalTypeResource.principalCollectionURL(),
- DirectoryPrincipalTypeResource.principalCollections()
+ DirectoryPrincipalTypeProvisioningResource.listChildren(),
+ DirectoryPrincipalTypeProvisioningResource.getChildren(),
+ DirectoryPrincipalTypeProvisioningResource.principalCollectionURL(),
+ DirectoryPrincipalTypeProvisioningResource.principalCollections()
DirectoryPrincipalResource.principalURL(),
"""
@@ -103,7 +103,7 @@
for recordType in recordTypes:
#print " -> %s" % (recordType,)
typeResource = provisioningResource.getChild(recordType)
- self.failUnless(isinstance(typeResource, DirectoryPrincipalTypeResource))
+ self.failUnless(isinstance(typeResource, DirectoryPrincipalTypeProvisioningResource))
typeURL = provisioningURL + recordType + "/"
self.assertEquals(typeURL, typeResource.principalCollectionURL())
@@ -120,7 +120,7 @@
self.failUnless(isinstance(recordResource, DirectoryPrincipalResource))
recordURL = typeURL + shortName + "/"
- self.assertEquals(recordURL, recordResource.principalURL())
+ self.assertIn(recordURL, (recordResource.principalURL(),) + tuple(recordResource.alternateURIs()))
principalCollections = recordResource.principalCollections()
self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
@@ -202,7 +202,7 @@
if record.shortName == "gemini":
self.assertTrue(principal.autoSchedule())
- # FIXME: Run DirectoryPrincipalProvisioningResource tests on DirectoryPrincipalTypeResource also
+ # FIXME: Run DirectoryPrincipalProvisioningResource tests on DirectoryPrincipalTypeProvisioningResource also
##
# DirectoryPrincipalResource
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlaccountsparser.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlaccountsparser.py 2007-08-21 00:35:50 UTC (rev 1809)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlaccountsparser.py 2007-08-21 02:22:46 UTC (rev 1810)
@@ -168,6 +168,10 @@
shortName = self.shortName % ctr
else:
shortName = self.shortName
+ if self.guid and self.guid.find("%") != -1:
+ guid = self.guid % ctr
+ else:
+ guid = self.guid
if self.password.find("%") != -1:
password = self.password % ctr
else:
@@ -185,6 +189,7 @@
result = XMLAccountRecord(self.recordType)
result.shortName = shortName
+ result.guid = guid
result.password = password
result.name = name
result.members = self.members
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlfile.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlfile.py 2007-08-21 00:35:50 UTC (rev 1809)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/directory/xmlfile.py 2007-08-21 02:22:46 UTC (rev 1810)
@@ -83,8 +83,11 @@
return None
def _entriesForRecordType(self, recordType):
- for entry in self._accounts()[recordType].itervalues():
- yield entry.shortName, entry
+ try:
+ for entry in self._accounts()[recordType].itervalues():
+ yield entry.shortName, entry
+ except KeyError:
+ return
def _accounts(self):
self.xmlFile.restat()
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/root.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/root.py 2007-08-21 00:35:50 UTC (rev 1809)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/root.py 2007-08-21 02:22:46 UTC (rev 1810)
@@ -86,17 +86,24 @@
request.authzUser = authzUser
# Figure out the "username" from the davxml.Principal object
- username = authzUser.children[0].children[0].data
- username = username.rstrip('/').split('/')[-1]
+ request.checkingSACL = True
+ d = request.locateResource(authzUser.children[0].children[0].data)
- if RootResource.CheckSACL(username, self.saclService) != 0:
- log.msg("User '%s' is not enabled with the '%s' SACL" % (username, self.saclService,))
- return Failure(HTTPError(403))
+ def _checkedSACLCb(principal):
+ delattr(request, "checkingSACL")
+ username = principal.record.shortName
+
+ if RootResource.CheckSACL(username, self.saclService) != 0:
+ log.msg("User '%s' is not enabled with the '%s' SACL" % (username, self.saclService,))
+ return Failure(HTTPError(403))
+
+ # Mark SACL's as having been checked so we can avoid doing it multiple times
+ request.checkedSACL = True
+ return True
+
+ d.addCallback(_checkedSACLCb)
+ return d
- # Mark SACL's as having been checked so we can avoid doing it multiple times
- request.checkedSACL = True
- return True
-
d = defer.maybeDeferred(self.authenticate, request)
d.addCallbacks(_authCb, _authEb)
d.addCallback(_checkSACLCb)
@@ -106,7 +113,7 @@
for filter in self.contentFilters:
request.addResponseFilter(filter[0], atEnd=filter[1])
- if self.useSacls and not hasattr(request, "checkedSACL"):
+ if self.useSacls and not hasattr(request, "checkedSACL") and not hasattr(request, "checkingSACL"):
d = self.checkSacl(request)
d.addCallback(lambda _: super(RootResource, self
).locateChild(request, segments))
Modified: CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/test/test_root.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/test/test_root.py 2007-08-21 00:35:50 UTC (rev 1809)
+++ CalendarServer/branches/release/CalendarServer-1.0-dev/twistedcaldav/test/test_root.py 2007-08-21 02:22:46 UTC (rev 1810)
@@ -141,7 +141,7 @@
self.assertEquals(request.authzUser,
davxml.Principal(
- davxml.HRef('/principals/users/dreid/')))
+ davxml.HRef('/principals/__uids__/5FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1/')))
d = defer.maybeDeferred(resrc.locateChild, request, ['principals'])
d.addCallback(_Cb)
@@ -169,6 +169,7 @@
['principals'])
def _Eb(failure):
+ failure.trap(HTTPError)
self.assertEquals(failure.value.response.code, 403)
d = defer.maybeDeferred(resrc.locateChild, request, ['principals'])
@@ -198,7 +199,6 @@
def _Eb(failure):
failure.trap(HTTPError)
-
self.assertEquals(failure.value.response.code, 401)
d = defer.maybeDeferred(resrc.locateChild, request, ['principals'])
@@ -229,6 +229,7 @@
['principals'])
def _Eb(failure):
+ failure.trap(HTTPError)
self.assertEquals(failure.value.response.code, 401)
d = defer.maybeDeferred(resrc.locateChild, request, ['principals'])
@@ -275,4 +276,4 @@
headers=http_headers.Headers({"Destination":"/copy/"})
)
return self.send(request, do_test)
-
\ No newline at end of file
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20070820/55daacdc/attachment.html
More information about the calendarserver-changes
mailing list