[CalendarServer-changes] [4524] CalendarServer/branches/more-deferreds-3
source_changes at macosforge.org
source_changes at macosforge.org
Thu Sep 3 10:58:16 PDT 2009
Revision: 4524
http://trac.macosforge.org/projects/calendarserver/changeset/4524
Author: sagen at apple.com
Date: 2009-09-03 10:58:15 -0700 (Thu, 03 Sep 2009)
Log Message:
-----------
Checkpoint -- more API deferred
Modified Paths:
--------------
CalendarServer/branches/more-deferreds-3/calendarserver/provision/root.py
CalendarServer/branches/more-deferreds-3/calendarserver/sidecar/task.py
CalendarServer/branches/more-deferreds-3/calendarserver/tools/principals.py
CalendarServer/branches/more-deferreds-3/calendarserver/tools/util.py
CalendarServer/branches/more-deferreds-3/calendarserver/webadmin/resource.py
CalendarServer/branches/more-deferreds-3/calendarserver/webcal/resource.py
CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.resource.patch
CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch
CalendarServer/branches/more-deferreds-3/twistedcaldav/accesslog.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/aggregate.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/appleopendirectory.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/cachingdirectory.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendar.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendaruserproxy.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/directory.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/principal.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/resource.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sudo.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_cachedirectory.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_calendar.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_guidchange.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_opendirectory.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_principal.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_proxyprincipalmembers.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_sudo.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_xmlfile.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/util.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/wiki.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/xmlfile.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/extensions.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/freebusyurl.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/index.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/mail.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_common.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_multiget.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/resource.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/schedule.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/implicit.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/scheduler.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/static.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_mkcalendar.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/timezoneservice.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/upgrade.py
Removed Paths:
-------------
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/apache.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldappleopendirectory.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldxmlfile.py
CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sqldb.py
Modified: CalendarServer/branches/more-deferreds-3/calendarserver/provision/root.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/provision/root.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/provision/root.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -19,7 +19,7 @@
"RootResource",
]
-from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
from twisted.cred.error import LoginFailed, UnauthorizedLogin
from twisted.web2 import responsecode
@@ -95,7 +95,7 @@
return self._dead_properties
def defaultAccessControlList(self):
- return config.RootResourceACL
+ return succeed(config.RootResourceACL)
@inlineCallbacks
def checkSacl(self, request):
@@ -135,7 +135,7 @@
request.checkingSACL = True
for collection in self.principalCollections():
- principal = collection._principalForURI(authzUser.children[0].children[0].data)
+ principal = (yield collection._principalForURI(authzUser.children[0].children[0].data))
if principal is None:
response = (yield UnauthorizedResponse.makeResponse(
request.credentialFactories,
@@ -180,14 +180,14 @@
username = (yield proxy.callRemote(wikiConfig["UserMethod"], token))
log.debug("Wiki lookup returned user: %s" % (username,))
directory = request.site.resource.getDirectory()
- record = directory.recordWithShortName("users", username)
+ record = (yield directory.recordWithShortName("users", username))
if record is None:
raise HTTPError(StatusResponse(
responsecode.FORBIDDEN,
"The username (%s) corresponding to your sessionID was not found by calendar server." % (username,)
))
for collection in self.principalCollections():
- principal = collection.principalForRecord(record)
+ principal = (yield collection.principalForRecord(record))
if principal is not None:
break
else:
@@ -217,8 +217,7 @@
davxml.HRef.fromString("/principals/wikis/%s/" % (wikiName,))
)
- child = (yield super(RootResource, self).locateChild(request, segments))
- returnValue(child)
+ returnValue((yield super(RootResource, self).locateChild(request, segments)))
# FIXME: should catch something more specific than Exception
except Exception, e:
@@ -275,8 +274,7 @@
except KeyError:
pass
- child = (yield super(RootResource, self).locateChild(request, segments))
- returnValue(child)
+ returnValue((yield super(RootResource, self).locateChild(request, segments)))
def http_COPY (self, request): return responsecode.FORBIDDEN
def http_MOVE (self, request): return responsecode.FORBIDDEN
Modified: CalendarServer/branches/more-deferreds-3/calendarserver/sidecar/task.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/sidecar/task.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/sidecar/task.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -92,7 +92,7 @@
log.debug("Processing inbox item %s" % (inboxItemFile,))
principals = rootResource.getChild("principals")
- ownerPrincipal = principals.principalForUID(uuid)
+ ownerPrincipal = (yield principals.principalForUID(uuid))
cua = "urn:uuid:%s" % (uuid,)
owner = LocalCalendarUser(cua, ownerPrincipal,
inboxFile, ownerPrincipal.scheduleInboxURL())
@@ -111,7 +111,7 @@
# originator is the organizer
originator = calendar.getOrganizer()
- originatorPrincipal = principals.principalForCalendarUserAddress(originator)
+ originatorPrincipal = (yield principals.principalForCalendarUserAddress(originator))
originator = LocalCalendarUser(originator, originatorPrincipal)
recipients = (owner,)
scheduler = DirectScheduler(FakeRequest(rootResource, "PUT"), inboxItemFile)
Modified: CalendarServer/branches/more-deferreds-3/calendarserver/tools/principals.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/tools/principals.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/tools/principals.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -144,6 +144,7 @@
raise AssertionError("Unknown proxy type")
try:
+ # MOR: what to do here?
principalForPrincipalID(arg, checkOnly=True)
except ValueError, e:
abort(e)
@@ -152,6 +153,7 @@
elif opt in ("", "--remove-proxy"):
try:
+ # MOR: what to do here?
principalForPrincipalID(arg, checkOnly=True)
except ValueError, e:
abort(e)
@@ -201,6 +203,7 @@
#
for arg in args:
try:
+ # MOR: what to do here?
principalForPrincipalID(arg, checkOnly=True)
except ValueError, e:
abort(e)
@@ -256,7 +259,7 @@
for principalID in principalIDs:
# Resolve the given principal IDs to principals
try:
- principal = principalForPrincipalID(principalID)
+ principal = (yield principalForPrincipalID(principalID))
except ValueError:
principal = None
@@ -275,6 +278,7 @@
#
reactor.stop()
+ at inlineCallbacks
def principalForPrincipalID(principalID, checkOnly=False, directory=None):
# Allow a directory parameter to be passed in, but default to config.directory
@@ -287,14 +291,14 @@
raise ValueError("Can't resolve paths yet")
if checkOnly:
- return None
+ returnValue(None)
if principalID.startswith("("):
try:
i = principalID.index(")")
if checkOnly:
- return None
+ returnValue(None)
recordType = principalID[1:i]
shortName = principalID[i+1:]
@@ -302,26 +306,26 @@
if not recordType or not shortName or "(" in recordType:
raise ValueError()
- return directory.principalCollection.principalForShortName(recordType, shortName)
+ returnValue((yield directory.principalCollection.principalForShortName(recordType, shortName)))
except ValueError:
pass
if ":" in principalID:
if checkOnly:
- return None
+ returnValue(None)
recordType, shortName = principalID.split(":", 1)
- return directory.principalCollection.principalForShortName(recordType, shortName)
+ returnValue((yield directory.principalCollection.principalForShortName(recordType, shortName)))
try:
guid = UUID(principalID)
if checkOnly:
- return None
+ returnValue(None)
- return directory.principalCollection.principalForUID(guid)
+ returnValue((yield directory.principalCollection.principalForUID(guid)))
except ValueError:
pass
@@ -340,7 +344,7 @@
@inlineCallbacks
def action_listProxies(principal, *proxyTypes):
for proxyType in proxyTypes:
- subPrincipal = proxySubprincipal(principal, proxyType)
+ subPrincipal = (yield proxySubprincipal(principal, proxyType))
if subPrincipal is None:
print "No %s proxies for %s" % (proxyType, principal)
continue
@@ -360,7 +364,7 @@
@inlineCallbacks
def action_addProxy(principal, proxyType, *proxyIDs):
for proxyID in proxyIDs:
- proxyPrincipal = principalForPrincipalID(proxyID)
+ proxyPrincipal = (yield principalForPrincipalID(proxyID))
(yield action_addProxyPrincipal(principal, proxyType, proxyPrincipal))
@inlineCallbacks
@@ -393,7 +397,7 @@
@inlineCallbacks
def action_removeProxy(principal, *proxyIDs, **kwargs):
for proxyID in proxyIDs:
- proxyPrincipal = principalForPrincipalID(proxyID)
+ proxyPrincipal = (yield principalForPrincipalID(proxyID))
(yield action_removeProxyPrincipal(principal, proxyPrincipal, **kwargs))
@inlineCallbacks
@@ -402,7 +406,7 @@
for proxyType in proxyTypes:
proxyURL = proxyPrincipal.url()
- subPrincipal = proxySubprincipal(principal, proxyType)
+ subPrincipal = (yield proxySubprincipal(principal, proxyType))
if subPrincipal is None:
sys.stderr.write("Unable to edit %s proxies for %s\n" % (proxyType, principal))
continue
Modified: CalendarServer/branches/more-deferreds-3/calendarserver/tools/util.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/tools/util.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/tools/util.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -25,6 +25,7 @@
import os
from time import sleep
+from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.python.reflect import namedClass
import socket
@@ -69,21 +70,24 @@
principalCollection = property(getPrincipalCollection, setPrincipalCollection)
+ @inlineCallbacks
def calendarHomeForRecord(self, record):
- principal = self.principalCollection.principalForRecord(record)
+ principal = (yield self.principalCollection.principalForRecord(record))
if principal:
try:
- return principal.calendarHome()
+ returnValue(principal.calendarHome())
except AttributeError:
pass
- return None
+ returnValue(None)
+ @inlineCallbacks
def calendarHomeForShortName(self, recordType, shortName):
- principal = self.principalCollection.principalForShortName(recordType, shortName)
+ principal = (yield self.principalCollection.principalForShortName(recordType, shortName))
if principal:
- return principal.calendarHome()
- return None
+ returnValue(principal.calendarHome())
+ returnValue(None)
+ # Deferred
def principalForCalendarUserAddress(self, cua):
return self.principalCollection.principalForCalendarUserAddress(cua)
@@ -100,7 +104,7 @@
baseGUID = "51856FD4-5023-4890-94FE-4356C4AAC3E4"
def recordTypes(self): return ()
def listRecords(self): return ()
- def recordWithShortName(self): return None
+ def recordWithShortName(self): return succeed(None)
dummyDirectoryRecord = DirectoryRecord(
service = DummyDirectoryService(),
Modified: CalendarServer/branches/more-deferreds-3/calendarserver/webadmin/resource.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/webadmin/resource.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/webadmin/resource.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -48,7 +48,7 @@
# Only allow administrators to access
def defaultAccessControlList(self):
- return davxml.ACL(*config.AdminACEs)
+ return succeed(davxml.ACL(*config.AdminACEs))
def etag(self):
# Can't be calculated here
@@ -149,7 +149,7 @@
# Add details if a resource has been selected.
if resourceId:
- principal = self.getResourceById(request, resourceId)
+ principal = (yield self.getResourceById(request, resourceId))
# Update the auto-schedule value if specified.
if autoSchedule is not None and (autoSchedule == "true" or autoSchedule == "false"):
@@ -158,15 +158,15 @@
# Update the proxies if specified.
for proxyId in removeProxies:
- proxy = self.getResourceById(request, proxyId)
+ proxy = (yield self.getResourceById(request, proxyId))
(yield action_removeProxyPrincipal(principal, proxy, proxyTypes=["read", "write"]))
for proxyId in makeReadProxies:
- proxy = self.getResourceById(request, proxyId)
+ proxy = (yield self.getResourceById(request, proxyId))
(yield action_addProxyPrincipal(principal, "read", proxy))
for proxyId in makeWriteProxies:
- proxy = self.getResourceById(request, proxyId)
+ proxy = (yield self.getResourceById(request, proxyId))
(yield action_addProxyPrincipal(principal, "write", proxy))
# Add the detailed content
@@ -435,6 +435,7 @@
htmlContent.addCallback(_defer)
return htmlContent
+ # Deferred
def getResourceById(self, request, resourceId):
if resourceId.startswith("/"):
return request.locateResource(resourceId)
Modified: CalendarServer/branches/more-deferreds-3/calendarserver/webcal/resource.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/webcal/resource.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/webcal/resource.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -41,15 +41,17 @@
class WebCalendarResource (ReadOnlyResourceMixIn, DAVFile):
def defaultAccessControlList(self):
- return davxml.ACL(
- davxml.ACE(
- davxml.Principal(davxml.Authenticated()),
- davxml.Grant(
- davxml.Privilege(davxml.Read()),
+ return succeed(
+ davxml.ACL(
+ davxml.ACE(
+ davxml.Principal(davxml.Authenticated()),
+ davxml.Grant(
+ davxml.Privilege(davxml.Read()),
+ ),
+ davxml.Protected(),
+ TwistedACLInheritable(),
),
- davxml.Protected(),
- TwistedACLInheritable(),
- ),
+ )
)
def etag(self):
Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.resource.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.resource.patch 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.resource.patch 2009-09-03 17:58:15 UTC (rev 4524)
@@ -13,7 +13,7 @@
from twisted.python import log
from twisted.python.failure import Failure
-from twisted.internet.defer import Deferred, maybeDeferred, succeed
-+from twisted.internet.defer import Deferred, maybeDeferred, succeed, inlineCallbacks
++from twisted.internet.defer import Deferred, maybeDeferred, succeed, inlineCallbacks, returnValue
from twisted.internet.defer import waitForDeferred, deferredGenerator
-from twisted.cred.error import LoginFailed, UnauthorizedLogin
from twisted.internet import reactor
@@ -126,7 +126,7 @@
if (qname not in qnames) and (qname[0] != twisted_private_namespace):
qnames.add(qname)
-@@ -495,37 +529,54 @@
+@@ -495,37 +529,62 @@
in the dead property store may or may not be ignored when reading the
property with L{readProperty}.
"""
@@ -177,25 +177,32 @@
+ d.addCallback(callback)
+ return d
++ @inlineCallbacks
def displayName(self):
- if self.hasDeadProperty((davxml.dav_namespace, "displayname")):
- return str(self.readDeadProperty((davxml.dav_namespace, "displayname")))
-- else:
++ if (yield self.hasDeadProperty((davxml.dav_namespace, "displayname"))):
++ returnValue(str((yield self.readDeadProperty((davxml.dav_namespace, "displayname")))))
+ else:
- return super(DAVPropertyMixIn, self).displayName()
++ returnValue((yield super(DAVPropertyMixIn, self).displayName()))
+
++ """
+ def callback(result):
+ if result:
+ return str(self.readDeadProperty((davxml.dav_namespace, "displayname")))
+ else:
+ return super(DAVPropertyMixIn, self).displayName()
-
++
+ d = self.hasDeadProperty((davxml.dav_namespace, "displayname"))
+ d.addCallback(callback)
+ return d
++ """
+
class DAVResource (DAVPropertyMixIn, StaticRenderMixin):
"""
WebDAV resource.
-@@ -578,11 +629,10 @@
+@@ -578,11 +637,10 @@
completionDeferred = Deferred()
basepath = request.urlForResource(self)
@@ -209,7 +216,7 @@
def checkPrivileges(child):
if child is None:
-@@ -595,7 +645,7 @@
+@@ -595,7 +653,7 @@
d.addCallback(lambda _: child)
return d
@@ -218,7 +225,7 @@
if child is None:
callback(None, childpath + "/")
else:
-@@ -603,14 +653,15 @@
+@@ -603,14 +661,15 @@
callback(child, childpath + "/")
if depth == "infinity":
d = child.findChildren(depth, request, callback, privileges)
@@ -237,7 +244,7 @@
try:
childname = children.pop()
except IndexError:
-@@ -619,10 +670,10 @@
+@@ -619,10 +678,10 @@
childpath = joinURL(basepath, childname)
d = request.locateChildResource(self, childname)
d.addCallback(checkPrivileges)
@@ -250,7 +257,7 @@
return completionDeferred
-@@ -642,41 +693,43 @@
+@@ -642,41 +701,43 @@
# Authentication
##
@@ -321,7 +328,25 @@
def authenticate(self, request):
if not (
hasattr(request, 'portal') and
-@@ -781,7 +834,7 @@
+@@ -761,7 +822,7 @@
+ # and deny any type of write access (PUT, DELETE, etc.) to
+ # everything.
+ #
+- return readonlyACL
++ return succeed(readonlyACL)
+
+ def defaultAccessControlList(self):
+ """
+@@ -772,7 +833,7 @@
+ # The default behaviour is no ACL; we should inherrit from the parent
+ # collection.
+ #
+- return davxml.ACL()
++ return succeed(davxml.ACL())
+
+ def setAccessControlList(self, acl):
+ """
+@@ -781,7 +842,7 @@
This implementation stores the ACL in the private property
C{(L{twisted_private_namespace}, "acl")}.
"""
@@ -330,7 +355,7 @@
def mergeAccessControlList(self, new_acl, request):
"""
-@@ -926,7 +979,9 @@
+@@ -926,7 +987,9 @@
# FIXME: verify acl is self-consistent
# Step 11
@@ -341,7 +366,7 @@
yield None
mergeAccessControlList = deferredGenerator(mergeAccessControlList)
-@@ -1089,7 +1144,9 @@
+@@ -1089,7 +1152,9 @@
return url
try:
@@ -352,8 +377,68 @@
except HTTPError, e:
assert e.response.code == responsecode.NOT_FOUND, (
"Expected %s response from readDeadProperty() exception, not %s"
-@@ -1635,7 +1692,9 @@
+@@ -1102,9 +1167,11 @@
+ if myURL == "/":
+ # If we get to the root without any ACLs, then use the default.
+- acl = self.defaultRootAccessControlList()
++ acl = waitForDeferred(self.defaultRootAccessControlList())
+ else:
+- acl = self.defaultAccessControlList()
++ acl = waitForDeferred(self.defaultAccessControlList())
++ yield acl
++ acl = acl.getResult()
+
+ # Dynamically update privileges for those ace's that are inherited.
+ if inheritance:
+@@ -1223,16 +1290,21 @@
+ It will errback with an HTTPError(responsecode.FORBIDDEN) if
+ the principal isn't found.
+ """
+- authnPrincipal = self.findPrincipalForAuthID(authid)
++ authnPrincipal = waitForDeferred(self.findPrincipalForAuthID(authid))
++ yield authnPrincipal
++ authnPrincipal = authnPrincipal.getResult()
+
+ if authnPrincipal is None:
+ log.msg("Could not find the principal resource for user id: %s" % (authid,))
+ raise HTTPError(responsecode.FORBIDDEN)
+
+- d = self.authorizationPrincipal(request, authid, authnPrincipal)
+- d.addCallback(lambda authzPrincipal: (authnPrincipal, authzPrincipal))
+- return d
++ authzPrincipal = waitForDeferred(self.authorizationPrincipal(request, authid, authnPrincipal))
++ yield authzPrincipal
++ authzPrincipal = authzPrincipal.getResult()
++ yield (authnPrincipal, authzPrincipal)
+
++ principalsForAuthID = deferredGenerator(principalsForAuthID)
++
+ def findPrincipalForAuthID(self, authid):
+ """
+ Return authentication and authoirization prinicipal identifiers for the
+@@ -1247,11 +1319,16 @@
+ If not found return None.
+ """
+ for collection in self.principalCollections():
+- principal = collection.principalForUser(authid)
++ principal = waitForDeferred(collection.principalForUser(authid))
++ yield principal
++ principal = principal.getResult()
+ if principal is not None:
+- return principal
+- return None
++ yield principal
++ return
++ yield None
+
++ findPrincipalForAuthID = deferredGenerator(findPrincipalForAuthID)
++
+ def authorizationPrincipal(self, request, authid, authnPrincipal):
+ """
+ Determine the authorization principal for the given request and authentication principal.
+@@ -1635,7 +1712,9 @@
+
# Check this resource first
if self.isCollection():
- qroot = self.quotaRoot(request)
@@ -363,7 +448,7 @@
if qroot is not None:
used = waitForDeferred(self.currentQuotaUse(request))
yield used
-@@ -1666,14 +1725,17 @@
+@@ -1666,14 +1745,17 @@
def hasQuota(self, request):
"""
@@ -383,7 +468,7 @@
yield True
return
-@@ -1705,10 +1767,19 @@
+@@ -1705,10 +1787,19 @@
@return: a C{int} containing the maximum allowed bytes if this collection
is quota-controlled, or C{None} if not quota controlled.
"""
@@ -406,7 +491,7 @@
def quotaRootParent(self, request):
"""
-@@ -1724,7 +1795,10 @@
+@@ -1724,7 +1815,10 @@
parent = waitForDeferred(request.locateResource(url))
yield parent
parent = parent.getResult()
@@ -418,7 +503,7 @@
yield parent
return
-@@ -1741,11 +1815,19 @@
+@@ -1741,11 +1835,19 @@
assert maxsize is None or isinstance(maxsize, int), "maxsize must be an int or None"
if maxsize is not None:
@@ -441,7 +526,7 @@
def quotaSize(self, request):
"""
-@@ -1795,7 +1877,10 @@
+@@ -1795,7 +1897,10 @@
# Check this resource first
if self.isCollection():
@@ -453,7 +538,7 @@
d = waitForDeferred(self.updateQuotaUse(request, adjust))
yield d
d.getResult()
-@@ -1825,20 +1910,34 @@
+@@ -1825,20 +1930,34 @@
is quota-controlled, or C{None} if not quota controlled.
"""
assert self.isCollection(), "Only collections can have a quota root"
@@ -497,7 +582,7 @@
def updateQuotaUse(self, request, adjust):
"""
Update the quota used value on this resource.
-@@ -1848,25 +1947,32 @@
+@@ -1848,25 +1967,32 @@
@return: an L{Deferred} with a C{int} result containing the current used byte if this collection
is quota-controlled, or C{None} if not quota controlled.
"""
@@ -547,7 +632,7 @@
##
# HTTP
##
-@@ -1880,7 +1986,7 @@
+@@ -1880,7 +2006,7 @@
# If this is a collection and the URI doesn't end in "/", redirect.
#
if self.isCollection() and request.path[-1:] != "/":
Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch 2009-09-03 17:58:15 UTC (rev 4524)
@@ -6,11 +6,20 @@
from twisted.cred.portal import Portal
-+from twisted.internet.defer import waitForDeferred, deferredGenerator
++from twisted.internet.defer import waitForDeferred, deferredGenerator, succeed
+
from twisted.web2 import responsecode
from twisted.web2.auth import basic
from twisted.web2.stream import MemoryStream
+@@ -57,7 +59,7 @@
+ if typeResource:
+ user = typeResource.children.get(shortName, None)
+
+- return user
++ return succeed(user)
+
+ class ACL(twisted.web2.dav.test.util.TestCase):
+ """
@@ -68,7 +70,9 @@
os.mkdir(docroot)
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/accesslog.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/accesslog.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/accesslog.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -79,6 +79,11 @@
uidz = str(request.authzUser.children[0])
def convertUIDtoShortName(uid):
+ # MOR: recordWithUID is now deferred -- not sure what to do here, so shortcircuiting for the moment:
+ return uid
+ # Cyrus suggests adding the records as attributes of
+ # the request objects when authn/authz are added
+
uid = uid.rstrip("/")
uid = uid[uid.rfind("/") + 1:]
record = request.site.resource.getDirectory().recordWithUID(uid)
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/aggregate.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/aggregate.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/aggregate.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -30,7 +30,7 @@
from twistedcaldav.directory.idirectory import IDirectoryService
from twistedcaldav.directory.directory import DirectoryService, DirectoryError
from twistedcaldav.directory.directory import UnknownRecordTypeError
-from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
class AggregateDirectoryService(DirectoryService):
"""
@@ -89,22 +89,27 @@
def recordTypes(self):
return set(self._recordTypes)
+ @inlineCallbacks
def listRecords(self, recordType):
- records = self._query("listRecords", recordType)
+ records = (yield self._query("listRecords", recordType))
if records is None:
- return ()
+ returnValue( () )
else:
- return records
+ returnValue(records)
+ # Deferred
def recordWithShortName(self, recordType, shortName):
return self._query("recordWithShortName", recordType, shortName)
+ # Deferred
def recordWithUID(self, uid):
return self._queryAll("recordWithUID", uid)
+ # Deferred
def recordWithAuthID(self, authID):
return self._queryAll("recordWithAuthID", authID)
+ # Deferred
def recordWithCalendarUserAddress(self, address):
return self._queryAll("recordWithCalendarUserAddress", address)
@@ -132,24 +137,27 @@
except KeyError:
raise UnknownRecordTypeError(recordType)
+ # Deferred
def _query(self, query, recordType, *args):
try:
service = self.serviceForRecordType(recordType)
except UnknownRecordTypeError:
- return None
+ return succeed(None)
+ # query is deferred
return getattr(service, query)(
recordType[len(service.recordTypePrefix):],
*[a[len(service.recordTypePrefix):] for a in args]
)
+ @inlineCallbacks
def _queryAll(self, query, *args):
for service in self._recordTypes.values():
- record = getattr(service, query)(*args)
+ record = (yield getattr(service, query)(*args))
if record is not None:
- return record
+ returnValue(record)
else:
- return None
+ returnValue(None)
userRecordTypes = [DirectoryService.recordType_users]
Deleted: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/apache.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/apache.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/apache.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -1,220 +0,0 @@
-##
-# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-##
-
-"""
-Apache UserFile/GroupFile compatible directory service implementation.
-"""
-
-__all__ = [
- "BasicDirectoryService",
- "DigestDirectoryService",
-]
-
-from crypt import crypt
-
-from twisted.python.filepath import FilePath
-from twisted.cred.credentials import UsernamePassword
-
-from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord
-from twistedcaldav.directory.directory import UnknownRecordTypeError, DirectoryConfigurationError
-
-class AbstractDirectoryService(DirectoryService):
- """
- Abstract Apache-compatible implementation of L{IDirectoryService}.
- """
- def __repr__(self):
- return "<%s %r: %r %r>" % (self.__class__.__name__, self.realmName, self.userFile, self.groupFile)
-
- def __init__(self, params):
- defaults = {
- 'realmName' : '',
- 'userFile' : None,
- 'groupFile' : None,
- }
- ignored = None
- params = self.getParams(params, defaults, ignored)
-
- super(AbstractDirectoryService, self).__init__()
-
- userFile = params["userFile"]
- if not userFile:
- raise DirectoryConfigurationError("Invalid Apache user file name: %r" % (userFile,))
-
- if userFile and type(userFile) is str:
- userFile = FilePath(userFile)
-
- groupFile = params["groupFile"]
- if groupFile and type(groupFile) is str:
- groupFile = FilePath(groupFile)
-
- self.realmName = params["realmName"]
- self.userFile = userFile
- self.groupFile = groupFile
-
- def recordTypes(self):
- recordTypes = (DirectoryService.recordType_users,)
- if self.groupFile is not None:
- recordTypes += (DirectoryService.recordType_groups,)
- return recordTypes
-
- def listRecords(self, recordType):
- for entryShortName, entryData in self.entriesForRecordType(recordType):
- if recordType == DirectoryService.recordType_users:
- yield self.userRecordClass(
- service = self,
- recordType = recordType,
- shortName = entryShortName,
- cryptPassword = entryData,
- )
-
- elif recordType == DirectoryService.recordType_groups:
- yield GroupRecord(
- service = self,
- recordType = recordType,
- shortName = entryShortName,
- members = entryData,
- )
-
- else:
- # Subclass should cover the remaining record types
- raise UnknownRecordTypeError("Unknown record type: %s" % (recordType,))
-
- def recordWithShortName(self, recordType, shortName):
- for entryShortName, entryData in self.entriesForRecordType(recordType):
- if entryShortName == shortName:
- if recordType == DirectoryService.recordType_users:
- return self.userRecordClass(
- service = self,
- recordType = recordType,
- shortName = entryShortName,
- cryptPassword = entryData,
- )
-
- if recordType == DirectoryService.recordType_groups:
- return GroupRecord(
- service = self,
- recordType = recordType,
- shortName = entryShortName,
- members = entryData,
- )
-
- # Subclass should cover the remaining record types
- raise UnknownRecordTypeError("Unknown record type: %s" % (recordType,))
-
- return None
-
- def entriesForRecordType(self, recordType):
- if recordType == DirectoryService.recordType_users:
- recordFile = self.userFile
- elif recordType == DirectoryService.recordType_groups:
- recordFile = self.groupFile
- else:
- raise UnknownRecordTypeError("Unknown record type: %s" % (recordType,))
-
- if recordFile is None:
- return
-
- try:
- handle = recordFile.open()
- except IOError, OSError:
- self.log_error("Auth file (for %s) not found: %s" % (recordType, recordFile.path))
- return
-
- try:
- for entry in handle:
- if entry and entry[0] != "#":
- try:
- shortName, rest = entry.rstrip("\n").split(":", 1)
- except ValueError:
- continue
- yield shortName, rest
- finally:
- handle.close()
-
-class AbstractDirectoryRecord(DirectoryRecord):
- """
- Abstract Apache-compatible implementation of L{IDirectoryRecord}.
- """
- def __init__(self, service, recordType, shortName):
- super(AbstractDirectoryRecord, self).__init__(
- service = service,
- recordType = recordType,
- guid = None,
- shortNames = (shortName,),
- )
-
-class AbstractUserRecord(AbstractDirectoryRecord):
- def __init__(self, service, recordType, shortName, cryptPassword=None):
- super(AbstractUserRecord, self).__init__(service, recordType, shortName)
-
- self._cryptPassword = cryptPassword
-
- def groups(self):
- for group in self.service.listRecords(DirectoryService.recordType_groups):
- for member in group.members():
- if member == self:
- yield group
- continue
-
-class BasicUserRecord(AbstractUserRecord):
- """
- Apache UserFile implementation of L{IDirectoryRecord}.
- """
- def verifyCredentials(self, credentials):
- if self._cryptPassword in ("", "*", "x"):
- return False
-
- if isinstance(credentials, UsernamePassword):
- return crypt(credentials.password, self._cryptPassword) == self._cryptPassword
-
- return super(BasicUserRecord, self).verifyCredentials(credentials)
-
-class BasicDirectoryService(AbstractDirectoryService):
- """
- Apache UserFile/GroupFile implementation of L{IDirectoryService}.
- """
- baseGUID = "DDF1E45C-CADE-4FCD-8AE6-B4B41D72B325"
- userRecordClass = BasicUserRecord
-
-class DigestUserRecord(AbstractUserRecord):
- """
- Apache DigestUserFile implementation of L{IDirectoryRecord}.
- """
- def verifyCredentials(self, credentials):
- raise NotImplementedError()
-
-class DigestDirectoryService(AbstractDirectoryService):
- """
- Apache DigestUserFile/GroupFile implementation of L{IDirectoryService}.
- """
- baseGUID = "0C719D1B-0A14-4074-8740-6D96A7D0C787"
- userRecordClass = DigestUserRecord
-
-class GroupRecord(AbstractDirectoryRecord):
- """
- Apache GroupFile implementation of L{IDirectoryRecord}.
- """
- def __init__(self, service, recordType, shortName, members=()):
- super(GroupRecord, self).__init__(service, recordType, shortName)
-
- if type(members) is str:
- members = tuple(m.strip() for m in members.split(","))
-
- self._members = members
-
- def members(self):
- for shortName in self._members:
- yield self.service.recordWithShortName(DirectoryService.recordType_users, shortName)
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/appleopendirectory.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/appleopendirectory.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -35,6 +35,7 @@
import dsattributes
import dsquery
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
from twisted.internet.threads import deferToThread
from twisted.cred.credentials import UsernamePassword
from twisted.web2.auth.digest import DigestedCredentials
@@ -120,8 +121,12 @@
h = (h + hash(getattr(self, attr))) & sys.maxint
return h
- def _expandGroupMembership(self, members, nestedGroups, processedGUIDs=None, returnGroups=False):
+ @inlineCallbacks
+ def _expandGroupMembership(self, members, nestedGroups, processedGUIDs=None, results=None, returnGroups=False):
+ if results is None:
+ results = set()
+
if processedGUIDs is None:
processedGUIDs = set()
@@ -134,7 +139,7 @@
for memberGUID in members:
if memberGUID not in processedGUIDs:
processedGUIDs.add(memberGUID)
- yield memberGUID
+ results.add(memberGUID)
for groupGUID in nestedGroups:
if groupGUID in processedGUIDs:
@@ -149,7 +154,9 @@
dsattributes.kDSStdRecordTypeGroups,
[dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups]
))
- result = opendirectory.queryRecordsWithAttribute_list(
+ # MOR: Doublecheck this
+ result = (yield deferToThread(
+ opendirectory.queryRecordsWithAttribute_list,
self.directory,
dsattributes.kDS1AttrGeneratedUID,
groupGUID,
@@ -157,7 +164,7 @@
False,
dsattributes.kDSStdRecordTypeGroups,
[dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups]
- )
+ ))
if not result:
self.log_error("Couldn't find group %s when trying to expand nested groups."
@@ -168,16 +175,18 @@
processedGUIDs.add(groupGUID)
if returnGroups:
- yield groupGUID
+ results.add(groupGUID)
- for GUID in self._expandGroupMembership(
+ yield self._expandGroupMembership(
group.get(dsattributes.kDSNAttrGroupMembers, []),
group.get(dsattributes.kDSNAttrNestedGroups, []),
processedGUIDs,
+ results,
returnGroups,
- ):
- yield GUID
+ )
+ returnValue(results)
+
def _calendarUserAddresses(self, recordType, recordData):
"""
Extract specific attributes from the directory record for use as calendar user address.
@@ -206,6 +215,7 @@
self.recordType_resources,
)
+ @inlineCallbacks
def groupsForGUID(self, guid):
attrs = [
@@ -227,7 +237,8 @@
recordType,
attrs,
))
- results = opendirectory.queryRecordsWithAttribute_list(
+ results = (yield deferToThread(
+ opendirectory.queryRecordsWithAttribute_list,
self.directory,
query.attribute,
query.value,
@@ -235,7 +246,7 @@
False,
recordType,
attrs,
- )
+ ))
except opendirectory.ODError, ex:
self.log_error("OpenDirectory (node=%s) error: %s" % (self.realmName, str(ex)))
raise
@@ -258,7 +269,8 @@
recordType,
attrs,
))
- results = opendirectory.queryRecordsWithAttribute_list(
+ results = (yield deferToThread(
+ opendirectory.queryRecordsWithAttribute_list,
self.directory,
query.attribute,
query.value,
@@ -266,7 +278,7 @@
False,
recordType,
attrs,
- )
+ ))
except opendirectory.ODError, ex:
self.log_error("OpenDirectory (node=%s) error: %s" % (self.realmName, str(ex)))
raise
@@ -278,7 +290,7 @@
if recordGUID:
guids.add(recordGUID)
- return guids
+ returnValue(guids)
def proxiesForGUID(self, recordType, guid):
@@ -361,24 +373,13 @@
_fromODRecordTypes = dict([(b, a) for a, b in _toODRecordTypes.iteritems()])
+ @inlineCallbacks
def recordsMatchingFields(self, fields, operand="or", recordType=None):
# Note that OD applies case-sensitivity globally across the entire
# query, not per expression, so the current code uses whatever is
# specified in the last field in the fields list
- def collectResults(results):
- self.log_info("Got back %d records from OD" % (len(results),))
- for key, val in results.iteritems():
- self.log_debug("OD result: %s %s" % (key, val))
- try:
- guid = val[dsattributes.kDS1AttrGeneratedUID]
- record = self.recordWithGUID(guid)
- if record:
- yield record
- except KeyError:
- pass
-
def multiQuery(directory, queries, attrs, operand):
results = {}
@@ -426,17 +427,30 @@
queries = buildQueries(recordTypes, fields, self._ODFields)
- deferred = deferToThread(
+ odResults = (yield deferToThread(
multiQuery,
self.directory,
queries,
[ dsattributes.kDS1AttrGeneratedUID ],
operand
- )
- deferred.addCallback(collectResults)
- return deferred
+ ))
+ results = []
+ self.log_info("Got back %d records from OD" % (len(results),))
+ for key, val in odResults.iteritems():
+ self.log_debug("OD result: %s %s" % (key, val))
+ try:
+ guid = val[dsattributes.kDS1AttrGeneratedUID]
+ record = (yield self.recordWithGUID(guid))
+ if record:
+ results.append(record)
+ except KeyError:
+ pass
+ returnValue(results)
+
+
+ @inlineCallbacks
def queryDirectory(self, recordTypes, indexType, indexKey,
lookupMethod=opendirectory.queryRecordsWithAttribute_list):
@@ -509,7 +523,8 @@
listRecordTypes,
attrs,
))
- results = lookupMethod(
+ results = (yield deferToThread(
+ lookupMethod,
self.directory,
query.attribute,
query.value,
@@ -517,13 +532,13 @@
False,
listRecordTypes,
attrs,
- )
+ ))
self.log_debug("opendirectory.queryRecordsWithAttribute_list matched records: %s" % (len(results),))
except opendirectory.ODError, ex:
if ex.message[1] == -14140 or ex.message[1] == -14200:
# Unsupported attribute on record - don't fail
- return
+ returnValue(None)
else:
self.log_error("OpenDirectory (node=%s) error: %s" % (self.realmName, str(ex)))
raise
@@ -603,7 +618,8 @@
dsattributes.kDSStdRecordTypeGroups,
[dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups,],
))
- results = lookupMethod(
+ results = (yield deferToThread(
+ lookupMethod,
self.directory,
attributeToMatch,
valueToMatch,
@@ -611,7 +627,7 @@
False,
dsattributes.kDSStdRecordTypeGroups,
[dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups,],
- )
+ ))
if len(results) == 1:
members = results[0][1].get(dsattributes.kDSNAttrGroupMembers, [])
@@ -619,7 +635,7 @@
else:
members = []
nestedGroups = []
- self.restrictedGUIDs = set(self._expandGroupMembership(members, nestedGroups, returnGroups=True))
+ self.restrictedGUIDs = (yield self._expandGroupMembership(members, nestedGroups, returnGroups=True))
self.log_debug("Got %d restricted group members" % (len(self.restrictedGUIDs),))
self.restrictedTimestamp = time.time()
@@ -701,9 +717,9 @@
# Fetch the set of groups this record is a member of so we can
# cache it, rather than have each process make the same group
# lookup
- record._groupMembershipGUIDs = self.groupsForGUID(record.guid)
+ record._groupMembershipGUIDs = (yield self.groupsForGUID(record.guid))
- self.recordCacheForType(recordType).addRecord(record, indexType, origIndexKey)
+ yield self.recordCacheForType(recordType).addRecord(record, indexType, origIndexKey)
def _parseResourceInfo(self, plist, guid, recordType, shortname):
"""
@@ -732,6 +748,7 @@
return (autoaccept, proxy, read_only_proxy,)
+ @inlineCallbacks
def getResourceInfo(self):
"""
Resource information including proxy assignments for resource and
@@ -743,6 +760,7 @@
dsattributes.kDS1AttrGeneratedUID,
dsattributes.kDSNAttrResourceInfo,
]
+ results = []
for recordType in (dsattributes.kDSStdRecordTypePlaces, dsattributes.kDSStdRecordTypeResources):
try:
@@ -751,11 +769,12 @@
recordType,
attrs,
))
- results = opendirectory.listAllRecordsWithAttributes_list(
+ results = (yield deferToThread(
+ opendirectory.listAllRecordsWithAttributes_list,
self.directory,
recordType,
attrs,
- )
+ ))
except opendirectory.ODError, ex:
self.log_error("OpenDirectory (node=%s) error: %s" % (self.realmName, str(ex)))
raise
@@ -769,7 +788,8 @@
recordGUID, recordType, recordShortName)
except ValueError:
continue
- yield recordGUID, autoSchedule, proxy, readOnlyProxy
+ results.append((recordGUID, autoSchedule, proxy, readOnlyProxy))
+ returnValue(results)
def isAvailable(self):
@@ -861,44 +881,56 @@
self.fullName
)
+ @inlineCallbacks
def members(self):
if self.recordType != self.service.recordType_groups:
- return
+ returnValue(None)
+ results = []
for guid in self._memberGUIDs:
- userRecord = self.service.recordWithGUID(guid)
+ userRecord = (yield self.service.recordWithGUID(guid))
if userRecord is not None:
- yield userRecord
+ results.append(userRecord)
+ returnValue(results)
+ @inlineCallbacks
def groups(self):
if self._groupMembershipGUIDs is None:
self._groupMembershipGUIDs = self.service.groupsForGUID(self.guid)
+ results = []
for guid in self._groupMembershipGUIDs:
- record = self.service.recordWithGUID(guid)
+ record = (yield self.service.recordWithGUID(guid))
if record:
- yield record
+ results.append(record)
+ returnValue(results)
+ @inlineCallbacks
def verifyCredentials(self, credentials):
if isinstance(credentials, UsernamePassword):
# Check cached password
try:
if credentials.password == self.password:
- return True
+ returnValue(True)
except AttributeError:
pass
# Check with directory services
try:
- if opendirectory.authenticateUserBasic(self.service.directory, self.nodeName, self.shortNames[0], credentials.password):
+ if (yield deferToThread(
+ opendirectory.authenticateUserBasic,
+ self.service.directory,
+ self.nodeName,
+ self.shortNames[0],
+ credentials.password)):
# Cache the password to avoid future DS queries
self.password = credentials.password
- return True
+ returnValue(True)
except opendirectory.ODError, e:
self.log_error("OpenDirectory (node=%s) error while performing basic authentication for user %s: %s"
% (self.service.realmName, self.shortNames[0], e))
- return False
+ returnValue(False)
elif isinstance(credentials, DigestedCredentials):
#
@@ -923,23 +955,24 @@
"missing digest response field: %s in: %s"
% (self.service.realmName, self.shortNames[0], e, credentials.fields)
)
- return False
+ returnValue(False)
try:
if self.digestcache[credentials.fields["uri"]] == response:
- return True
+ returnValue(True)
except (AttributeError, KeyError):
pass
try:
- if opendirectory.authenticateUserDigest(
+ if (yield deferToThread(
+ opendirectory.authenticateUserDigest,
self.service.directory,
self.nodeName,
self.shortNames[0],
challenge,
response,
credentials.originalMethod if credentials.originalMethod else credentials.method
- ):
+ )):
try:
cache = self.digestcache
except AttributeError:
@@ -947,7 +980,7 @@
cache[credentials.fields["uri"]] = response
- return True
+ returnValue(True)
else:
self.log_debug(
"""OpenDirectory digest authentication failed with:
@@ -963,11 +996,11 @@
"OpenDirectory (node=%s) error while performing digest authentication for user %s: %s"
% (self.service.realmName, self.shortNames[0], e)
)
- return False
+ returnValue(False)
- return False
+ returnValue(False)
- return super(OpenDirectoryRecord, self).verifyCredentials(credentials)
+ returnValue((yield super(OpenDirectoryRecord, self).verifyCredentials(credentials)))
class OpenDirectoryInitError(DirectoryError):
"""
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/cachingdirectory.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/cachingdirectory.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/cachingdirectory.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -34,6 +34,7 @@
from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord, DirectoryError
from twistedcaldav.log import LoggingMixIn
from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
class RecordTypeCache(object):
@@ -72,6 +73,7 @@
CachingDirectoryService.INDEX_TYPE_AUTHID : {},
}
+ # MOR: Defer this
def addRecord(self, record, indexType, indexKey, useMemcache=True,
neverExpire=False):
@@ -94,7 +96,9 @@
self.log_debug("Memcache: storing %s" % (key,))
self.directoryService.memcacheSet(key, record)
+ return succeed(None) # MOR: Remove this when really deferred
+ # MOR: Defer this
def removeRecord(self, record):
if record in self.records:
self.records.remove(record)
@@ -113,6 +117,8 @@
self.log_debug("Missing record index item; type: %s, item: %s" % (indexType, item))
else:
raise AssertionError("Data from record attribute must be str, list or tuple")
+
+ return succeed(None) # MOR: Remove this when really deferred
def findRecord(self, indexType, indexKey):
return self.recordsIndexedBy[indexType].get(indexKey)
@@ -158,6 +164,8 @@
debug=0, pickleProtocol=2)
return self.memcacheClient
+
+ @inlineCallbacks
def memcacheSet(self, key, record):
hideService = isinstance(record, DirectoryRecord)
@@ -167,12 +175,12 @@
record.service = None # so we don't pickle service
key = base64.b64encode(key)
- if not self._getMemcacheClient().set(key, record, time=self.cacheTimeout):
+ if not (yield self._getMemcacheClient().set(key, record, time=self.cacheTimeout)):
self.log_error("Could not write to memcache, retrying")
- if not self._getMemcacheClient(refresh=True).set(
+ if not (yield self._getMemcacheClient(refresh=True).set(
key, record,
time=self.cacheTimeout
- ):
+ )):
self.log_error("Could not write to memcache again, giving up")
del self.memcacheClient
raise DirectoryMemcacheError("Failed to write to memcache")
@@ -180,22 +188,23 @@
if hideService:
record.service = self
+ @inlineCallbacks
def memcacheGet(self, key):
key = base64.b64encode(key)
try:
- record = self._getMemcacheClient().get(key)
+ record = (yield self._getMemcacheClient().get(key))
if record is not None and isinstance(record, DirectoryRecord):
record.service = self
except memcacheclient.MemcacheError:
self.log_error("Could not read from memcache, retrying")
try:
- record = self._getMemcacheClient(refresh=True).get(key)
+ record = (yield self._getMemcacheClient(refresh=True).get(key))
except memcacheclient.MemcacheError:
self.log_error("Could not read from memcache again, giving up")
del self.memcacheClient
raise DirectoryMemcacheError("Failed to read from memcache")
- return record
+ returnValue(record)
def _initCaches(self, cacheClass):
self._recordCaches = dict([
@@ -223,16 +232,17 @@
def recordWithShortName(self, recordType, shortName):
return self._lookupRecord((recordType,), CachingDirectoryService.INDEX_TYPE_SHORTNAME, shortName)
+ @inlineCallbacks
def recordWithCalendarUserAddress(self, address):
address = normalizeCUAddr(address)
record = None
if address.startswith("urn:uuid:"):
guid = address[9:]
- record = self.recordWithGUID(guid)
+ record = (yield self.recordWithGUID(guid))
elif address.startswith("mailto:"):
- record = self._lookupRecord(None, CachingDirectoryService.INDEX_TYPE_CUA, address)
+ record = (yield self._lookupRecord(None, CachingDirectoryService.INDEX_TYPE_CUA, address))
- return record if record and record.enabledForCalendaring else None
+ returnValue(record if record and record.enabledForCalendaring else None)
def recordWithAuthID(self, authID):
return self._lookupRecord(None, CachingDirectoryService.INDEX_TYPE_AUTHID, authID)
@@ -242,6 +252,7 @@
recordWithUID = recordWithGUID
+ @inlineCallbacks
def _lookupRecord(self, recordTypes, indexType, indexKey, cacheOnMiss=True):
if recordTypes is None:
@@ -254,9 +265,10 @@
if recordType in supportedRecordTypes:
typesToQuery.append(recordType)
if not typesToQuery:
- return None
+ returnValue(None)
recordTypes = typesToQuery
+ @inlineCallbacks
def lookup():
for recordType in recordTypes:
record = self.recordCacheForType(recordType).findRecord(indexType, indexKey)
@@ -266,16 +278,16 @@
record.cachedTime != 0 and
time.time() - record.cachedTime > self.cacheTimeout
):
- self.recordCacheForType(recordType).removeRecord(record)
- return None
+ yield self.recordCacheForType(recordType).removeRecord(record)
+ returnValue(None)
else:
- return record
+ returnValue(record)
else:
- return None
+ returnValue(None)
- record = lookup()
+ record = (yield lookup())
if record:
- return record
+ returnValue(record)
if cacheOnMiss:
@@ -283,38 +295,38 @@
try:
disabledTime = self._disabledKeys[indexType][indexKey]
if time.time() - disabledTime < self.cacheTimeout:
- return None
+ returnValue(None)
except KeyError:
pass
# Check memcache
if config.Memcached.ClientEnabled:
key = "dir|%s|%s" % (indexType, indexKey)
- record = self.memcacheGet(key)
+ record = (yield self.memcacheGet(key))
self.log_debug("Memcache: checking %s" % (key,))
if record is None:
self.log_debug("Memcache: miss %s" % (key,))
else:
self.log_debug("Memcache: hit %s" % (key,))
- self.recordCacheForType(record.recordType).addRecord(record, indexType, indexKey, useMemcache=False)
- return record
+ yield self.recordCacheForType(record.recordType).addRecord(record, indexType, indexKey, useMemcache=False)
+ returnValue(record)
# Check negative memcache
- val = self.memcacheGet("-%s" % (key,))
+ val = (yield self.memcacheGet("-%s" % (key,)))
if val == 1:
self.log_debug("Memcache: negative %s" % (key,))
self._disabledKeys[indexType][indexKey] = time.time()
- return None
+ returnValue(None)
# Try query
self.log_debug("Faulting record for attribute '%s' with value '%s'" % (indexType, indexKey,))
- self.queryDirectory(recordTypes, indexType, indexKey)
+ yield self.queryDirectory(recordTypes, indexType, indexKey)
# Now try again from cache
- record = lookup()
+ record = (yield lookup())
if record:
self.log_debug("Found record for attribute '%s' with value '%s'" % (indexType, indexKey,))
- return record
+ returnValue(record)
# Add to negative cache with timestamp
@@ -323,9 +335,9 @@
if config.Memcached.ClientEnabled:
self.log_debug("Memcache: storing (negative) %s" % (key,))
- self.memcacheSet("-%s" % (key,), 1)
+ yield self.memcacheSet("-%s" % (key,), 1)
- return None
+ returnValue(None)
def queryDirectory(self, recordTypes, indexType, indexKey):
raise NotImplementedError()
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendar.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendar.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendar.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -58,13 +58,32 @@
DAVResource,
):
def defaultAccessControlList(self):
- return config.ProvisioningResourceACL
+ return succeed(config.ProvisioningResourceACL)
class DirectoryCalendarHomeProvisioningResource (DirectoryCalendarProvisioningResource):
"""
Resource which provisions calendar home collections as needed.
"""
+
+ @classmethod
+ @inlineCallbacks
+ def fetch(cls, *a, **kw):
+ self = (yield super(DirectoryCalendarHomeProvisioningResource, cls).fetch(*a, **kw))
+ #
+ # Create children
+ #
+
+ @inlineCallbacks
+ def _provisionChild(name):
+ self.putChild(name, (yield self.provisionChild(name)))
+
+ for recordType in self.directory.recordTypes():
+ (yield _provisionChild(recordType))
+
+ (yield _provisionChild(uidsResourceName))
+ returnValue(self)
+
def __init__(self, directory, url):
"""
@param directory: an L{IDirectoryService} to provision calendars from.
@@ -81,17 +100,7 @@
# FIXME: Smells like a hack
directory.calendarHomesCollection = self
- #
- # Create children
- #
- def provisionChild(name):
- self.putChild(name, self.provisionChild(name))
- for recordType in self.directory.recordTypes():
- provisionChild(recordType)
-
- provisionChild(uidsResourceName)
-
def provisionChild(self, recordType):
raise NotImplementedError("Subclass must implement provisionChild()")
@@ -99,7 +108,7 @@
return self._url
def getChild(self, name):
- return self.putChildren.get(name, None)
+ return succeed(self.putChildren.get(name, None))
def listChildren(self):
return succeed(self.directory.recordTypes())
@@ -109,17 +118,19 @@
# See DirectoryPrincipalProvisioningResource.__init__()
return self.directory.principalCollection.principalCollections()
+ # Deferred
def principalForRecord(self, record):
# FIXME: directory.principalCollection smells like a hack
# See DirectoryPrincipalProvisioningResource.__init__()
return self.directory.principalCollection.principalForRecord(record)
+ @inlineCallbacks
def homeForDirectoryRecord(self, record):
- uidResource = self.getChild(uidsResourceName)
+ uidResource = (yield self.getChild(uidsResourceName))
if uidResource is None:
- return succeed(None)
+ returnValue(None)
else:
- return uidResource.getChild(record.uid)
+ returnValue((yield uidResource.getChild(record.uid)))
##
# DAV
@@ -158,25 +169,26 @@
returnValue(self)
if record is None:
- record = self.directory.recordWithShortName(self.recordType, name)
+ record = (yield self.directory.recordWithShortName(self.recordType, name))
if record is None:
returnValue(None)
returnValue((yield self._parent.homeForDirectoryRecord(record)))
+ @inlineCallbacks
def listChildren(self):
if config.EnablePrincipalListings:
- def _recordShortnameExpand():
- for record in self.directory.listRecords(self.recordType):
- if record.enabledForCalendaring:
- for shortName in record.shortNames:
- yield shortName
+ results = []
+ for record in (yield self.directory.listRecords(self.recordType)):
+ if record.enabledForCalendaring:
+ for shortName in record.shortNames:
+ results.append(shortName)
- return succeed(_recordShortnameExpand())
+ returnValue(results)
else:
# Not a listable collection
- return fail(HTTPError(responsecode.FORBIDDEN))
+ raise HTTPError(responsecode.FORBIDDEN)
def createSimilarFile(self, path):
raise HTTPError(responsecode.NOT_FOUND)
@@ -195,6 +207,7 @@
def principalCollections(self):
return self._parent.principalCollections()
+ # Deferred
def principalForRecord(self, record):
return self._parent.principalForRecord(record)
@@ -221,7 +234,7 @@
returnValue(self)
if record is None:
- record = self.directory.recordWithUID(name)
+ record = (yield self.directory.recordWithUID(name))
if record is None:
returnValue(None)
@@ -245,6 +258,7 @@
def principalCollections(self):
return self.parent.principalCollections()
+ # Deferred
def principalForRecord(self, record):
return self.parent.principalForRecord(record)
@@ -295,15 +309,22 @@
self.parent = parent
+ @inlineCallbacks
def provisionDefaultCalendars(self):
# Disable notifications during provisioning
if hasattr(self, "clientNotifier"):
self.clientNotifier.disableNotify()
- @inlineCallbacks
- def setupFreeBusy(_, child):
- # Default calendar is initially opaque to freebusy
+ try:
+ yield self.provision()
+
+ childName = "calendar"
+ childURL = joinURL(self.url(), childName)
+ child = (yield self.provisionChild(childName))
+
+ assert isinstance(child, CalDAVResource), "Child %r is not a %s: %r" % (childName, CalDAVResource.__name__, child)
+ yield child.createCalendarCollection()
yield child.writeDeadProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Opaque()))
# FIXME: Shouldn't have to call provision() on another resource
@@ -312,41 +333,18 @@
# This will go away once we remove the free-busy-set property on inbox.
# Set calendar-free-busy-set on inbox
- inbox = self.getChild("inbox")
+ inbox = (yield self.getChild("inbox"))
yield inbox.provision()
yield inbox.processFreeBusyCalendar(childURL, True)
# Default calendar is marked as the default for scheduling
yield inbox.writeDeadProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(childURL)))
- returnValue(self)
-
- try:
- d = self.provision()
-
- childName = "calendar"
- childURL = joinURL(self.url(), childName)
- d.addCallback(lambda _: self.provisionChild(childName))
-
- def _makeChild(child):
- assert isinstance(child, CalDAVResource), "Child %r is not a %s: %r" % (childName, CalDAVResource.__name__, child)
- return child.createCalendarCollection().addCallback(setupFreeBusy, child)
-
- d.addCallback(_makeChild)
- except:
- # We want to make sure to re-enable notifications, so do so
- # if there is an immediate exception above, or via errback, below
+ finally:
if hasattr(self, "clientNotifier"):
self.clientNotifier.enableNotify(None)
- raise
- # Re-enable notifications
- if hasattr(self, "clientNotifier"):
- d.addCallback(self.clientNotifier.enableNotify)
- d.addErrback(self.clientNotifier.enableNotify)
- return d
-
def provisionChild(self, name):
raise NotImplementedError("Subclass must implement provisionChild()")
@@ -370,14 +368,18 @@
# ACL
##
+ @inlineCallbacks
def owner(self, request):
- return succeed(davxml.HRef(self.principalForRecord().principalURL()))
+ principal = (yield self.principalForRecord())
+ returnValue(davxml.HRef(principal.principalURL()))
+ # Deferred
def ownerPrincipal(self, request):
- return succeed(self.principalForRecord())
+ return self.principalForRecord()
+ @inlineCallbacks
def defaultAccessControlList(self):
- myPrincipal = self.principalForRecord()
+ myPrincipal = (yield self.principalForRecord())
aces = (
# Inheritable DAV:all access for the resource's associated principal.
@@ -426,7 +428,7 @@
),
)
- return davxml.ACL(*aces)
+ returnValue(davxml.ACL(*aces))
@inlineCallbacks
def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
@@ -439,11 +441,12 @@
else:
# ...otherwise permissions are fixed, and are not subject to
# inheritance rules, etc.
- returnValue(self.defaultAccessControlList())
+ returnValue((yield self.defaultAccessControlList()))
def principalCollections(self):
return self.parent.principalCollections()
+ # Deferred
def principalForRecord(self):
return self.parent.principalForRecord(self.record)
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendaruserproxy.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendaruserproxy.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -71,11 +71,11 @@
for principal in config.AdminPrincipals
))
- return davxml.ACL(*aces)
+ return succeed(davxml.ACL(*aces))
def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
# Permissions here are fixed, and are not subject to inheritance rules, etc.
- return succeed(self.defaultAccessControlList())
+ return self.defaultAccessControlList()
class CalendarUserProxyPrincipalResource (CalDAVComplianceMixIn, PermissionsMixIn, DAVPrincipalResource, DAVFile):
"""
@@ -150,13 +150,14 @@
return True
def etag(self):
- return None
+ return succeed(None)
def deadProperties(self):
if not hasattr(self, "_dead_properties"):
self._dead_properties = NonePropertyStore(self)
return self._dead_properties
+ # Deferred
def writeProperty(self, property, request):
assert isinstance(property, davxml.WebDAVElement)
@@ -183,7 +184,7 @@
principals = []
newUIDs = set()
for uri in members:
- principal = self.pcollection._principalForURI(uri)
+ principal = (yield self.pcollection._principalForURI(uri))
# Invalid principals MUST result in an error.
if principal is None or principal.principalURL() != uri:
raise HTTPError(StatusResponse(
@@ -205,7 +206,7 @@
changedUIDs = newUIDs.symmetric_difference(oldUIDs)
for uid in changedUIDs:
- principal = self.pcollection.principalForUID(uid)
+ principal = (yield self.pcollection.principalForUID(uid))
if principal:
yield principal.cacheNotifier.changed()
@@ -306,7 +307,7 @@
if uid not in uids:
from twistedcaldav.directory.principal import DirectoryPrincipalResource
uids.add(uid)
- principal = self.pcollection.principalForUID(uid)
+ principal = (yield self.pcollection.principalForUID(uid))
if isinstance(principal, CalendarUserProxyPrincipalResource):
members = yield self._directGroupMembers()
for member in members:
@@ -330,7 +331,7 @@
found = []
missing = []
for uid in members:
- p = self.pcollection.principalForUID(uid)
+ p = (yield self.pcollection.principalForUID(uid))
if p:
found.append(p)
# Make sure any outstanding deletion timer entries for
@@ -343,8 +344,7 @@
for uid in missing:
cacheTimeout = config.DirectoryService.params.get("cacheTimeout", 30) * 60 # in seconds
- yield self._index().removePrincipal(uid,
- delay=cacheTimeout*2)
+ yield self._index().removePrincipal(uid, delay=cacheTimeout*2)
returnValue(found)
@@ -358,7 +358,7 @@
def groupMemberships(self):
# Get membership UIDs and map to principal resources
memberships = yield self._index().getMemberships(self.uid)
- returnValue([p for p in [self.pcollection.principalForUID(uid) for uid in memberships] if p])
+ returnValue([p for p in [(yield self.pcollection.principalForUID(uid)) for uid in memberships] if p])
class CalendarUserProxyDatabase(AbstractSQLDatabase, LoggingMixIn):
"""
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/directory.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/directory.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/directory.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -35,7 +35,7 @@
from twisted.cred.error import UnauthorizedLogin
from twisted.cred.checkers import ICredentialsChecker
from twisted.web2.dav.auth import IPrincipalCredentials
-from twisted.internet.defer import succeed, maybeDeferred
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed, maybeDeferred
from twistedcaldav.log import LoggingMixIn
from twistedcaldav.directory.idirectory import IDirectoryService, IDirectoryRecord
@@ -130,35 +130,36 @@
def recordWithUID(self, uid):
for record in self.allRecords():
if record.uid == uid:
- return record
- return None
+ return succeed(record)
+ return succeed(None)
def recordWithGUID(self, guid):
for record in self.allRecords():
if record.guid == guid:
- return record
- return None
+ return succeed(record)
+ return succeed(None)
def recordWithAuthID(self, authID):
for record in self.allRecords():
if authID in record.authIDs:
- return record
- return None
+ return succeed(record)
+ return succeed(None)
+ @inlineCallbacks
def recordWithCalendarUserAddress(self, address):
address = normalizeCUAddr(address)
record = None
if address.startswith("urn:uuid:"):
guid = address[9:]
- record = self.recordWithGUID(guid)
+ record = (yield self.recordWithGUID(guid))
elif address.startswith("mailto:"):
for record in self.allRecords():
if address in record.calendarUserAddresses:
break
else:
- return None
+ returnValue(None)
- return record if record and record.enabledForCalendaring else None
+ returnValue(record if record and record.enabledForCalendaring else None)
def allRecords(self):
for recordType in self.recordTypes():
@@ -251,7 +252,7 @@
return succeed(yieldMatches(recordType))
def getResourceInfo(self):
- return ()
+ return succeed(())
def isAvailable(self):
return True
@@ -362,13 +363,13 @@
return h
def members(self):
- return ()
+ return succeed(())
def groups(self):
- return ()
+ return succeed(())
def verifyCredentials(self, credentials):
- return False
+ return succeed(False)
# Mapping from directory record.recordType to RFC2445 CUTYPE values
_cuTypes = {
Deleted: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldappleopendirectory.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldappleopendirectory.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldappleopendirectory.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -1,1176 +0,0 @@
-##
-# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-##
-
-"""
-Apple Open Directory directory service implementation.
-"""
-
-__all__ = [
- "OpenDirectoryService",
- "OpenDirectoryInitError",
-]
-
-import sys
-from random import random
-from uuid import UUID
-
-from xml.parsers.expat import ExpatError
-
-import opendirectory
-import dsattributes
-import dsquery
-
-from twisted.internet.reactor import callLater
-from twisted.internet.threads import deferToThread
-from twisted.cred.credentials import UsernamePassword
-from twisted.web2.auth.digest import DigestedCredentials
-
-from twext.python.plistlib import readPlistFromString
-
-from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord
-from twistedcaldav.directory.directory import DirectoryError, UnknownRecordTypeError
-from twistedcaldav.directory.principal import cuAddressConverter
-from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
-
-class OpenDirectoryService(DirectoryService):
- """
- Open Directory implementation of L{IDirectoryService}.
- """
- baseGUID = "891F8321-ED02-424C-BA72-89C32F215C1E"
-
- def __repr__(self):
- return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.node)
-
- def __init__(
- self,
- node="/Search",
- restrictEnabledRecords=False,
- restrictToGroup="",
- dosetup=True,
- cacheTimeout=30
- ):
- """
- @param node: an OpenDirectory node name to bind to.
- @param restrictEnabledRecords: C{True} if a group in the directory is to be used to determine
- which calendar users are enabled.
- @param restrictToGroup: C{str} guid or name of group used to restrict enabled users.
- @param dosetup: if C{True} then the directory records are initialized,
- if C{False} they are not.
- This should only be set to C{False} when doing unit tests.
- @param cacheTimeout: C{int} number of minutes before cache is invalidated.
- """
- try:
- directory = opendirectory.odInit(node)
- except opendirectory.ODError, e:
- self.log_error("Open Directory (node=%s) Initialization error: %s" % (node, e))
- raise
-
- self.realmName = node
- self.directory = directory
- self.node = node
- self.restrictEnabledRecords = restrictEnabledRecords
- self.restrictToGroup = restrictToGroup
- try:
- UUID(self.restrictToGroup)
- except:
- self.restrictToGUID = False
- else:
- self.restrictToGUID = True
- self.restrictedGUIDs = None
- self.cacheTimeout = cacheTimeout
- self._records = {}
- self._delayedCalls = set()
-
- if dosetup:
- for recordType in self.recordTypes():
- self.recordsForType(recordType)
-
- def __cmp__(self, other):
- if not isinstance(other, DirectoryRecord):
- return super(DirectoryRecord, self).__eq__(other)
-
- for attr in ("directory", "node"):
- diff = cmp(getattr(self, attr), getattr(other, attr))
- if diff != 0:
- return diff
- return 0
-
- def __hash__(self):
- h = hash(self.__class__)
- for attr in ("directory", "node"):
- h = (h + hash(getattr(self, attr))) & sys.maxint
- return h
-
- def _expandGroupMembership(self, members, nestedGroups, processedGUIDs=None, returnGroups=False):
-
- if processedGUIDs is None:
- processedGUIDs = set()
-
- if isinstance(members, str):
- members = [members]
-
- if isinstance(nestedGroups, str):
- nestedGroups = [nestedGroups]
-
- for memberGUID in members:
- if memberGUID not in processedGUIDs:
- processedGUIDs.add(memberGUID)
- yield memberGUID
-
- for groupGUID in nestedGroups:
- if groupGUID in processedGUIDs:
- continue
-
- self.log_debug("opendirectory.queryRecordsWithAttribute_list(%r,%r,%r,%r,%r,%r,%r)" % (
- self.directory,
- dsattributes.kDS1AttrGeneratedUID,
- groupGUID,
- dsattributes.eDSExact,
- False,
- dsattributes.kDSStdRecordTypeGroups,
- [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups]
- ))
- result = opendirectory.queryRecordsWithAttribute_list(
- self.directory,
- dsattributes.kDS1AttrGeneratedUID,
- groupGUID,
- dsattributes.eDSExact,
- False,
- dsattributes.kDSStdRecordTypeGroups,
- [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups]
- )
-
- if not result:
- self.log_error("Couldn't find group %s when trying to expand nested groups."
- % (groupGUID,))
- continue
-
- group = result[0][1]
-
- processedGUIDs.add(groupGUID)
- if returnGroups:
- yield groupGUID
-
- for GUID in self._expandGroupMembership(
- group.get(dsattributes.kDSNAttrGroupMembers, []),
- group.get(dsattributes.kDSNAttrNestedGroups, []),
- processedGUIDs,
- returnGroups,
- ):
- yield GUID
-
- def _calendarUserAddresses(self, recordType, recordData):
- """
- Extract specific attributes from the directory record for use as calendar user address.
-
- @param recordData: a C{dict} containing the attributes retrieved from the directory.
- @return: a C{set} of C{str} for each expanded calendar user address.
- """
- # Now get the addresses
- result = set()
-
- # Add each email address as a mailto URI
- emails = recordData.get(dsattributes.kDSNAttrEMailAddress)
- if emails is not None:
- if isinstance(emails, str):
- emails = [emails]
- for email in emails:
- result.add("mailto:%s" % (email.lower(),))
-
- return result
-
- def _parseResourceInfo(self, plist, guid, recordType, shortname):
- """
- Parse OD ResourceInfo attribute and extract information that the server needs.
-
- @param plist: the plist that is the attribute value.
- @type plist: str
- @param guid: the directory GUID of the record being parsed.
- @type guid: str
- @param shortname: the record shortname of the record being parsed.
- @type shortname: str
- @return: a C{tuple} of C{bool} for auto-accept, C{str} for proxy GUID, C{str} for read-only proxy GUID.
- """
- try:
- plist = readPlistFromString(plist)
- wpframework = plist.get("com.apple.WhitePagesFramework", {})
- autoaccept = wpframework.get("AutoAcceptsInvitation", False)
- proxy = wpframework.get("CalendaringDelegate", None)
- read_only_proxy = wpframework.get("ReadOnlyCalendaringDelegate", None)
- except (ExpatError, AttributeError), e:
- self.log_error(
- "Failed to parse ResourceInfo attribute of record (%s)%s (guid=%s): %s\n%s" %
- (recordType, shortname, guid, e, plist,)
- )
- raise ValueError("Invalid ResourceInfo")
-
- return (autoaccept, proxy, read_only_proxy,)
-
- def recordTypes(self):
- return (
- self.recordType_users,
- self.recordType_groups,
- self.recordType_locations,
- self.recordType_resources,
- )
-
- def _storage(self, recordType):
- try:
- storage = self._records[recordType]
- except KeyError:
- self.reloadCache(recordType)
- storage = self._records[recordType]
- else:
- if storage["status"] == "stale":
- storage["status"] = "loading"
-
- def onError(f):
- storage["status"] = "stale" # Keep trying
- self.log_error(
- "Unable to load records of type %s from OpenDirectory due to unexpected error: %s"
- % (recordType, f)
- )
-
- # Reload the restricted access group details if reloading user records
- if recordType == self.recordType_users:
- self.restrictedGUIDs = None
-
- d = deferToThread(self.reloadCache, recordType)
- d.addErrback(onError)
-
- return storage
-
- def recordsForType(self, recordType):
- """
- @param recordType: a record type
- @return: a dictionary containing all records for the given record
- type. Keys are short names and values are the corresponding
- OpenDirectoryRecord for the given record type.
- """
- return self._storage(recordType)["records"]
-
- def listRecords(self, recordType):
- return self.recordsForType(recordType).itervalues()
-
- def recordWithShortName(self, recordType, shortName):
- try:
- return self.recordsForType(recordType)[shortName]
- except KeyError:
- # Check negative cache
- if shortName in self._storage(recordType)["disabled names"]:
- return None
-
- # Cache miss; try looking the record up, in case it is new
- # FIXME: This is a blocking call (hopefully it's a fast one)
- self.reloadCache(recordType, lookup=("shortName", shortName,))
- record = self.recordsForType(recordType).get(shortName, None)
- if record is None:
- # Add to negative cache
- self._storage(recordType)["disabled names"].add(shortName)
- return record
-
- def recordWithCalendarUserAddress(self, address):
- address = normalizeCUAddr(address)
- record = None
- if address.startswith("urn:uuid:"):
- guid = address[9:]
- record = self.recordWithGUID(guid)
- elif address.startswith("mailto:"):
- record = self._recordWithAttribute("cuas", "disabled cuas", "cua", address)
-
- return record if record and record.enabledForCalendaring else None
-
- def recordWithGUID(self, guid):
- return self._recordWithAttribute("guids", "disabled guids", "guid", guid)
-
- recordWithUID = recordWithGUID
-
- def recordWithAuthID(self, authID):
- return self._recordWithAttribute("authIDs", "disabled authIDs", "authID", authID)
-
- def _recordWithAttribute(self, cacheKey, disabledKey, lookupKey, value):
- def lookup():
- for recordType in self.recordTypes():
- record = self._storage(recordType)[cacheKey].get(value, None)
- if record:
- return record
- else:
- return None
-
- record = lookup()
-
- if record is None:
- # Cache miss; try looking the record up, in case it is new
- for recordType in self.recordTypes():
- # Check negative cache
- if value in self._storage(recordType)[disabledKey]:
- continue
-
- try:
- self.reloadCache(recordType, lookup=(lookupKey, value,))
- record = lookup()
- except opendirectory.ODError, e:
- if e.message[1] == -14140 or e.message[1] == -14200:
- # Unsupported attribute on record - don't fail
- record = None
- else:
- raise
-
- if record is None:
- self._storage(recordType)[disabledKey].add(value)
- else:
- self.log_info("Faulted record with %s %s into %s record cache"
- % (lookupKey, value, recordType))
- break
- else:
- # Nothing found; add to negative cache
- self.log_info("Unable to find any record with %s %s" % (lookupKey, value,))
-
- return record
-
- def groupsForGUID(self, guid):
-
- # Lookup in index
- try:
- return self._storage(self.recordType_groups)["groupsForGUID"][guid]
- except KeyError:
- return ()
-
- def proxiesForGUID(self, recordType, guid):
-
- # Lookup in index
- try:
- return self._storage(recordType)["proxiesForGUID"][guid]
- except KeyError:
- return ()
-
- def readOnlyProxiesForGUID(self, recordType, guid):
-
- # Lookup in index
- try:
- return self._storage(recordType)["readOnlyProxiesForGUID"][guid]
- except KeyError:
- return ()
-
- def _indexGroup(self, group, guids, index):
- for guid in guids:
- index.setdefault(guid, set()).add(group)
-
- _ODFields = {
- 'fullName' : {
- 'odField' : dsattributes.kDS1AttrDistinguishedName,
- 'appliesTo' : set([
- dsattributes.kDSStdRecordTypeUsers,
- dsattributes.kDSStdRecordTypeGroups,
- dsattributes.kDSStdRecordTypePlaces,
- dsattributes.kDSStdRecordTypeResources,
- ]),
- },
- 'firstName' : {
- 'odField' : dsattributes.kDS1AttrFirstName,
- 'appliesTo' : set([
- dsattributes.kDSStdRecordTypeUsers,
- ]),
- },
- 'lastName' : {
- 'odField' : dsattributes.kDS1AttrLastName,
- 'appliesTo' : set([
- dsattributes.kDSStdRecordTypeUsers,
- ]),
- },
- 'emailAddresses' : {
- 'odField' : dsattributes.kDSNAttrEMailAddress,
- 'appliesTo' : set([
- dsattributes.kDSStdRecordTypeUsers,
- dsattributes.kDSStdRecordTypeGroups,
- ]),
- },
- 'recordName' : {
- 'odField' : dsattributes.kDSNAttrRecordName,
- 'appliesTo' : set([
- dsattributes.kDSStdRecordTypeUsers,
- dsattributes.kDSStdRecordTypeGroups,
- dsattributes.kDSStdRecordTypePlaces,
- dsattributes.kDSStdRecordTypeResources,
- ]),
- },
- 'guid' : {
- 'odField' : dsattributes.kDS1AttrGeneratedUID,
- 'appliesTo' : set([
- dsattributes.kDSStdRecordTypeUsers,
- dsattributes.kDSStdRecordTypeGroups,
- dsattributes.kDSStdRecordTypePlaces,
- dsattributes.kDSStdRecordTypeResources,
- ]),
- },
- }
-
- _toODRecordTypes = {
- DirectoryService.recordType_users :
- dsattributes.kDSStdRecordTypeUsers,
- DirectoryService.recordType_locations :
- dsattributes.kDSStdRecordTypePlaces,
- DirectoryService.recordType_groups :
- dsattributes.kDSStdRecordTypeGroups,
- DirectoryService.recordType_resources :
- dsattributes.kDSStdRecordTypeResources,
- }
-
- _fromODRecordTypes = dict([(b, a) for a, b in _toODRecordTypes.iteritems()])
-
-
- def recordsMatchingFields(self, fields, operand="or", recordType=None):
-
- # Note that OD applies case-sensitivity globally across the entire
- # query, not per expression, so the current code uses whatever is
- # specified in the last field in the fields list
-
- def collectResults(results):
- self.log_info("Got back %d records from OD" % (len(results),))
- for key, val in results.iteritems():
- self.log_debug("OD result: %s %s" % (key, val))
- try:
- guid = val[dsattributes.kDS1AttrGeneratedUID]
- record = self.recordWithGUID(guid)
- if record:
- yield record
- except KeyError:
- pass
-
- def multiQuery(directory, queries, attrs, operand):
- results = {}
-
- for query, recordTypes in queries.iteritems():
- if not query:
- continue
-
- expressions = []
- for ODField, value, caseless, matchType in query:
- if matchType == "starts-with":
- comparison = dsattributes.eDSStartsWith
- elif matchType == "contains":
- comparison = dsattributes.eDSContains
- else:
- comparison = dsattributes.eDSExact
- expressions.append(dsquery.match(ODField, value, comparison))
-
- complexExpression = dsquery.expression(operand, expressions).generate()
-
- self.log_info("Calling OD: Types %s, Operand %s, Caseless %s, %s" %
- (recordTypes, operand, caseless, complexExpression))
-
- results.update(
- opendirectory.queryRecordsWithAttributes(
- directory,
- complexExpression,
- caseless,
- recordTypes,
- attrs,
- )
- )
-
- return results
-
-
- operand = (dsquery.expression.OR if operand == "or"
- else dsquery.expression.AND)
-
- if recordType is None:
- # The client is looking for records in any of the four types
- recordTypes = set(self._toODRecordTypes.values())
- else:
- # The client is after only one recordType
- recordTypes = [self._toODRecordTypes[recordType]]
-
- queries = buildQueries(recordTypes, fields, self._ODFields)
-
- deferred = deferToThread(
- multiQuery,
- self.directory,
- queries,
- [ dsattributes.kDS1AttrGeneratedUID ],
- operand
- )
- deferred.addCallback(collectResults)
- return deferred
-
-
- def reloadCache(self, recordType, lookup=None):
- if lookup is not None:
- self.log_info("Faulting record with %s %s into %s record cache" % (lookup[0], lookup[1], recordType))
- else:
- self.log_info("Reloading %s record cache" % (recordType,))
-
- results = self._queryDirectory(recordType, lookup=lookup)
-
- if lookup is None:
- records = {}
- guids = {}
- authIDs = {}
- cuas = {}
-
- disabledNames = set()
- disabledGUIDs = set()
- disabledAuthIDs = set()
- disabledCUAs = set()
-
- if recordType == self.recordType_groups:
- groupsForGUID = {}
- elif recordType in (self.recordType_resources, self.recordType_locations):
- proxiesForGUID = {}
- readOnlyProxiesForGUID = {}
- else:
- storage = self._records[recordType]
-
- records = storage["records"]
- guids = storage["guids"]
- authIDs = storage["authIDs"]
- cuas = storage["cuas"]
-
- disabledNames = storage["disabled names"]
- disabledGUIDs = storage["disabled guids"]
- disabledAuthIDs = storage["disabled authIDs"]
- disabledCUAs = storage["disabled cuas"]
-
- if recordType == self.recordType_groups:
- groupsForGUID = storage["groupsForGUID"]
- elif recordType in (self.recordType_resources, self.recordType_locations):
- proxiesForGUID = storage["proxiesForGUID"]
- readOnlyProxiesForGUID = storage["readOnlyProxiesForGUID"]
-
- enabled_count = 0
-
- def _uniqueTupleFromAttribute(attribute):
- if attribute:
- if isinstance(attribute, str):
- return (attribute,)
- else:
- s = set()
- return tuple([(s.add(x), x)[1] for x in attribute if x not in s])
- else:
- return ()
-
- def _setFromAttribute(attribute, lower=False):
- if attribute:
- if isinstance(attribute, str):
- return set((attribute.lower() if lower else attribute,))
- else:
- return set([item.lower() if lower else item for item in attribute])
- else:
- return ()
-
- for (recordShortName, value) in results:
-
- # Now get useful record info.
- recordGUID = value.get(dsattributes.kDS1AttrGeneratedUID)
- recordShortNames = _uniqueTupleFromAttribute(value.get(dsattributes.kDSNAttrRecordName))
- recordAuthIDs = _setFromAttribute(value.get(dsattributes.kDSNAttrAltSecurityIdentities))
- recordFullName = value.get(dsattributes.kDS1AttrDistinguishedName)
- recordFirstName = value.get(dsattributes.kDS1AttrFirstName)
- recordLastName = value.get(dsattributes.kDS1AttrLastName)
- recordEmailAddresses = _setFromAttribute(value.get(dsattributes.kDSNAttrEMailAddress), lower=True)
- recordNodeName = value.get(dsattributes.kDSNAttrMetaNodeLocation)
-
- if not recordGUID:
- self.log_debug("Record (%s)%s in node %s has no GUID; ignoring."
- % (recordType, recordShortName, recordNodeName))
- continue
-
- if recordGUID.lower().startswith("ffffeeee-dddd-cccc-bbbb-aaaa"):
- self.log_debug("Ignoring system record (%s)%s in node %s."
- % (recordType, recordShortName, recordNodeName))
- continue
-
- # Determine enabled state
- if recordType == self.recordType_groups:
- enabledForCalendaring = False
- else:
- if self.restrictEnabledRecords and self.restrictedGUIDs is not None:
- enabledForCalendaring = recordGUID in self.restrictedGUIDs
- else:
- enabledForCalendaring = True
-
- if enabledForCalendaring:
- enabled_count += 1
- calendarUserAddresses = self._calendarUserAddresses(recordType, value)
- else:
- # Some records we want to keep even though they are not enabled for calendaring.
- # Others we discard.
- if recordType not in (
- self.recordType_users,
- self.recordType_groups,
- ):
- self.log_debug(
- "Record (%s) %s is not enabled for calendaring"
- % (recordType, recordShortName)
- )
- continue
-
- self.log_debug(
- "Record (%s) %s is not enabled for calendaring but may be used in ACLs"
- % (recordType, recordShortName)
- )
- calendarUserAddresses = ()
-
- # Special case for groups, which have members.
- if recordType == self.recordType_groups:
- memberGUIDs = value.get(dsattributes.kDSNAttrGroupMembers)
- if memberGUIDs is None:
- memberGUIDs = ()
- elif type(memberGUIDs) is str:
- memberGUIDs = (memberGUIDs,)
- nestedGUIDs = value.get(dsattributes.kDSNAttrNestedGroups)
- if nestedGUIDs:
- if type(nestedGUIDs) is str:
- nestedGUIDs = (nestedGUIDs,)
- memberGUIDs += tuple(nestedGUIDs)
- else:
- memberGUIDs = ()
-
- record = OpenDirectoryRecord(
- service = self,
- recordType = recordType,
- guid = recordGUID,
- nodeName = recordNodeName,
- shortNames = recordShortNames,
- authIDs = recordAuthIDs,
- fullName = recordFullName,
- firstName = recordFirstName,
- lastName = recordLastName,
- emailAddresses = recordEmailAddresses,
- calendarUserAddresses = calendarUserAddresses,
- enabledForCalendaring = enabledForCalendaring,
- memberGUIDs = memberGUIDs,
- )
-
- def disableGUID(guid, record):
- """
- Disable the record by removing it from all indexes.
- """
-
- self.log_warn("GUID %s disabled due to conflict for record: %s"
- % (guid, record))
-
- disabledGUIDs.add(guid)
- disabledNames.update(record.shortNames)
- disabledAuthIDs.update(record.authIDs)
- disabledCUAs.update(record.calendarUserAddresses)
-
- if guid in guids:
- try:
- del guids[guid]
- except KeyError:
- pass
- for shortName in record.shortNames:
- try:
- del records[shortName]
- except KeyError:
- pass
- for authID in record.authIDs:
- try:
- del authIDs[authID]
- except KeyError:
- pass
- for cua in record.calendarUserAddresses:
- try:
- del cuas[cua]
- except KeyError:
- pass
-
- if record.guid in disabledGUIDs:
- disableGUID(record.guid, record)
- else:
- # Check for duplicates
- existing_record = guids.get(record.guid)
- if existing_record is not None:
- if existing_record.shortNames != record.shortNames:
- disableGUID(record.guid, record)
- disableGUID(record.guid, existing_record)
- if existing_record.enabledForCalendaring:
- enabled_count -= 1
- else:
- guids[record.guid] = record
- self.log_debug("Added record %s to OD record cache" % (record,))
- if record.enabledForCalendaring:
- enabled_count += 1
-
- # Do group indexing if needed
- if recordType == self.recordType_groups:
- self._indexGroup(record, record._memberGUIDs, groupsForGUID)
-
- # Index non-duplicate shortNames
- def disableName(shortName, record):
- self.log_warn("Short name %s disabled due to conflict for record: %s"
- % (shortName, record))
-
- record.shortNames = tuple([item for item in record.shortNames if item != shortName])
- disabledNames.add(shortName)
-
- if shortName in records:
- del records[shortName]
-
- for shortName in tuple(record.shortNames):
- if shortName in disabledNames:
- disableName(shortName, record)
- else:
- # Check for duplicates
- existing_record = records.get(shortName)
- if existing_record is not None and existing_record != record:
- disableName(shortName, record)
- disableName(shortName, existing_record)
- else:
- records[shortName] = record
-
- # Index non-duplicate authIDs
- def disableAuthIDs(authID, record):
- self.log_warn("Auth ID %s disabled due to conflict for record: %s"
- % (authID, record))
-
- record.authIDs.remove(authID)
- disabledAuthIDs.add(authID)
-
- if authID in authIDs:
- del authIDs[authID]
-
- for authID in frozenset(recordAuthIDs):
- if authID in disabledAuthIDs:
- disableAuthIDs(authID, record)
- else:
- # Check for duplicates
- existing_record = authIDs.get(authID)
- if existing_record is not None:
- disableAuthIDs(authID, record)
- disableAuthIDs(authID, existing_record)
- else:
- authIDs[authID] = record
-
- # Index non-duplicate CUAs
- def disableCUA(cua, record):
- self.log_warn("CUA %s disabled due to conflict for record: %s"
- % (cua, record))
-
- record.calendarUserAddresses.remove(cua)
- disabledCUAs.add(cua)
-
- if cua in cuas:
- del cuas[cua]
-
- if cua in records:
- del records[cua]
-
- for cua in frozenset(calendarUserAddresses):
- if cua in disabledCUAs:
- disableCUA(cua, record)
- else:
- # Check for duplicates
- existing_record = cuas.get(cua)
- if existing_record is not None:
- disableCUA(cua, record)
- disableCUA(cua, existing_record)
- else:
- cuas[cua] = record
-
- if lookup is None:
- #
- # Replace the entire cache
- #
- storage = {
- "status" : "new",
- "records" : records,
- "guids" : guids,
- "authIDs" : authIDs,
- "cuas" : cuas,
- "disabled names" : disabledNames,
- "disabled guids" : disabledGUIDs,
- "disabled authIDs" : disabledAuthIDs,
- "disabled cuas" : disabledCUAs,
- }
-
- # Add group indexing if needed
- if recordType == self.recordType_groups:
- storage["groupsForGUID"] = groupsForGUID
-
- # Add proxy indexing if needed
- elif recordType in (self.recordType_resources, self.recordType_locations):
- storage["proxiesForGUID"] = proxiesForGUID
- storage["readOnlyProxiesForGUID"] = readOnlyProxiesForGUID
-
- def rot():
- storage["status"] = "stale"
- removals = set()
- for call in self._delayedCalls:
- if not call.active():
- removals.add(call)
- for item in removals:
- self._delayedCalls.remove(item)
-
- #
- # Add jitter/fuzz factor to avoid stampede for large OD query
- # Max out the jitter at 60 minutes
- #
- cacheTimeout = min(self.cacheTimeout, 60) * 60
- cacheTimeout = (cacheTimeout * random()) - (cacheTimeout / 2)
- cacheTimeout += self.cacheTimeout * 60
- self._delayedCalls.add(callLater(cacheTimeout, rot))
-
- self._records[recordType] = storage
-
- self.log_info(
- "Added %d (%d enabled) records to %s OD record cache; expires in %d seconds"
- % (len(self._records[recordType]["guids"]), enabled_count, recordType, cacheTimeout)
- )
-
- def _queryDirectory(self, recordType, lookup=None):
- attrs = [
- dsattributes.kDS1AttrGeneratedUID,
- dsattributes.kDSNAttrRecordName,
- dsattributes.kDSNAttrAltSecurityIdentities,
- dsattributes.kDS1AttrDistinguishedName,
- dsattributes.kDS1AttrFirstName,
- dsattributes.kDS1AttrLastName,
- dsattributes.kDSNAttrEMailAddress,
- dsattributes.kDSNAttrMetaNodeLocation,
- ]
-
- if recordType == self.recordType_users:
- listRecordType = dsattributes.kDSStdRecordTypeUsers
-
- elif recordType == self.recordType_groups:
- listRecordType = dsattributes.kDSStdRecordTypeGroups
- attrs.append(dsattributes.kDSNAttrGroupMembers)
- attrs.append(dsattributes.kDSNAttrNestedGroups)
-
- elif recordType == self.recordType_locations:
- listRecordType = dsattributes.kDSStdRecordTypePlaces
- attrs.append(dsattributes.kDSNAttrResourceInfo)
-
- elif recordType == self.recordType_resources:
- listRecordType = dsattributes.kDSStdRecordTypeResources
- attrs.append(dsattributes.kDSNAttrResourceInfo)
-
- else:
- raise UnknownRecordTypeError("Unknown Open Directory record type: %s" % (recordType))
-
- # If restricting enabled records, then make sure the restricted group member
- # details are loaded. Do nested group expansion and include the nested groups
- # as enabled records too.
- if self.restrictEnabledRecords and self.restrictedGUIDs is None:
-
- attributeToMatch = dsattributes.kDS1AttrGeneratedUID if self.restrictToGUID else dsattributes.kDSNAttrRecordName
- valueToMatch = self.restrictToGroup
-
- self.log_debug("Doing restricted group membership check")
- self.log_debug("opendirectory.queryRecordsWithAttribute_list(%r,%r,%r,%r,%r,%r,%r)" % (
- self.directory,
- attributeToMatch,
- valueToMatch,
- dsattributes.eDSExact,
- False,
- dsattributes.kDSStdRecordTypeGroups,
- [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups,],
- ))
- results = opendirectory.queryRecordsWithAttribute_list(
- self.directory,
- attributeToMatch,
- valueToMatch,
- dsattributes.eDSExact,
- False,
- dsattributes.kDSStdRecordTypeGroups,
- [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups,],
- )
-
- if len(results) == 1:
- members = results[0][1].get(dsattributes.kDSNAttrGroupMembers, [])
- nestedGroups = results[0][1].get(dsattributes.kDSNAttrNestedGroups, [])
- else:
- members = []
- nestedGroups = []
-
- self.restrictedGUIDs = set(self._expandGroupMembership(members, nestedGroups, returnGroups=True))
- self.log_debug("Got %d restricted group members" % (len(self.restrictedGUIDs),))
-
- query = None
- if lookup is not None:
- indexType, indexKey = lookup
- origIndexKey = indexKey
-
- if indexType == "cua":
- # The directory doesn't contain CUAs, so we need to convert
- # the CUA to the appropriate field name and value:
- queryattr, indexKey = cuAddressConverter(indexKey)
- # queryattr will be one of:
- # guid, emailAddresses, or recordName
- # ...which will need to be mapped to DS
- queryattr = self._ODFields[queryattr]['odField']
-
- else:
- queryattr = {
- "shortName" : dsattributes.kDSNAttrRecordName,
- "guid" : dsattributes.kDS1AttrGeneratedUID,
- "authID" : dsattributes.kDSNAttrAltSecurityIdentities,
- }.get(indexType)
- assert queryattr is not None, "Invalid type for record faulting query"
-
- query = dsquery.match(queryattr, indexKey, dsattributes.eDSExact)
-
- try:
- if query:
- self.log_debug("opendirectory.queryRecordsWithAttribute_list(%r,%r,%r,%r,%r,%r,%r)" % (
- self.directory,
- query.attribute,
- query.value,
- query.matchType,
- False,
- listRecordType,
- attrs,
- ))
- results = opendirectory.queryRecordsWithAttribute_list(
- self.directory,
- query.attribute,
- query.value,
- query.matchType,
- False,
- listRecordType,
- attrs,
- )
- else:
- self.log_debug("opendirectory.listAllRecordsWithAttributes_list(%r,%r,%r)" % (
- self.directory,
- listRecordType,
- attrs,
- ))
- results = opendirectory.listAllRecordsWithAttributes_list(
- self.directory,
- listRecordType,
- attrs,
- )
- except opendirectory.ODError, ex:
- self.log_error("Open Directory (node=%s) error: %s" % (self.realmName, str(ex)))
- raise
-
- return results
-
- def getResourceInfo(self):
- """
- Resource information including proxy assignments for resource and
- locations, as well as auto-schedule settings, used to live in the
- directory. This method fetches old resource info for migration
- purposes.
- """
- attrs = [
- dsattributes.kDS1AttrGeneratedUID,
- dsattributes.kDSNAttrResourceInfo,
- ]
-
- for recordType in (dsattributes.kDSStdRecordTypePlaces, dsattributes.kDSStdRecordTypeResources):
- try:
- self.log_debug("opendirectory.listAllRecordsWithAttributes_list(%r,%r,%r)" % (
- self.directory,
- recordType,
- attrs,
- ))
- results = opendirectory.listAllRecordsWithAttributes_list(
- self.directory,
- recordType,
- attrs,
- )
- except opendirectory.ODError, ex:
- self.log_error("Open Directory (node=%s) error: %s" % (self.realmName, str(ex)))
- raise
-
- for (recordShortName, value) in results:
- recordGUID = value.get(dsattributes.kDS1AttrGeneratedUID)
- resourceInfo = value.get(dsattributes.kDSNAttrResourceInfo)
- if resourceInfo is not None:
- try:
- autoSchedule, proxy, readOnlyProxy = self._parseResourceInfo(resourceInfo,
- recordGUID, recordType, recordShortName)
- except ValueError:
- continue
- yield recordGUID, autoSchedule, proxy, readOnlyProxy
-
-
-def buildQueries(recordTypes, fields, mapping):
- """
- Determine how many queries need to be performed in order to work around opendirectory
- quirks, where searching on fields that don't apply to a given recordType returns incorrect
- results (either none, or all records).
- """
-
- fieldLists = {}
- for recordType in recordTypes:
- fieldLists[recordType] = []
- for field, value, caseless, matchType in fields:
- if field in mapping:
- if recordType in mapping[field]['appliesTo']:
- ODField = mapping[field]['odField']
- fieldLists[recordType].append((ODField, value, caseless, matchType))
-
- queries = {}
- for recordType, fieldList in fieldLists.iteritems():
- key = tuple(fieldList)
- queries.setdefault(key, []).append(recordType)
- return queries
-
-
-class OpenDirectoryRecord(DirectoryRecord):
- """
- Open Directory implementation of L{IDirectoryRecord}.
- """
- def __init__(
- self, service, recordType, guid, nodeName, shortNames, authIDs, fullName,
- firstName, lastName, emailAddresses,
- calendarUserAddresses, enabledForCalendaring,
- memberGUIDs,
- ):
- super(OpenDirectoryRecord, self).__init__(
- service = service,
- recordType = recordType,
- guid = guid,
- shortNames = shortNames,
- authIDs = authIDs,
- fullName = fullName,
- firstName = firstName,
- lastName = lastName,
- emailAddresses = emailAddresses,
- calendarUserAddresses = calendarUserAddresses,
- enabledForCalendaring = enabledForCalendaring,
- )
- self.nodeName = nodeName
- self._memberGUIDs = tuple(memberGUIDs)
-
- def __repr__(self):
- if self.service.realmName == self.nodeName:
- location = self.nodeName
- else:
- location = "%s->%s" % (self.service.realmName, self.nodeName)
-
- return "<%s[%s@%s(%s)] %s(%s) %r>" % (
- self.__class__.__name__,
- self.recordType,
- self.service.guid,
- location,
- self.guid,
- ",".join(self.shortNames),
- self.fullName
- )
-
- def members(self):
- if self.recordType != self.service.recordType_groups:
- return
-
- for guid in self._memberGUIDs:
- userRecord = self.service.recordWithGUID(guid)
- if userRecord is not None:
- yield userRecord
-
- def groups(self):
- return self.service.groupsForGUID(self.guid)
-
- def verifyCredentials(self, credentials):
- if isinstance(credentials, UsernamePassword):
- # Check cached password
- try:
- if credentials.password == self.password:
- return True
- except AttributeError:
- pass
-
- # Check with directory services
- try:
- if opendirectory.authenticateUserBasic(self.service.directory, self.nodeName, self.shortNames[0], credentials.password):
- # Cache the password to avoid future DS queries
- self.password = credentials.password
- return True
- except opendirectory.ODError, e:
- self.log_error("Open Directory (node=%s) error while performing basic authentication for user %s: %s"
- % (self.service.realmName, self.shortNames[0], e))
-
- return False
-
- elif isinstance(credentials, DigestedCredentials):
- #
- # We need a special format for the "challenge" and "response" strings passed into open directory, as it is
- # picky about exactly what it receives.
- #
- try:
- if "algorithm" not in credentials.fields:
- credentials.fields["algorithm"] = "md5"
- challenge = 'Digest realm="%(realm)s", nonce="%(nonce)s", algorithm=%(algorithm)s' % credentials.fields
- response = (
- 'Digest username="%(username)s", '
- 'realm="%(realm)s", '
- 'nonce="%(nonce)s", '
- 'uri="%(uri)s", '
- 'response="%(response)s",'
- 'algorithm=%(algorithm)s'
- ) % credentials.fields
- except KeyError, e:
- self.log_error(
- "Open Directory (node=%s) error while performing digest authentication for user %s: "
- "missing digest response field: %s in: %s"
- % (self.service.realmName, self.shortNames[0], e, credentials.fields)
- )
- return False
-
- try:
- if self.digestcache[credentials.fields["uri"]] == response:
- return True
- except (AttributeError, KeyError):
- pass
-
- try:
- if opendirectory.authenticateUserDigest(
- self.service.directory,
- self.nodeName,
- self.shortNames[0],
- challenge,
- response,
- credentials.originalMethod if credentials.originalMethod else credentials.method
- ):
- try:
- cache = self.digestcache
- except AttributeError:
- cache = self.digestcache = {}
-
- cache[credentials.fields["uri"]] = response
-
- return True
- else:
- self.log_debug(
-"""Open Directory digest authentication failed with:
- Nodename: %s
- Username: %s
- Challenge: %s
- Response: %s
- Method: %s
-""" % (self.nodeName, self.shortNames[0], challenge, response, credentials.originalMethod if credentials.originalMethod else credentials.method))
-
- except opendirectory.ODError, e:
- self.log_error(
- "Open Directory (node=%s) error while performing digest authentication for user %s: %s"
- % (self.service.realmName, self.shortNames[0], e)
- )
- return False
-
- return False
-
- return super(OpenDirectoryRecord, self).verifyCredentials(credentials)
-
-class OpenDirectoryInitError(DirectoryError):
- """
- OpenDirectory initialization error.
- """
Deleted: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldxmlfile.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldxmlfile.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/oldxmlfile.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -1,144 +0,0 @@
-##
-# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-##
-
-"""
-XML based user/group/resource directory service implementation.
-"""
-
-__all__ = [
- "XMLDirectoryService",
-]
-
-from time import time
-
-from twisted.cred.credentials import UsernamePassword
-from twisted.web2.auth.digest import DigestedCredentials
-from twisted.python.filepath import FilePath
-
-from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord
-from twistedcaldav.directory.xmlaccountsparser import XMLAccountsParser
-
-class XMLDirectoryService(DirectoryService):
- """
- XML based implementation of L{IDirectoryService}.
- """
- baseGUID = "9CA8DEC5-5A17-43A9-84A8-BE77C1FB9172"
-
- realmName = None
-
- def __repr__(self):
- return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.xmlFile)
-
- def __init__(self, xmlFile, alwaysStat=False):
- super(XMLDirectoryService, self).__init__()
-
- if type(xmlFile) is str:
- xmlFile = FilePath(xmlFile)
-
- self.xmlFile = xmlFile
- self._fileInfo = None
- self._lastCheck = 0
- self._alwaysStat = alwaysStat
- self._accounts()
-
- def recordTypes(self):
- recordTypes = (
- DirectoryService.recordType_users,
- DirectoryService.recordType_groups,
- DirectoryService.recordType_locations,
- DirectoryService.recordType_resources
- )
- return recordTypes
-
- def listRecords(self, recordType):
- for _ignore_entryShortName, xmlPrincipal in self._entriesForRecordType(recordType):
- yield XMLDirectoryRecord(
- service = self,
- recordType = recordType,
- shortNames = tuple(xmlPrincipal.shortNames),
- xmlPrincipal = xmlPrincipal,
- )
-
- def recordWithShortName(self, recordType, shortName):
- for _ignore_entryShortName, xmlPrincipal in self._entriesForRecordType(recordType):
- if shortName in xmlPrincipal.shortNames:
- return XMLDirectoryRecord(
- service = self,
- recordType = recordType,
- shortNames = tuple(xmlPrincipal.shortNames),
- xmlPrincipal = xmlPrincipal,
- )
-
- return None
-
- def _entriesForRecordType(self, recordType):
- try:
- for shortName, entry in sorted(self._accounts()[recordType].iteritems(), key=lambda x: x[0]):
- yield shortName, entry
- except KeyError:
- return
-
- def _accounts(self):
- currentTime = time()
- if self._alwaysStat or currentTime - self._lastCheck > 60:
- self.xmlFile.restat()
- self._lastCheck = currentTime
- fileInfo = (self.xmlFile.getmtime(), self.xmlFile.getsize())
- if fileInfo != self._fileInfo:
- parser = XMLAccountsParser(self.xmlFile)
- self._parsedAccounts = parser.items
- self.realmName = parser.realm
- self._fileInfo = fileInfo
- return self._parsedAccounts
-
-
-class XMLDirectoryRecord(DirectoryRecord):
- """
- XML based implementation implementation of L{IDirectoryRecord}.
- """
- def __init__(self, service, recordType, shortNames, xmlPrincipal):
- super(XMLDirectoryRecord, self).__init__(
- service = service,
- recordType = recordType,
- guid = xmlPrincipal.guid,
- shortNames = shortNames,
- fullName = xmlPrincipal.fullName,
- firstName = xmlPrincipal.firstName,
- lastName = xmlPrincipal.lastName,
- emailAddresses = xmlPrincipal.emailAddresses,
- calendarUserAddresses = xmlPrincipal.calendarUserAddresses,
- enabledForCalendaring = xmlPrincipal.enabledForCalendaring,
- )
-
- self.password = xmlPrincipal.password
- self._members = xmlPrincipal.members
- self._groups = xmlPrincipal.groups
-
- def members(self):
- for recordType, shortName in self._members:
- yield self.service.recordWithShortName(recordType, shortName)
-
- def groups(self):
- for shortName in self._groups:
- yield self.service.recordWithShortName(DirectoryService.recordType_groups, shortName)
-
- def verifyCredentials(self, credentials):
- if isinstance(credentials, UsernamePassword):
- return credentials.password == self.password
- if isinstance(credentials, DigestedCredentials):
- return credentials.checkPassword(self.password)
-
- return super(XMLDirectoryRecord, self).verifyCredentials(credentials)
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/principal.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/principal.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -74,7 +74,7 @@
class PermissionsMixIn (ReadOnlyResourceMixIn):
def defaultAccessControlList(self):
- return authReadACL
+ return succeed(authReadACL)
@inlineCallbacks
def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
@@ -87,7 +87,7 @@
else:
# ...otherwise permissions are fixed, and are not subject to
# inheritance rules, etc.
- returnValue(self.defaultAccessControlList())
+ returnValue((yield self.defaultAccessControlList()))
@@ -146,11 +146,12 @@
def __repr__(self):
return "<%s: %s %s>" % (self.__class__.__name__, self.directory, self._url)
+ @inlineCallbacks
def locateChild(self, req, segments):
- child = self.getChild(segments[0])
+ child = (yield self.getChild(segments[0]))
if child is not None:
- return (child, segments[1:])
- return (None, ())
+ returnValue( (child, segments[1:]) )
+ returnValue( (None, ()) )
def deadProperties(self):
if not hasattr(self, "_dead_properties"):
@@ -158,34 +159,38 @@
return self._dead_properties
def etag(self):
- return None
+ return succeed(None)
+ @inlineCallbacks
def principalForShortName(self, recordType, name):
- return self.principalForRecord(self.directory.recordWithShortName(recordType, name))
+ returnValue((yield self.principalForRecord((yield self.directory.recordWithShortName(recordType, name)))))
+ # Deferred
def principalForUser(self, user):
return self.principalForShortName(DirectoryService.recordType_users, user)
+ @inlineCallbacks
def principalForAuthID(self, user):
# Basic/Digest creds -> just lookup user name
if isinstance(user, UsernamePassword) or isinstance(user, DigestedCredentials):
- return self.principalForUser(user.username)
+ returnValue((yield self.principalForUser(user.username)))
elif isinstance(user, NegotiateCredentials):
authID = "Kerberos:%s" % (user.principal,)
- principal = self.principalForRecord(self.directory.recordWithAuthID(authID))
+ principal = (yield self.principalForRecord((yield self.directory.recordWithAuthID(authID))))
if principal:
- return principal
+ returnValue(principal)
elif user.username:
- return self.principalForUser(user.username)
+ returnValue((yield self.principalForUser(user.username)))
- return None
+ returnValue(None)
def principalForUID(self, uid):
raise NotImplementedError("Subclass must implement principalForUID()")
+ # Deferred
def principalForRecord(self, record):
if record is None:
- return None
+ return succeed(None)
return self.principalForUID(record.uid)
def principalForCalendarUserAddress(self, address):
@@ -263,9 +268,13 @@
self.putChild(uidsResourceName, DirectoryPrincipalUIDProvisioningResource(self))
+ @inlineCallbacks
def principalForUID(self, uid):
- return self.getChild(uidsResourceName).getChild(uid)
+ child = (yield self.getChild(uidsResourceName))
+ child = (yield child.getChild(uid))
+ returnValue(child)
+ @inlineCallbacks
def _principalForURI(self, uri):
scheme, netloc, path, _ignore_params, _ignore_query, _ignore_fragment = urlparse(uri)
@@ -286,51 +295,52 @@
port = int(netloc[1])
if host != config.ServerHostName:
- return None
+ returnValue(None)
if port != {
"http" : config.HTTPPort,
"https": config.SSLPort,
}[scheme]:
- return None
+ returnValue(None)
elif scheme == "urn":
if path.startswith("uuid:"):
- return self.principalForUID(path[5:])
+ returnValue((yield self.principalForUID(path[5:])))
else:
- return None
+ returnValue(None)
else:
- return None
+ returnValue(None)
if not path.startswith(self._url):
- return None
+ returnValue(None)
path = path[len(self._url) - 1:]
segments = [unquote(s) for s in path.rstrip("/").split("/")]
if segments[0] == "" and len(segments) == 3:
- typeResource = self.getChild(segments[1])
+ typeResource = (yield self.getChild(segments[1]))
if typeResource is not None:
- principalResource = typeResource.getChild(segments[2])
+ principalResource = (yield typeResource.getChild(segments[2]))
if principalResource:
- return principalResource
+ returnValue(principalResource)
- return None
+ returnValue(None)
+ @inlineCallbacks
def principalForCalendarUserAddress(self, address):
# First see if the address is a principal URI
- principal = self._principalForURI(address)
+ principal = (yield self._principalForURI(address))
if principal:
if isinstance(principal, DirectoryCalendarPrincipalResource):
- return principal
+ returnValue(principal)
else:
# Next try looking it up in the directory
- record = self.directory.recordWithCalendarUserAddress(address)
+ record = (yield self.directory.recordWithCalendarUserAddress(address))
if record is not None:
- return self.principalForRecord(record)
+ returnValue((yield self.principalForRecord(record)))
log.debug("No principal for calendar user address: %r" % (address,))
- return None
+ returnValue(None)
##
@@ -343,9 +353,9 @@
def getChild(self, name):
if name == "":
- return self
+ return succeed(self)
else:
- return self.putChildren.get(name, None)
+ return succeed(self.putChildren.get(name, None))
def listChildren(self):
return succeed(self.directory.recordTypes())
@@ -377,9 +387,11 @@
self.recordType = recordType
self.parent = parent
+ # Deferred
def principalForUID(self, uid):
return self.parent.principalForUID(uid)
+ # Deferred
def principalForCalendarUserAddress(self, address):
return self.parent.principalForCalendarUserAddress(address)
@@ -391,9 +403,10 @@
log.err("Attempt to create clone %r of resource %r" % (path, self))
raise HTTPError(responsecode.NOT_FOUND)
+ # Deferred
def getChild(self, name):
if name == "":
- return self
+ return succeed(self)
else:
return self.principalForShortName(self.recordType, name)
@@ -436,9 +449,11 @@
self.parent = parent
+ # Deferred
def principalForUID(self, uid):
return self.parent.principalForUID(uid)
+ # Deferred
def principalForCalendarUserAddress(self, address):
return self.parent.principalForCalendarUserAddress(address)
@@ -450,9 +465,10 @@
log.err("Attempt to create clone %r of resource %r" % (path, self))
raise HTTPError(responsecode.NOT_FOUND)
+ @inlineCallbacks
def getChild(self, name):
if name == "":
- return self
+ returnValue(self)
if "#" in name:
# This UID belongs to a sub-principal
@@ -461,11 +477,11 @@
primaryUID = name
subType = None
- record = self.directory.recordWithUID(primaryUID)
+ record = (yield self.directory.recordWithUID(primaryUID))
if record is None:
log.err("No principal found for UID: %s" % (name,))
- return None
+ returnValue(None)
if record.enabledForCalendaring:
primaryPrincipal = DirectoryCalendarPrincipalResource(self, record)
@@ -473,9 +489,9 @@
primaryPrincipal = DirectoryPrincipalResource(self, record)
if subType is None:
- return primaryPrincipal
+ returnValue(primaryPrincipal)
else:
- return primaryPrincipal.getChild(subType)
+ returnValue((yield primaryPrincipal.getChild(subType)))
def listChildren(self):
# Not a listable collection
@@ -568,7 +584,7 @@
return self._dead_properties
def etag(self):
- return None
+ return succeed(None)
##
# HTTP
@@ -667,7 +683,7 @@
proxyFors = set()
if resolve_memberships:
- memberships = self._getRelatives("groups", infinity=True)
+ memberships = (yield self._getRelatives("groups", infinity=True))
for membership in memberships:
results = (yield membership.proxyFor(read_write, False))
proxyFors.update(results)
@@ -677,7 +693,7 @@
proxies = []
memberships = (yield self._calendar_user_proxy_index().getMemberships(self.principalUID()))
for uid in memberships:
- subprincipal = self.parent.principalForUID(uid)
+ subprincipal = (yield self.parent.principalForUID(uid))
if subprincipal:
if subprincipal.isProxyType(read_write):
proxies.append(subprincipal.parent)
@@ -688,6 +704,7 @@
returnValue(proxyFors)
+ @inlineCallbacks
def _getRelatives(self, method, record=None, relatives=None, records=None, proxy=None, infinity=False):
if record is None:
record = self.record
@@ -698,41 +715,43 @@
if record not in records:
records.add(record)
- for relative in getattr(record, method)():
+ for relative in (yield getattr(record, method)()):
if relative not in records:
- found = self.parent.principalForRecord(relative)
+ found = (yield self.parent.principalForRecord(relative))
if found is None:
log.err("No principal found for directory record: %r" % (relative,))
else:
if proxy:
if proxy == "read-write":
- found = found.getChild("calendar-proxy-write")
+ found = (yield found.getChild("calendar-proxy-write"))
else:
- found = found.getChild("calendar-proxy-read")
+ found = (yield found.getChild("calendar-proxy-read"))
relatives.add(found)
if infinity:
- self._getRelatives(method, relative, relatives, records,
+ yield self._getRelatives(method, relative, relatives, records,
infinity=infinity)
- return relatives
+ returnValue(relatives)
+ # Deferred
def groupMembers(self):
- return succeed(self._getRelatives("members"))
+ return self._getRelatives("members")
+ # Deferred
def expandedGroupMembers(self):
- return succeed(self._getRelatives("members", infinity=True))
+ return self._getRelatives("members", infinity=True)
@inlineCallbacks
def groupMemberships(self, infinity=False):
- groups = self._getRelatives("groups", infinity=infinity)
+ groups = (yield self._getRelatives("groups", infinity=infinity))
if config.EnableProxyPrincipals:
# Get proxy group UIDs and map to principal resources
proxies = []
memberships = (yield self._calendar_user_proxy_index().getMemberships(self.principalUID()))
for uid in memberships:
- subprincipal = self.parent.principalForUID(uid)
+ subprincipal = (yield self.parent.principalForUID(uid))
if subprincipal:
proxies.append(subprincipal)
else:
@@ -757,7 +776,7 @@
##
def setAutoSchedule(self, autoSchedule):
- self._resource_info_index().setAutoSchedule(self.record.guid, autoSchedule)
+ return self._resource_info_index().setAutoSchedule(self.record.guid, autoSchedule)
@inlineCallbacks
def getAutoSchedule(self):
@@ -798,17 +817,18 @@
log.err("Attempt to create clone %r of resource %r" % (path, self))
raise HTTPError(responsecode.NOT_FOUND)
+ @inlineCallbacks
def locateChild(self, req, segments):
- child = self.getChild(segments[0])
+ child = (yield self.getChild(segments[0]))
if child is not None:
- return (child, segments[1:])
- return (None, ())
+ returnValue((child, segments[1:]))
+ returnValue((None, ()))
def getChild(self, name):
if name == "":
- return self
+ return succeed(self)
- return None
+ return succeed(None)
def listChildren(self):
return succeed(())
@@ -934,12 +954,12 @@
def getChild(self, name):
if name == "":
- return self
+ return succeed(self)
if config.EnableProxyPrincipals and name in ("calendar-proxy-read", "calendar-proxy-write"):
- return CalendarUserProxyPrincipalResource(self, name)
+ return succeed(CalendarUserProxyPrincipalResource(self, name))
else:
- return None
+ return succeed(None)
def listChildren(self):
if config.EnableProxyPrincipals:
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/resource.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/resource.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/resource.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -20,7 +20,7 @@
__all__ = ["AutoProvisioningResourceMixIn"]
-from twisted.internet.defer import maybeDeferred
+from twisted.internet.defer import maybeDeferred, succeed
class AutoProvisioningResourceMixIn (object):
"""
@@ -36,7 +36,7 @@
already provisioned (eg. the backing store exists).
@return: a deferred or None.
"""
- return None
+ return succeed(None)
def provisionChild(self, name):
"""
@@ -48,7 +48,7 @@
@return: the newly created (optionally deferred) child, or None of no resource
is bound as a child of this resource with the given C{name}.
"""
- return None
+ return succeed(None)
def locateChild(self, request, segments):
"""
Deleted: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sqldb.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sqldb.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sqldb.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -1,368 +0,0 @@
-##
-# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-##
-
-"""
-SQL (sqlite) based user/group/resource directory service implementation.
-"""
-
-"""
-SCHEMA:
-
-User Database:
-
-ROW: RECORD_TYPE, SHORT_NAME (unique), PASSWORD, NAME
-
-Group Database:
-
-ROW: SHORT_NAME, MEMBER_SHORT_NAME
-
-CUAddress database:
-
-ROW: ADDRESS (unqiue), SHORT_NAME
-
-"""
-
-__all__ = [
- "SQLDirectoryService",
-]
-
-from twisted.cred.credentials import UsernamePassword
-from twisted.python.filepath import FilePath
-
-from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord
-from twistedcaldav.directory.xmlaccountsparser import XMLAccountsParser
-from twistedcaldav.sql import AbstractSQLDatabase
-from twistedcaldav.sql import db_prefix
-
-import os
-
-class SQLDirectoryManager(AbstractSQLDatabase):
- """
- House keeping operations on the SQL DB, including loading from XML file,
- and record dumping. This can be used as a standalong DB management tool.
- """
- dbType = "DIRECTORYSERVICE"
- dbFilename = db_prefix + "accounts"
- dbFormatVersion = "3"
-
- def __init__(self, path):
- path = os.path.join(path, SQLDirectoryManager.dbFilename)
- super(SQLDirectoryManager, self).__init__(path, True)
-
- def loadFromXML(self, xmlFile):
- parser = XMLAccountsParser(xmlFile)
-
- # Totally wipe existing DB and start from scratch
- if os.path.exists(self.dbpath):
- os.remove(self.dbpath)
-
- self._db_execute("insert into SERVICE (REALM) values (:1)", parser.realm)
-
- # Now add records to db
- for item in parser.items.values():
- for entry in item.itervalues():
- self._add_to_db(entry)
- self._db_commit()
-
- def getRealm(self):
- for realm in self._db_execute("select REALM from SERVICE"):
- return realm[0].decode("utf-8")
- else:
- return ""
-
- def listRecords(self, recordType):
- # Get each account record
- for shortName, guid, password, name in self._db_execute(
- """
- select SHORT_NAME, GUID, PASSWORD, NAME
- from ACCOUNTS
- where RECORD_TYPE = :1
- """, recordType
- ):
- # See if we have members
- members = self.members(shortName)
-
- # See if we are a member of any groups
- groups = self.groups(shortName)
-
- # Get calendar user addresses
- calendarUserAddresses = self.calendarUserAddresses(shortName)
-
- yield shortName, guid, password, name, members, groups, calendarUserAddresses
-
- def getRecord(self, recordType, shortName):
- # Get individual account record
- for shortName, guid, password, name in self._db_execute(
- """
- select SHORT_NAME, GUID, PASSWORD, NAME
- from ACCOUNTS
- where RECORD_TYPE = :1
- and SHORT_NAME = :2
- """, recordType, shortName
- ):
- break
- else:
- return None
-
- # See if we have members
- members = self.members(shortName)
-
- # See if we are a member of any groups
- groups = self.groups(shortName)
-
- # Get calendar user addresses
- calendarUserAddresses = self.calendarUserAddresses(shortName)
-
- return shortName, guid, password, name, members, groups, calendarUserAddresses
-
- def members(self, shortName):
- members = set()
- for member in self._db_execute(
- """
- select MEMBER_RECORD_TYPE, MEMBER_SHORT_NAME
- from GROUPS
- where SHORT_NAME = :1
- """, shortName
- ):
- members.add(tuple(member))
- return members
-
- def groups(self, shortName):
- groups = set()
- for (name,) in self._db_execute(
- """
- select SHORT_NAME
- from GROUPS
- where MEMBER_SHORT_NAME = :1
- """, shortName
- ):
- groups.add(name)
- return groups
-
- def calendarUserAddresses(self, shortName):
- calendarUserAddresses = set()
- for (address,) in self._db_execute(
- """
- select ADDRESS
- from ADDRESSES
- where SHORT_NAME = :1
- """, shortName
- ):
- calendarUserAddresses.add(address)
- return calendarUserAddresses
-
- def _add_to_db(self, record):
- # Do regular account entry
- recordType = record.recordType
- shortName = record.shortNames[0]
- guid = record.guid
- password = record.password
- name = record.fullName
-
- self._db_execute(
- """
- insert into ACCOUNTS (RECORD_TYPE, SHORT_NAME, GUID, PASSWORD, NAME)
- values (:1, :2, :3, :4, :5)
- """, recordType, shortName, guid, password, name
- )
-
- # Check for members
- for memberRecordType, memberShortName in record.members:
- self._db_execute(
- """
- insert into GROUPS (SHORT_NAME, MEMBER_RECORD_TYPE, MEMBER_SHORT_NAME)
- values (:1, :2, :3)
- """, shortName, memberRecordType, memberShortName
- )
-
- # CUAddress
- for cuaddr in record.calendarUserAddresses:
- self._db_execute(
- """
- insert into ADDRESSES (ADDRESS, SHORT_NAME)
- values (:1, :2)
- """, cuaddr, shortName
- )
-
- def _delete_from_db(self, shortName):
- """
- Deletes the specified entry from all dbs.
- @param name: the name of the resource to delete.
- @param shortName: the short name of the resource to delete.
- """
- self._db_execute("delete from ACCOUNTS where SHORT_NAME = :1", shortName)
- self._db_execute("delete from GROUPS where SHORT_NAME = :1", shortName)
- self._db_execute("delete from GROUPS where MEMBER_SHORT_NAME = :1", shortName)
- self._db_execute("delete from ADDRESSES where SHORT_NAME = :1", shortName)
-
- def _db_version(self):
- """
- @return: the schema version assigned to this index.
- """
- return SQLDirectoryManager.dbFormatVersion
-
- def _db_type(self):
- """
- @return: the collection type assigned to this index.
- """
- return SQLDirectoryManager.dbType
-
- def _db_init_data_tables(self, q):
- """
- Initialise the underlying database tables.
- @param q: a database cursor to use.
- """
- #
- # SERVICE table
- #
- q.execute("create table SERVICE (REALM text)")
-
- #
- # ACCOUNTS table
- #
- q.execute(
- """
- create table ACCOUNTS (
- RECORD_TYPE text,
- SHORT_NAME text,
- GUID text,
- PASSWORD text,
- NAME text
- )
- """
- )
-
- #
- # GROUPS table
- #
- q.execute(
- """
- create table GROUPS (
- SHORT_NAME text,
- MEMBER_RECORD_TYPE text,
- MEMBER_SHORT_NAME text
- )
- """
- )
-
- #
- # ADDRESSES table
- #
- q.execute(
- """
- create table ADDRESSES (
- ADDRESS text unique,
- SHORT_NAME text
- )
- """
- )
-
-class SQLDirectoryService(DirectoryService):
- """
- XML based implementation of L{IDirectoryService}.
- """
- baseGUID = "8256E464-35E0-4DBB-A99C-F0E30C231675"
- realmName = None
-
- def __repr__(self):
- return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.manager.dbpath)
-
- def __init__(self, dbParentPath, xmlFile=None):
- super(SQLDirectoryService, self).__init__()
-
- if type(dbParentPath) is str:
- dbParentPath = FilePath(dbParentPath)
-
- self.manager = SQLDirectoryManager(dbParentPath.path)
- if xmlFile:
- self.manager.loadFromXML(xmlFile)
- self.realmName = self.manager.getRealm()
-
- def recordTypes(self):
- recordTypes = (
- DirectoryService.recordType_users,
- DirectoryService.recordType_groups,
- DirectoryService.recordType_locations,
- DirectoryService.recordType_resources,
- )
- return recordTypes
-
- def listRecords(self, recordType):
- for result in self.manager.listRecords(recordType):
- yield SQLDirectoryRecord(
- service = self,
- recordType = recordType,
- shortName = result[0],
- guid = result[1],
- password = result[2],
- name = result[3],
- members = result[4],
- groups = result[5],
- calendarUserAddresses = result[6],
- )
-
- def recordWithShortName(self, recordType, shortName):
- result = self.manager.getRecord(recordType, shortName)
- if result:
- return SQLDirectoryRecord(
- service = self,
- recordType = recordType,
- shortName = result[0],
- guid = result[1],
- password = result[2],
- name = result[3],
- members = result[4],
- groups = result[5],
- calendarUserAddresses = result[6],
- )
-
- return None
-
-class SQLDirectoryRecord(DirectoryRecord):
- """
- XML based implementation implementation of L{IDirectoryRecord}.
- """
- def __init__(self, service, recordType, shortName, guid, password, name, members, groups, calendarUserAddresses):
- super(SQLDirectoryRecord, self).__init__(
- service = service,
- recordType = recordType,
- guid = guid,
- shortNames = (shortName,),
- fullName = name,
- calendarUserAddresses = calendarUserAddresses,
- )
-
- self.password = password
- self._members = members
- self._groups = groups
-
- def members(self):
- for recordType, shortName in self._members:
- yield self.service.recordWithShortName(recordType, shortName)
-
- def groups(self):
- for shortName in self._groups:
- yield self.service.recordWithShortName(DirectoryService.recordType_groups, shortName)
-
- def verifyCredentials(self, credentials):
- if isinstance(credentials, UsernamePassword):
- return credentials.password == self.password
-
- return super(SQLDirectoryRecord, self).verifyCredentials(credentials)
-
-if __name__ == '__main__':
- mgr = SQLDirectoryManager("./")
- mgr.loadFromXML("test/accounts.xml")
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sudo.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sudo.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/sudo.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -26,6 +26,7 @@
from twisted.python.filepath import FilePath
from twisted.cred.credentials import IUsernamePassword, IUsernameHashedPassword
from twisted.cred.error import UnauthorizedLogin
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
from twext.python.plistlib import readPlist
@@ -93,8 +94,9 @@
for entry in self._accounts()['users']:
if entry['username'] == shortName:
- return self._recordForEntry(entry)
+ return succeed(self._recordForEntry(entry))
+ @inlineCallbacks
def requestAvatarId(self, credentials):
# FIXME: ?
# We were checking if principal is enabled; seems unnecessary in current
@@ -105,11 +107,11 @@
raise UnauthorizedLogin("No such user: %s" % (credentials.credentials.username,))
sudouser = credentials.authnPrincipal.record
- if credentials.authnPrincipal.record.verifyCredentials(credentials.credentials):
- return (
+ if (yield credentials.authnPrincipal.record.verifyCredentials(credentials.credentials)):
+ returnValue( (
credentials.authnPrincipal.principalURL(),
credentials.authzPrincipal.principalURL(),
- )
+ ) )
else:
raise UnauthorizedLogin(
"Incorrect credentials for %s" % (sudouser,))
@@ -134,8 +136,8 @@
def verifyCredentials(self, credentials):
if IUsernamePassword.providedBy(credentials):
- return credentials.checkPassword(self.password)
+ return succeed(credentials.checkPassword(self.password))
elif IUsernameHashedPassword.providedBy(credentials):
- return credentials.checkPassword(self.password)
+ return succeed(credentials.checkPassword(self.password))
return super(SudoDirectoryRecord, self).verifyCredentials(credentials)
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_cachedirectory.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_cachedirectory.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_cachedirectory.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -14,6 +14,7 @@
# limitations under the License.
##
+from twisted.internet.defer import inlineCallbacks
from twistedcaldav.directory.cachingdirectory import CachingDirectoryService,\
CachingDirectoryRecord, DictRecordTypeCache
from twistedcaldav.test.util import TestCase
@@ -161,10 +162,11 @@
self.verifyRecords(DirectoryService.recordType_resources, set())
self.verifyRecords(DirectoryService.recordType_locations, set())
+ @inlineCallbacks
def test_cacheoneguid(self):
self.dummyRecords()
- self.assertTrue(self.service.recordWithGUID(self.guidForShortName("user01")) is not None)
+ self.assertTrue((yield self.service.recordWithGUID(self.guidForShortName("user01"))) is not None)
self.assertTrue(self.service.queried)
self.verifyRecords(DirectoryService.recordType_users, set((
self.guidForShortName("user01"),
@@ -175,16 +177,17 @@
# Make sure it really is cached and won't cause another query
self.service.queried = False
- self.assertTrue(self.service.recordWithGUID(self.guidForShortName("user01")) is not None)
+ self.assertTrue((yield self.service.recordWithGUID(self.guidForShortName("user01"))) is not None)
self.assertFalse(self.service.queried)
+ @inlineCallbacks
def test_cacheoneshortname(self):
self.dummyRecords()
- self.assertTrue(self.service.recordWithShortName(
+ self.assertTrue((yield self.service.recordWithShortName(
DirectoryService.recordType_users,
"user02"
- ) is not None)
+ )) is not None)
self.assertTrue(self.service.queried)
self.verifyRecords(DirectoryService.recordType_users, set((
self.guidForShortName("user02"),
@@ -195,18 +198,19 @@
# Make sure it really is cached and won't cause another query
self.service.queried = False
- self.assertTrue(self.service.recordWithShortName(
+ self.assertTrue((yield self.service.recordWithShortName(
DirectoryService.recordType_users,
"user02"
- ) is not None)
+ )) is not None)
self.assertFalse(self.service.queried)
+ @inlineCallbacks
def test_cacheoneemail(self):
self.dummyRecords()
- self.assertTrue(self.service.recordWithCalendarUserAddress(
+ self.assertTrue((yield self.service.recordWithCalendarUserAddress(
"mailto:user03 at example.com"
- ) is not None)
+ )) is not None)
self.assertTrue(self.service.queried)
self.verifyRecords(DirectoryService.recordType_users, set((
self.guidForShortName("user03"),
@@ -217,17 +221,18 @@
# Make sure it really is cached and won't cause another query
self.service.queried = False
- self.assertTrue(self.service.recordWithCalendarUserAddress(
+ self.assertTrue((yield self.service.recordWithCalendarUserAddress(
"mailto:user03 at example.com"
- ) is not None)
+ )) is not None)
self.assertFalse(self.service.queried)
+ @inlineCallbacks
def test_cacheoneauthid(self):
self.dummyRecords()
- self.assertTrue(self.service.recordWithAuthID(
+ self.assertTrue((yield self.service.recordWithAuthID(
"Kerberos:user03 at example.com"
- ) is not None)
+ )) is not None)
self.assertTrue(self.service.queried)
self.verifyRecords(DirectoryService.recordType_users, set((
self.guidForShortName("user03"),
@@ -238,7 +243,7 @@
# Make sure it really is cached and won't cause another query
self.service.queried = False
- self.assertTrue(self.service.recordWithAuthID(
+ self.assertTrue((yield self.service.recordWithAuthID(
"Kerberos:user03 at example.com"
- ) is not None)
+ )) is not None)
self.assertFalse(self.service.queried)
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_calendar.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_calendar.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_calendar.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -32,6 +32,7 @@
"""
Directory service provisioned principals.
"""
+ @inlineCallbacks
def setUp(self):
super(ProvisionedCalendars, self).setUp()
@@ -48,18 +49,20 @@
provisioningResource = DirectoryPrincipalProvisioningResource(url, self.directoryService)
- self.site.resource.putChild("principals", provisioningResource)
+ yield self.site.resource.putChild("principals", provisioningResource)
- self.setupCalendars()
+ yield self.setupCalendars()
self.site.resource.setAccessControlList(davxml.ACL())
+ @inlineCallbacks
def setupCalendars(self):
- calendarCollection = CalendarHomeProvisioningFile(
+ calendarCollection = (yield CalendarHomeProvisioningFile.fetch(
+ None,
os.path.join(self.docroot, "calendars"),
self.directoryService,
"/calendars/"
- )
+ ))
self.site.resource.putChild("calendars", calendarCollection)
def test_NonExistentCalendarHome(self):
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_guidchange.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_guidchange.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_guidchange.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -19,6 +19,7 @@
import os
+from twisted.internet.defer import inlineCallbacks
from twisted.web2.dav import davxml
from twisted.web2.dav.resource import AccessDeniedError
from twisted.web2.test.test_server import SimpleRequest
@@ -76,6 +77,7 @@
homeResource = "/calendars/users/cdaboo/"
+ @inlineCallbacks
def privs1(result):
# Change GUID in record
fd = open(self.xmlfile, "w")
@@ -85,13 +87,13 @@
# Force re-read of records (not sure why _fileInfo has to be wiped here...)
self.directoryService._fileInfo = (0, 0)
- self.directoryService.recordWithShortName(DirectoryService.recordType_users, "cdaboo")
+ yield self.directoryService.recordWithShortName(DirectoryService.recordType_users, "cdaboo")
# Now force the calendar home resource to be reset
self.resetCalendars()
# Make sure new user cannot access old user's calendar home
- return self._checkPrivileges(None, homeResource, davxml.HRef("/principals/__uids__/" + newUID + "/"), davxml.Write, False)
+ returnValue((yield self._checkPrivileges(None, homeResource, davxml.HRef("/principals/__uids__/" + newUID + "/"), davxml.Write, False)))
# Make sure current user has access to their calendar home
d = self._checkPrivileges(None, homeResource, davxml.HRef("/principals/__uids__/" + oldUID + "/"), davxml.Write, True)
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_opendirectory.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_opendirectory.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_opendirectory.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -20,6 +20,7 @@
pass
else:
import twisted.web2.auth.digest
+ from twisted.internet.defer import inlineCallbacks
import twistedcaldav.directory.test.util
from twistedcaldav.directory.directory import DirectoryService
from twistedcaldav.directory.appleopendirectory import OpenDirectoryRecord
@@ -78,6 +79,7 @@
)
self.assertEquals(record.fullName, "")
+ @inlineCallbacks
def test_invalidODDigest(self):
record = OpenDirectoryRecord(
service = self.service(),
@@ -98,7 +100,7 @@
digestFields = {}
digested = twisted.web2.auth.digest.DigestedCredentials("user", "GET", "example.com", digestFields, None)
- self.assertFalse(record.verifyCredentials(digested))
+ self.assertFalse((yield record.verifyCredentials(digested)))
def test_validODDigest(self):
record = OpenDirectoryRecord(
@@ -146,6 +148,7 @@
self.assertTrue(record.verifyCredentials(digested))
+ @inlineCallbacks
def test_queryDirectorySingleGUID(self):
""" Test for lookup on existing and non-existing GUIDs """
@@ -165,11 +168,12 @@
return results
recordTypes = [DirectoryService.recordType_users, DirectoryService.recordType_groups, DirectoryService.recordType_locations, DirectoryService.recordType_resources]
- self.service().queryDirectory(recordTypes, self.service().INDEX_TYPE_GUID, "1234567890", lookupMethod=lookupMethod)
- self.assertTrue(self.service().recordWithGUID("1234567890"))
- self.assertFalse(self.service().recordWithGUID("987654321"))
+ yield self.service().queryDirectory(recordTypes, self.service().INDEX_TYPE_GUID, "1234567890", lookupMethod=lookupMethod)
+ self.assertTrue((yield self.service().recordWithGUID("1234567890")))
+ self.assertFalse((yield self.service().recordWithGUID("987654321")))
+ @inlineCallbacks
def test_queryDirectoryDuplicateGUIDs(self):
""" Test for lookup on duplicate GUIDs, ensuring they don't get
faulted in """
@@ -195,5 +199,5 @@
return results
recordTypes = [DirectoryService.recordType_users, DirectoryService.recordType_groups, DirectoryService.recordType_locations, DirectoryService.recordType_resources]
- self.service().queryDirectory(recordTypes, self.service().INDEX_TYPE_GUID, "1234567890", lookupMethod=lookupMethod)
- self.assertFalse(self.service().recordWithGUID("1234567890"))
+ yield self.service().queryDirectory(recordTypes, self.service().INDEX_TYPE_GUID, "1234567890", lookupMethod=lookupMethod)
+ self.assertFalse((yield self.service().recordWithGUID("1234567890")))
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_principal.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_principal.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_principal.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -17,7 +17,7 @@
import os
from twisted.cred.credentials import UsernamePassword
-from twisted.internet.defer import inlineCallbacks, gatherResults
+from twisted.internet.defer import inlineCallbacks, gatherResults, returnValue
from twisted.web2.dav import davxml
from twisted.web2.dav.fileop import rmdir
from twisted.web2.dav.resource import AccessDeniedError
@@ -81,6 +81,7 @@
self.principalRootResources[directory.__class__.__name__] = provisioningResource
+ @inlineCallbacks
def test_hierarchy(self):
"""
DirectoryPrincipalProvisioningResource.listChildren(),
@@ -105,59 +106,58 @@
principalCollections = provisioningResource.principalCollections()
self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
- d = provisioningResource.listChildren()
- def _gotProvisioningChildren(children):
- recordTypes = set(children)
- self.assertEquals(recordTypes, set(directory.recordTypes()))
+ children = (yield provisioningResource.listChildren())
+ recordTypes = set(children)
+ self.assertEquals(recordTypes, set(directory.recordTypes()))
- for recordType in recordTypes:
- #print " -> %s" % (recordType,)
- typeResource = provisioningResource.getChild(recordType)
- self.failUnless(isinstance(typeResource, DirectoryPrincipalTypeProvisioningResource))
+ for recordType in recordTypes:
+ #print " -> %s" % (recordType,)
+ typeResource = (yield provisioningResource.getChild(recordType))
+ self.failUnless(isinstance(typeResource, DirectoryPrincipalTypeProvisioningResource))
- typeURL = provisioningURL + recordType + "/"
- self.assertEquals(typeURL, typeResource.principalCollectionURL())
+ typeURL = provisioningURL + recordType + "/"
+ self.assertEquals(typeURL, typeResource.principalCollectionURL())
- principalCollections = typeResource.principalCollections()
- self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
- d = typeResource.listChildren()
- def _gotTypeChildren(children):
- shortNames = set(children)
- self.assertEquals(shortNames, set(r.shortNames[0] for r in directory.listRecords(recordType)))
+ principalCollections = typeResource.principalCollections()
+ self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
+ shortNames = set((yield typeResource.listChildren()))
+ self.assertEquals(shortNames, set(r.shortNames[0] for r in directory.listRecords(recordType)))
- for shortName in shortNames:
- #print " -> %s" % (shortName,)
- recordResource = typeResource.getChild(shortName)
- self.failUnless(isinstance(recordResource, DirectoryPrincipalResource))
+ for shortName in shortNames:
+ #print " -> %s" % (shortName,)
+ recordResource = (yield typeResource.getChild(shortName))
+ self.failUnless(isinstance(recordResource, DirectoryPrincipalResource))
- recordURL = typeURL + shortName + "/"
- self.assertIn(recordURL, (recordResource.principalURL(),) + tuple(recordResource.alternateURIs()))
+ recordURL = typeURL + shortName + "/"
+ self.assertIn(recordURL, (recordResource.principalURL(),) + tuple(recordResource.alternateURIs()))
- principalCollections = recordResource.principalCollections()
- self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
+ principalCollections = recordResource.principalCollections()
+ self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
- return d.addCallback(_gotProvisioningChildren)
+ @inlineCallbacks
def test_allRecords(self):
"""
Test of a test routine...
"""
- for provisioningResource, recordType, recordResource, record in self._allRecords():
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
self.assertEquals(recordResource.record, record)
##
# DirectoryPrincipalProvisioningResource
##
+ @inlineCallbacks
def test_principalForShortName(self):
"""
DirectoryPrincipalProvisioningResource.principalForShortName()
"""
- for provisioningResource, recordType, recordResource, record in self._allRecords():
- principal = provisioningResource.principalForShortName(recordType, record.shortNames[0])
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
+ principal = (yield provisioningResource.principalForShortName(recordType, record.shortNames[0]))
self.failIf(principal is None)
self.assertEquals(record, principal.record)
+ @inlineCallbacks
def test_principalForUser(self):
"""
DirectoryPrincipalProvisioningResource.principalForUser()
@@ -166,10 +166,11 @@
provisioningResource = self.principalRootResources[directory.__class__.__name__]
for user in directory.listRecords(DirectoryService.recordType_users):
- userResource = provisioningResource.principalForUser(user.shortNames[0])
+ userResource = (yield provisioningResource.principalForUser(user.shortNames[0]))
self.failIf(userResource is None)
self.assertEquals(user, userResource.record)
+ @inlineCallbacks
def test_principalForAuthID(self):
"""
DirectoryPrincipalProvisioningResource.principalForAuthID()
@@ -179,33 +180,36 @@
for user in directory.listRecords(DirectoryService.recordType_users):
creds = UsernamePassword(user.shortNames[0], "bogus")
- userResource = provisioningResource.principalForAuthID(creds)
+ userResource = (yield provisioningResource.principalForAuthID(creds))
self.failIf(userResource is None)
self.assertEquals(user, userResource.record)
+ @inlineCallbacks
def test_principalForUID(self):
"""
DirectoryPrincipalProvisioningResource.principalForUID()
"""
- for provisioningResource, recordType, recordResource, record in self._allRecords():
- principal = provisioningResource.principalForUID(record.uid)
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
+ principal = (yield provisioningResource.principalForUID(record.uid))
self.failIf(principal is None)
self.assertEquals(record, principal.record)
+ @inlineCallbacks
def test_principalForRecord(self):
"""
DirectoryPrincipalProvisioningResource.principalForRecord()
"""
- for provisioningResource, recordType, recordResource, record in self._allRecords():
- principal = provisioningResource.principalForRecord(record)
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
+ principal = (yield provisioningResource.principalForRecord(record))
self.failIf(principal is None)
self.assertEquals(record, principal.record)
+ @inlineCallbacks
def test_principalForCalendarUserAddress(self):
"""
DirectoryPrincipalProvisioningResource.principalForCalendarUserAddress()
"""
- for provisioningResource, recordType, recordResource, record in self._allRecords():
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
principalURL = recordResource.principalURL()
if principalURL.endswith("/"):
alternateURL = principalURL[:-1]
@@ -213,7 +217,7 @@
alternateURL = principalURL + "/"
for address in tuple(record.calendarUserAddresses) + (principalURL, alternateURL):
- principal = provisioningResource.principalForCalendarUserAddress(address)
+ principal = (yield provisioningResource.principalForCalendarUserAddress(address))
if record.enabledForCalendaring:
self.failIf(principal is None)
self.assertEquals(record, principal.record)
@@ -221,17 +225,18 @@
self.failIf(principal is not None)
# Explicitly check the disabled record
- self.failIf(provisioningResource.principalForCalendarUserAddress("mailto:nocalendar at example.com") is not None)
- self.failIf(provisioningResource.principalForCalendarUserAddress("urn:uuid:543D28BA-F74F-4D5F-9243-B3E3A61171E5") is not None)
- self.failIf(provisioningResource.principalForCalendarUserAddress("/principals/users/nocalendar/") is not None)
- self.failIf(provisioningResource.principalForCalendarUserAddress("/principals/__uids__/543D28BA-F74F-4D5F-9243-B3E3A61171E5/") is not None)
+ self.failIf((yield provisioningResource.principalForCalendarUserAddress("mailto:nocalendar at example.com")) is not None)
+ self.failIf((yield provisioningResource.principalForCalendarUserAddress("urn:uuid:543D28BA-F74F-4D5F-9243-B3E3A61171E5")) is not None)
+ self.failIf((yield provisioningResource.principalForCalendarUserAddress("/principals/users/nocalendar/")) is not None)
+ self.failIf((yield provisioningResource.principalForCalendarUserAddress("/principals/__uids__/543D28BA-F74F-4D5F-9243-B3E3A61171E5/")) is not None)
+ @inlineCallbacks
def test_enabledForCalendaring(self):
"""
DirectoryPrincipalProvisioningResource.principalForCalendarUserAddress()
"""
- for provisioningResource, recordType, recordResource, record in self._allRecords():
- principal = provisioningResource.principalForRecord(record)
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
+ principal = (yield provisioningResource.principalForRecord(record))
self.failIf(principal is None)
if record.enabledForCalendaring:
self.assertTrue(isinstance(principal, DirectoryCalendarPrincipalResource))
@@ -239,6 +244,7 @@
self.assertTrue(isinstance(principal, DirectoryPrincipalResource))
self.assertFalse(isinstance(principal, DirectoryCalendarPrincipalResource))
+ @inlineCallbacks
def test_enabledAsOrganizer(self):
"""
DirectoryPrincipalProvisioningResource.principalForCalendarUserAddress()
@@ -247,10 +253,10 @@
ok_types = (
DirectoryService.recordType_users,
)
- for provisioningResource, recordType, recordResource, record in self._allRecords():
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
if record.enabledForCalendaring:
- principal = provisioningResource.principalForRecord(record)
+ principal = (yield provisioningResource.principalForRecord(record))
self.failIf(principal is None)
self.assertEqual(principal.enabledAsOrganizer(), recordType in ok_types)
@@ -263,10 +269,10 @@
DirectoryService.recordType_locations,
DirectoryService.recordType_resources,
)
- for provisioningResource, recordType, recordResource, record in self._allRecords():
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
if record.enabledForCalendaring:
- principal = provisioningResource.principalForRecord(record)
+ principal = (yield provisioningResource.principalForRecord(record))
self.failIf(principal is None)
self.assertEqual(principal.enabledAsOrganizer(), recordType in ok_types)
@@ -276,20 +282,22 @@
# DirectoryPrincipalResource
##
+ @inlineCallbacks
def test_cacheNotifier(self):
"""
Each DirectoryPrincipalResource should have a cacheNotifier attribute
that is an instance of XattrCacheChangeNotifier
"""
- for provisioningResource, recordType, recordResource, record in self._allRecords():
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
self.failUnless(isinstance(recordResource.cacheNotifier,
DisabledCacheNotifier))
+ @inlineCallbacks
def test_displayName(self):
"""
DirectoryPrincipalResource.displayName()
"""
- for provisioningResource, recordType, recordResource, record in self._allRecords():
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
self.failUnless(recordResource.displayName())
@inlineCallbacks
@@ -297,24 +305,25 @@
"""
DirectoryPrincipalResource.groupMembers()
"""
- for provisioningResource, recordType, recordResource, record in self._allRecords():
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
members = yield recordResource.groupMembers()
- self.failUnless(set(record.members()).issubset(set(r.record for r in members)))
+ self.failUnless(set((yield record.members())).issubset(set(r.record for r in members)))
@inlineCallbacks
def test_groupMemberships(self):
"""
DirectoryPrincipalResource.groupMemberships()
"""
- for provisioningResource, recordType, recordResource, record in self._allRecords():
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
memberships = yield recordResource.groupMemberships()
- self.failUnless(set(record.groups()).issubset(set(r.record for r in memberships if hasattr(r, "record"))))
+ self.failUnless(set((yield record.groups())).issubset(set(r.record for r in memberships if hasattr(r, "record"))))
+ @inlineCallbacks
def test_principalUID(self):
"""
DirectoryPrincipalResource.principalUID()
"""
- for provisioningResource, recordType, recordResource, record in self._allRecords():
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
self.assertEquals(record.guid, recordResource.principalUID())
@inlineCallbacks
@@ -322,7 +331,7 @@
"""
DirectoryPrincipalResource.calendarUserAddresses()
"""
- for provisioningResource, recordType, recordResource, record in self._allRecords():
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
if record.enabledForCalendaring:
self.failUnless(
(
@@ -331,6 +340,7 @@
).issubset(set((yield recordResource.calendarUserAddresses())))
)
+ @inlineCallbacks
def test_calendarHomeURLs(self):
"""
DirectoryPrincipalResource.calendarHomeURLs(),
@@ -339,13 +349,12 @@
"""
ds = []
# No calendar home provisioner should result in no calendar homes.
- for provisioningResource, recordType, recordResource, record in self._allRecords():
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
if record.enabledForCalendaring:
- d = recordResource.calendarHomeURLs()
- d.addCallback(lambda u: self.assertEqual(len(u), 0))
- ds.append(d)
- ds.append(recordResource.scheduleInboxURL().addCallback(self.failIf))
- ds.append(recordResource.scheduleOutboxURL().addCallback(self.failIf))
+ urls = (yield recordResource.calendarHomeURLs())
+ self.assertEqual(len(urls), 0)
+ self.failIf((yield recordResource.scheduleInboxURL()))
+ self.failIf((yield recordResource.scheduleOutboxURL()))
# Need to create a calendar home provisioner for each service.
calendarRootResources = {}
@@ -358,46 +367,50 @@
rmdir(path)
os.mkdir(path)
- provisioningResource = CalendarHomeProvisioningFile(path, directory, url)
+ provisioningResource = (yield CalendarHomeProvisioningFile.fetch(
+ None, path, directory, url))
calendarRootResources[directory.__class__.__name__] = provisioningResource
# Calendar home provisioners should result in calendar homes.
- for provisioningResource, recordType, recordResource, record in self._allRecords():
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
if record.enabledForCalendaring:
- d = gatherResults([recordResource.calendarHomeURLs(),
- recordResource.scheduleInboxURL(),
- recordResource.scheduleOutboxURL()])
- def _gotURLs(homeURLs, inboxURL, outboxURL):
- calendarRootURL = calendarRootResources[record.service.__class__.__name__].url()
+ homeURLs = tuple((yield recordResource.calendarHomeURLs()))
+ self.failUnless(homeURLs)
- self.failUnless(inboxURL)
- self.failUnless(outboxURL)
+ calendarRootURL = calendarRootResources[record.service.__class__.__name__].url()
- for homeURL in homeURLs:
- self.failUnless(homeURL.startswith(calendarRootURL))
+ inboxURL = (yield recordResource.scheduleInboxURL())
+ outboxURL = (yield recordResource.scheduleOutboxURL())
- if inboxURL and inboxURL.startswith(homeURL):
- self.failUnless(len(inboxURL) > len(homeURL))
- self.failUnless(inboxURL.endswith("/"))
- inboxURL = None
+ self.failUnless(inboxURL)
+ self.failUnless(outboxURL)
- if outboxURL and outboxURL.startswith(homeURL):
- self.failUnless(len(outboxURL) > len(homeURL))
- self.failUnless(outboxURL.endswith("/"))
- outboxURL = None
+ for homeURL in homeURLs:
+ self.failUnless(homeURL.startswith(calendarRootURL))
- self.failIf(inboxURL)
- self.failIf(outboxURL)
- return gatherResults(ds)
+ if inboxURL and inboxURL.startswith(homeURL):
+ self.failUnless(len(inboxURL) > len(homeURL))
+ self.failUnless(inboxURL.endswith("/"))
+ inboxURL = None
+ if outboxURL and outboxURL.startswith(homeURL):
+ self.failUnless(len(outboxURL) > len(homeURL))
+ self.failUnless(outboxURL.endswith("/"))
+ outboxURL = None
+
+ self.failIf(inboxURL)
+ self.failIf(outboxURL)
+
+
+
@inlineCallbacks
def test_defaultAccessControlList_principals(self):
"""
Default access controls for principals.
"""
- for provisioningResource, recordType, recordResource, record in self._allRecords():
- for args in _authReadOnlyPrivileges(self, recordResource, recordResource.principalURL()):
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
+ for args in (yield _authReadOnlyPrivileges(self, recordResource, recordResource.principalURL())):
yield self._checkPrivileges(*args)
@inlineCallbacks
@@ -409,14 +422,14 @@
#print "\n -> %s" % (directory.__class__.__name__,)
provisioningResource = self.principalRootResources[directory.__class__.__name__]
- for args in _authReadOnlyPrivileges(self, provisioningResource, provisioningResource.principalCollectionURL()):
+ for args in (yield _authReadOnlyPrivileges(self, provisioningResource, provisioningResource.principalCollectionURL())):
yield self._checkPrivileges(*args)
children = yield provisioningResource.listChildren()
for recordType in children:
#print " -> %s" % (recordType,)
- typeResource = provisioningResource.getChild(recordType)
+ typeResource = (yield provisioningResource.getChild(recordType))
- for args in _authReadOnlyPrivileges(self, typeResource, typeResource.principalCollectionURL()):
+ for args in (yield _authReadOnlyPrivileges(self, typeResource, typeResource.principalCollectionURL())):
yield self._checkPrivileges(*args)
def test_propertyToField(self):
@@ -455,6 +468,7 @@
(field, converted)
)
+ @inlineCallbacks
def _allRecords(self):
"""
@return: an iterable of tuples
@@ -465,12 +479,14 @@
C{record} is the directory service record
for each record in each directory in C{directoryServices}.
"""
+ results = []
for directory in self.directoryServices:
provisioningResource = self.principalRootResources[directory.__class__.__name__]
for recordType in directory.recordTypes():
for record in directory.listRecords(recordType):
- recordResource = provisioningResource.principalForRecord(record)
- yield provisioningResource, recordType, recordResource, record
+ recordResource = (yield provisioningResource.principalForRecord(record))
+ results.append((provisioningResource, recordType, recordResource, record))
+ returnValue(results)
def _checkPrivileges(self, resource, url, principal, privilege, allowed):
request = SimpleRequest(self.site, "GET", "/")
@@ -497,9 +513,10 @@
d.addCallback(gotResource)
return d
+ at inlineCallbacks
def _authReadOnlyPrivileges(self, resource, url):
items = []
- for provisioningResource, recordType, recordResource, record in self._allRecords():
+ for provisioningResource, recordType, recordResource, record in (yield self._allRecords()):
if recordResource == resource:
items.append(( davxml.HRef().fromString(recordResource.principalURL()), davxml.Read() , True ))
items.append(( davxml.HRef().fromString(recordResource.principalURL()), davxml.Write() , True ))
@@ -509,5 +526,7 @@
items.append(( davxml.Unauthenticated() , davxml.Read() , False ))
items.append(( davxml.Unauthenticated() , davxml.Write() , False ))
+ results = []
for principal, privilege, allowed in items:
- yield resource, url, principal, privilege, allowed
+ results.append((resource, url, principal, privilege, allowed))
+ returnValue(results)
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_proxyprincipalmembers.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_proxyprincipalmembers.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_proxyprincipalmembers.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -52,42 +52,38 @@
provisioningResource = self.principalRootResources[self.directoryService.__class__.__name__]
return provisioningResource.principalForShortName(type, name)
+ @inlineCallbacks
def _groupMembersTest(self, recordType, recordName, subPrincipalName, expectedMembers):
- def gotMembers(members):
- memberNames = set([p.displayName() for p in members])
- self.assertEquals(memberNames, set(expectedMembers))
- principal = self._getPrincipalByShortName(recordType, recordName)
+ principal = (yield self._getPrincipalByShortName(recordType, recordName))
if subPrincipalName is not None:
- principal = principal.getChild(subPrincipalName)
+ principal = (yield principal.getChild(subPrincipalName))
- d = principal.expandedGroupMembers()
- d.addCallback(gotMembers)
- return d
+ members = (yield principal.expandedGroupMembers())
+ memberNames = set([p.displayName() for p in members])
+ self.assertEquals(memberNames, set(expectedMembers))
+ @inlineCallbacks
def _groupMembershipsTest(self, recordType, recordName, subPrincipalName, expectedMemberships):
- def gotMemberships(memberships):
- uids = set([p.principalUID() for p in memberships])
- self.assertEquals(uids, set(expectedMemberships))
- principal = self._getPrincipalByShortName(recordType, recordName)
+ principal = (yield self._getPrincipalByShortName(recordType, recordName))
if subPrincipalName is not None:
- principal = principal.getChild(subPrincipalName)
+ principal = (yield principal.getChild(subPrincipalName))
- d = principal.groupMemberships()
- d.addCallback(gotMemberships)
- return d
+ memberships = (yield principal.groupMemberships())
+ uids = set([p.principalUID() for p in memberships])
+ self.assertEquals(uids, set(expectedMemberships))
@inlineCallbacks
def _addProxy(self, principal, subPrincipalName, proxyPrincipal):
if isinstance(principal, tuple):
- principal = self._getPrincipalByShortName(principal[0], principal[1])
- principal = principal.getChild(subPrincipalName)
+ principal = (yield self._getPrincipalByShortName(principal[0], principal[1]))
+ principal = (yield principal.getChild(subPrincipalName))
members = (yield principal.groupMembers())
if isinstance(proxyPrincipal, tuple):
- proxyPrincipal = self._getPrincipalByShortName(proxyPrincipal[0], proxyPrincipal[1])
+ proxyPrincipal = (yield self._getPrincipalByShortName(proxyPrincipal[0], proxyPrincipal[1]))
members.add(proxyPrincipal)
principal.setGroupMemberSetPrincipals(members)
@@ -95,11 +91,11 @@
@inlineCallbacks
def _removeProxy(self, recordType, recordName, subPrincipalName, proxyRecordType, proxyRecordName):
- principal = self._getPrincipalByShortName(recordType, recordName)
- principal = principal.getChild(subPrincipalName)
+ principal = (yield self._getPrincipalByShortName(recordType, recordName))
+ principal = (yield principal.getChild(subPrincipalName))
members = (yield principal.groupMembers())
- proxyPrincipal = self._getPrincipalByShortName(proxyRecordType, proxyRecordName)
+ proxyPrincipal = (yield self._getPrincipalByShortName(proxyRecordType, proxyRecordName))
for p in members:
if p.principalUID() == proxyPrincipal.principalUID():
members.remove(p)
@@ -107,16 +103,17 @@
principal.setGroupMemberSetPrincipals(members)
+ @inlineCallbacks
def _clearProxy(self, principal, subPrincipalName):
if isinstance(principal, tuple):
- principal = self._getPrincipalByShortName(principal[0], principal[1])
- principal = principal.getChild(subPrincipalName)
+ principal = (yield self._getPrincipalByShortName(principal[0], principal[1]))
+ principal = (yield principal.getChild(subPrincipalName))
principal.setGroupMemberSetPrincipals(set())
@inlineCallbacks
def _proxyForTest(self, recordType, recordName, expectedProxies, read_write):
- principal = self._getPrincipalByShortName(recordType, recordName)
+ principal = (yield self._getPrincipalByShortName(recordType, recordName))
proxies = (yield principal.proxyFor(read_write))
proxies = set([principal.displayName() for principal in proxies])
self.assertEquals(proxies, set(expectedProxies))
@@ -193,53 +190,46 @@
return DeferredList(ds)
+ @inlineCallbacks
def test_groupMembersProxyMissingUser(self):
"""
DirectoryPrincipalResource.expandedGroupMembers()
"""
- proxy = self._getPrincipalByShortName(DirectoryService.recordType_users, "cdaboo")
- proxyGroup = proxy.getChild("calendar-proxy-write")
+ proxy = (yield self._getPrincipalByShortName(DirectoryService.recordType_users, "cdaboo"))
+ proxyGroup = (yield proxy.getChild("calendar-proxy-write"))
- def gotMembers(members):
- members.add("12345")
- return proxyGroup._index().setGroupMembers("%s#calendar-proxy-write" % (proxy.principalUID(),), members)
- def check(_):
- return self._groupMembersTest(
- DirectoryService.recordType_users, "cdaboo", "calendar-proxy-write",
- (),
- )
# Setup the fake entry in the DB
- d = proxyGroup._index().getMembers("%s#calendar-proxy-write" % (proxy.principalUID(),))
- d.addCallback(gotMembers)
- d.addCallback(check)
- return d
+ members = (yield proxyGroup._index().getMembers("%s#calendar-proxy-write" % (proxy.principalUID(),)))
+ members.add("12345")
+ proxyGroup._index().setGroupMembers("%s#calendar-proxy-write" % (proxy.principalUID(),), members)
+ self._groupMembersTest(
+ DirectoryService.recordType_users, "cdaboo", "calendar-proxy-write",
+ (),
+ )
+
+ @inlineCallbacks
def test_groupMembershipsMissingUser(self):
"""
DirectoryPrincipalResource.expandedGroupMembers()
"""
# Setup the fake entry in the DB
fake_uid = "12345"
- proxy = self._getPrincipalByShortName(DirectoryService.recordType_users, "cdaboo")
- proxyGroup = proxy.getChild("calendar-proxy-write")
+ proxy = (yield self._getPrincipalByShortName(DirectoryService.recordType_users, "cdaboo"))
+ proxyGroup = (yield proxy.getChild("calendar-proxy-write"))
- def gotMembers(members):
- members.add("%s#calendar-proxy-write" % (proxy.principalUID(),))
- return proxyGroup._index().setGroupMembers("%s#calendar-proxy-write" % (fake_uid,), members)
- def check(_):
- return self._groupMembershipsTest(
- DirectoryService.recordType_users, "cdaboo", "calendar-proxy-write",
- (),
- )
+ members = (yield proxyGroup._index().getMembers("%s#calendar-proxy-write" % (fake_uid,)))
+ members.add("%s#calendar-proxy-write" % (proxy.principalUID(),))
+ proxyGroup._index().setGroupMembers("%s#calendar-proxy-write" % (fake_uid,), members)
+ self._groupMembershipsTest(
+ DirectoryService.recordType_users, "cdaboo", "calendar-proxy-write",
+ (),
+ )
- d = proxyGroup._index().getMembers("%s#calendar-proxy-write" % (fake_uid,))
- d.addCallback(gotMembers)
- d.addCallback(check)
- return d
-
+ @inlineCallbacks
def test_setGroupMemberSet(self):
class StubMemberDB(object):
def __init__(self):
@@ -252,10 +242,9 @@
return self.members
- user = self._getPrincipalByShortName(self.directoryService.recordType_users,
- "cdaboo")
+ user = (yield self._getPrincipalByShortName(self.directoryService.recordType_users, "cdaboo"))
- proxyGroup = user.getChild("calendar-proxy-write")
+ proxyGroup = (yield user.getChild("calendar-proxy-write"))
memberdb = StubMemberDB()
@@ -275,15 +264,16 @@
"8B4288F6-CC82-491D-8EF9-642EF4F3E7D0"]))
+ @inlineCallbacks
def test_setGroupMemberSetNotifiesPrincipalCaches(self):
class StubCacheNotifier(object):
changedCount = 0
def changed(self):
self.changedCount += 1
- user = self._getPrincipalByShortName(self.directoryService.recordType_users, "cdaboo")
+ user = (yield self._getPrincipalByShortName(self.directoryService.recordType_users, "cdaboo"))
- proxyGroup = user.getChild("calendar-proxy-write")
+ proxyGroup = (yield user.getChild("calendar-proxy-write"))
notifier = StubCacheNotifier()
@@ -367,8 +357,8 @@
# Set up the in-memory (non-null) memcacher:
config.ProcessType = "Single"
- principal = self._getPrincipalByShortName(
- DirectoryService.recordType_users, "wsanchez")
+ principal = (yield self._getPrincipalByShortName(
+ DirectoryService.recordType_users, "wsanchez"))
db = principal._calendar_user_proxy_index()
# Set the clock to the epoch:
@@ -379,13 +369,13 @@
for doMembershipFirst in (True, False):
for proxyType in ("calendar-proxy-read", "calendar-proxy-write"):
- principal = self._getPrincipalByShortName(DirectoryService.recordType_users, "wsanchez")
- proxyGroup = principal.getChild(proxyType)
+ principal = (yield self._getPrincipalByShortName(DirectoryService.recordType_users, "wsanchez"))
+ proxyGroup = (yield principal.getChild(proxyType))
- testPrincipal = self._getPrincipalByShortName(DirectoryService.recordType_users, "cdaboo")
+ testPrincipal = (yield self._getPrincipalByShortName(DirectoryService.recordType_users, "cdaboo"))
- fakePrincipal = self._getPrincipalByShortName(DirectoryService.recordType_users, "dreid")
- fakeProxyGroup = fakePrincipal.getChild(proxyType)
+ fakePrincipal = (yield self._getPrincipalByShortName(DirectoryService.recordType_users, "dreid"))
+ fakeProxyGroup = (yield fakePrincipal.getChild(proxyType))
yield self._addProxy(
principal,
@@ -420,10 +410,10 @@
# Remove the dreid user from the directory service
- delRec = self.directoryService.recordWithShortName(
- DirectoryService.recordType_users, "dreid")
+ delRec = (yield self.directoryService.recordWithShortName(
+ DirectoryService.recordType_users, "dreid"))
for cache in self.directoryService._recordCaches.itervalues():
- cache.removeRecord(delRec)
+ yield cache.removeRecord(delRec)
del self.directoryService._accounts()[
DirectoryService.recordType_users]["dreid"]
@@ -463,7 +453,7 @@
# Restore removed user
parser = XMLAccountsParser(self.directoryService.xmlFile)
self.directoryService._parsedAccounts = parser.items
- self.directoryService.recordWithShortName(
+ yield self.directoryService.recordWithShortName(
DirectoryService.recordType_users, "dreid")
# Trigger the proxy DB clean up, which will actually
@@ -476,10 +466,10 @@
self.assertEquals(result, None)
# Remove the dreid user from the directory service
- delRec = self.directoryService.recordWithShortName(
- DirectoryService.recordType_users, "dreid")
+ delRec = (yield self.directoryService.recordWithShortName(
+ DirectoryService.recordType_users, "dreid"))
for cache in self.directoryService._recordCaches.itervalues():
- cache.removeRecord(delRec)
+ yield cache.removeRecord(delRec)
del self.directoryService._accounts()[
DirectoryService.recordType_users]["dreid"]
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_sudo.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_sudo.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_sudo.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -16,6 +16,7 @@
import os
from twisted.python.filepath import FilePath
+from twisted.internet.defer import inlineCallbacks
import twistedcaldav.directory.test.util
from twistedcaldav.directory.sudo import SudoDirectoryService
@@ -57,19 +58,21 @@
self.assertEqual(self.sudoers[record.shortNames[0]]['password'],
record.password)
+ @inlineCallbacks
def test_recordWithShortName(self):
service = self.service()
- record = service.recordWithShortName(self.recordType, 'alice')
+ record = (yield service.recordWithShortName(self.recordType, 'alice'))
self.assertEquals(record.password, 'alice')
- record = service.recordWithShortName(self.recordType, 'bob')
+ record = (yield service.recordWithShortName(self.recordType, 'bob'))
self.failIf(record)
+ @inlineCallbacks
def test_calendaringDisabled(self):
service = self.service()
- record = service.recordWithShortName(self.recordType, 'alice')
+ record = (yield service.recordWithShortName(self.recordType, 'alice'))
self.failIf(record.enabledForCalendaring,
"sudoers should have enabledForCalendaring=False")
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_xmlfile.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_xmlfile.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_xmlfile.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -99,6 +99,7 @@
def service(self):
return XMLDirectoryService({'xmlFile' : self.xmlFile()}, alwaysStat=True)
+ @inlineCallbacks
def test_changedXML(self):
service = self.service()
@@ -123,7 +124,7 @@
):
# Fault records in
for name in expectedRecords:
- service.recordWithShortName(recordType, name)
+ yield service.recordWithShortName(recordType, name)
self.assertEquals(
set(r.shortNames[0] for r in service.listRecords(recordType)),
@@ -156,16 +157,17 @@
):
# Fault records in
for name in expectedRecords:
- service.recordWithShortName(recordType, name)
+ yield service.recordWithShortName(recordType, name)
self.assertEquals(
set(r.shortNames[0] for r in service.listRecords(recordType)),
set(expectedRecords)
)
resourceInfoDatabase = ResourceInfoDatabase(config.DataRoot)
- self.assertTrue((yield resourceInfoDatabase.getAutoSchedule(service.recordWithShortName(DirectoryService.recordType_locations, "my office").guid)))
+ self.assertTrue((yield resourceInfoDatabase.getAutoSchedule((yield service.recordWithShortName(DirectoryService.recordType_locations, "my office")).guid)))
+ @inlineCallbacks
def test_okDisableCalendar(self):
service = self.service()
@@ -195,7 +197,7 @@
):
# Fault records in
for name in expectedRecords:
- service.recordWithShortName(recordType, name)
+ yield service.recordWithShortName(recordType, name)
self.assertEquals(
set(r.shortNames[0] for r in service.listRecords(recordType)),
@@ -203,8 +205,8 @@
)
# All groups are disabled
- self.assertFalse(service.recordWithShortName(DirectoryService.recordType_groups, "enabled").enabledForCalendaring)
- self.assertFalse(service.recordWithShortName(DirectoryService.recordType_groups, "disabled").enabledForCalendaring)
+ self.assertFalse((yield service.recordWithShortName(DirectoryService.recordType_groups, "enabled")).enabledForCalendaring)
+ self.assertFalse((yield service.recordWithShortName(DirectoryService.recordType_groups, "disabled")).enabledForCalendaring)
@inlineCallbacks
def test_okProxies(self):
@@ -241,7 +243,7 @@
):
# Fault records in
for name in expectedRecords:
- service.recordWithShortName(recordType, name)
+ yield service.recordWithShortName(recordType, name)
self.assertEquals(
set(r.shortNames[0] for r in service.listRecords(recordType)),
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/util.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/util.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/util.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -14,6 +14,7 @@
# limitations under the License.
##
+from twisted.internet.defer import inlineCallbacks
from twisted.trial.unittest import SkipTest
from twisted.cred.credentials import UsernamePassword
from twisted.web2.auth.digest import DigestedCredentials, calcResponse, calcHA1
@@ -65,6 +66,7 @@
self.assertEquals(set(self.service().recordTypes()), self.recordTypes)
+ @inlineCallbacks
def test_recordWithShortName(self):
"""
IDirectoryService.recordWithShortName()
@@ -80,17 +82,18 @@
service = self.service()
for shortName, info in data.iteritems():
- record = service.recordWithShortName(info.get("prefix", "") + recordType, shortName)
+ record = (yield service.recordWithShortName(info.get("prefix", "") + recordType, shortName))
self.failUnless(record, "No record (%s)%s" % (info.get("prefix", "") + recordType, shortName))
self.compare(record, shortName, data[shortName])
for prefix in self.recordTypePrefixes:
try:
- record = service.recordWithShortName(prefix + recordType, "IDunnoWhoThisIsIReallyDont")
+ record = (yield service.recordWithShortName(prefix + recordType, "IDunnoWhoThisIsIReallyDont"))
except UnknownRecordTypeError:
continue
self.assertEquals(record, None)
+ @inlineCallbacks
def test_recordWithUID(self):
service = self.service()
record = None
@@ -98,19 +101,20 @@
for shortName, what in self.allEntries():
guid = what["guid"]
if guid is not None:
- record = service.recordWithUID(guid)
+ record = (yield service.recordWithUID(guid))
self.compare(record, shortName, what)
if record is None:
raise SkipTest("No GUIDs provided to test")
+ @inlineCallbacks
def test_recordWithCalendarUserAddress(self):
service = self.service()
record = None
for shortName, what in self.allEntries():
for address in what["addresses"]:
- record = service.recordWithCalendarUserAddress(address)
+ record = (yield service.recordWithCalendarUserAddress(address))
self.compare(record, shortName, what)
if record is None:
@@ -126,7 +130,7 @@
service = self.service()
for group, info in self.groups.iteritems():
prefix = info.get("prefix", "")
- groupRecord = service.recordWithShortName(prefix + DirectoryService.recordType_groups, group)
+ groupRecord = (yield service.recordWithShortName(prefix + DirectoryService.recordType_groups, group))
result = set((m.recordType, prefix + m.shortNames[0]) for m in groupRecord.members())
expected = set(self.groups[group]["members"])
self.assertEquals(
@@ -150,7 +154,7 @@
service = self.service()
for shortName, info in data.iteritems():
prefix = info.get("prefix", "")
- record = service.recordWithShortName(prefix + recordType, shortName)
+ record = (yield service.recordWithShortName(prefix + recordType, shortName))
result = set(prefix + g.shortNames[0] for g in record.groups())
expected = set(g for g in self.groups if (record.recordType, shortName) in self.groups[g]["members"])
self.assertEquals(
@@ -261,6 +265,7 @@
"""
Tests a directory implementation with basic auth.
"""
+ @inlineCallbacks
def test_verifyCredentials_basic(self):
"""
IDirectoryRecord.verifyCredentials() with basic
@@ -270,8 +275,8 @@
service = self.service()
for user in self.users:
- userRecord = service.recordWithShortName(DirectoryService.recordType_users, user)
- self.failUnless(userRecord.verifyCredentials(UsernamePassword(user, self.users[user]["password"])))
+ userRecord = (yield service.recordWithShortName(DirectoryService.recordType_users, user))
+ self.failUnless((yield userRecord.verifyCredentials(UsernamePassword(user, self.users[user]["password"]))))
# authRequest = {
# username="username",
@@ -290,6 +295,7 @@
"""
Tests a directory implementation with digest auth.
"""
+ @inlineCallbacks
def test_verifyCredentials_digest(self):
"""
IDirectoryRecord.verifyCredentials() with digest
@@ -300,7 +306,7 @@
service = self.service()
for user in self.users:
for good in (True, True, False, False, True):
- userRecord = service.recordWithShortName(DirectoryService.recordType_users, user)
+ userRecord = (yield service.recordWithShortName(DirectoryService.recordType_users, user))
# I'm glad this is so simple...
response = calcResponse(
@@ -342,6 +348,6 @@
)
if good:
- self.failUnless(userRecord.verifyCredentials(credentials))
+ self.failUnless((yield userRecord.verifyCredentials(credentials)))
else:
- self.failIf(userRecord.verifyCredentials(credentials))
+ self.failIf((yield userRecord.verifyCredentials(credentials)))
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/wiki.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/wiki.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/wiki.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -75,10 +75,10 @@
record = self.byShortName[shortName]
self.log_info("Returning existing wiki record with UID %s" %
(record.uid,))
- return record
+ return succeed(record)
record = self._addRecord(shortName)
- return record
+ return succeed(record)
def recordWithUID(self, uid):
@@ -86,14 +86,14 @@
record = self.byUID[uid]
self.log_info("Returning existing wiki record with UID %s" %
(record.uid,))
- return record
+ return succeed(record)
if uid.startswith(self.UIDPrefix):
shortName = uid[len(self.UIDPrefix):]
record = self._addRecord(shortName)
- return record
+ return succeed(record)
else:
- return None
+ return succeed(None)
def _addRecord(self, shortName):
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/xmlfile.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/xmlfile.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/xmlfile.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -28,6 +28,7 @@
from twisted.cred.credentials import UsernamePassword
from twisted.web2.auth.digest import DigestedCredentials
from twisted.python.filepath import FilePath
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
from twistedcaldav.directory.directory import DirectoryService
from twistedcaldav.directory.cachingdirectory import CachingDirectoryService,\
@@ -96,7 +97,10 @@
)
self.recordCacheForType(recordType).addRecord(record,
indexType, indexKey)
+
+ return succeed(None)
+ @inlineCallbacks
def recordsMatchingFields(self, fields, operand="or", recordType=None):
# Default, brute force method search of underlying XML data
@@ -155,15 +159,17 @@
else:
recordTypes = (recordType,)
+ results = []
for recordType in recordTypes:
for xmlPrincipal in self._accounts()[recordType].itervalues():
if xmlPrincipalMatches(xmlPrincipal):
-
# Load/cache record from its GUID
- record = self.recordWithGUID(xmlPrincipal.guid)
+ record = (yield self.recordWithGUID(xmlPrincipal.guid))
if record:
- yield record
+ results.append(record)
+ returnValue(results)
+
def _accounts(self):
currentTime = time()
if self._alwaysStat or currentTime - self._lastCheck > 60:
@@ -199,18 +205,26 @@
self._members = xmlPrincipal.members
self._groups = xmlPrincipal.groups
+ @inlineCallbacks
def members(self):
+ results = []
for recordType, shortName in self._members:
- yield self.service.recordWithShortName(recordType, shortName)
+ record = (yield self.service.recordWithShortName(recordType, shortName))
+ results.append(record)
+ returnValue(results)
+ @inlineCallbacks
def groups(self):
+ results = []
for shortName in self._groups:
- yield self.service.recordWithShortName(DirectoryService.recordType_groups, shortName)
+ record = (yield self.service.recordWithShortName(DirectoryService.recordType_groups, shortName))
+ results.append(record)
+ returnValue(results)
def verifyCredentials(self, credentials):
if isinstance(credentials, UsernamePassword):
- return credentials.password == self.password
+ return succeed(credentials.password == self.password)
if isinstance(credentials, DigestedCredentials):
- return credentials.checkPassword(self.password)
+ return succeed(credentials.checkPassword(self.password))
return super(XMLDirectoryRecord, self).verifyCredentials(credentials)
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/extensions.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/extensions.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -163,6 +163,7 @@
request.authzUser = davxml.Principal(davxml.Unauthenticated())
returnValue((request.authnUser, request.authzUser,))
+ @inlineCallbacks
def principalsForAuthID(self, request, creds):
"""
Return authentication and authorization prinicipal identifiers
@@ -180,17 +181,17 @@
HTTPError(responsecode.FORBIDDEN) if the principal isn't
found.
"""
- authnPrincipal = self.findPrincipalForAuthID(creds)
+ authnPrincipal = (yield self.findPrincipalForAuthID(creds))
if authnPrincipal is None:
log.info("Could not find the principal resource for user id: %s"
% (creds.username,))
raise HTTPError(responsecode.FORBIDDEN)
- d = self.authorizationPrincipal(request, creds.username, authnPrincipal)
- d.addCallback(lambda authzPrincipal: (authnPrincipal, authzPrincipal))
- return d
+ authzPrincipal = (yield self.authorizationPrincipal(request, creds.username, authnPrincipal))
+ returnValue((authnPrincipal, authzPrincipal))
+ @inlineCallbacks
def findPrincipalForAuthID(self, creds):
"""
Return an authentication and authorization principal
@@ -198,20 +199,20 @@
Check for sudo users before regular users.
"""
if type(creds) is str:
- return super(SudoSACLMixin, self).findPrincipalForAuthID(creds)
+ returnValue((yield super(SudoSACLMixin, self).findPrincipalForAuthID(creds)))
for collection in self.principalCollections():
- principal = collection.principalForShortName(
+ principal = (yield collection.principalForShortName(
SudoDirectoryService.recordType_sudoers,
- creds.username)
+ creds.username))
if principal is not None:
- return principal
+ returnValue(principal)
for collection in self.principalCollections():
- principal = collection.principalForAuthID(creds)
+ principal = (yield collection.principalForAuthID(creds))
if principal is not None:
- return principal
- return None
+ returnValue(principal)
+ returnValue(None)
@inlineCallbacks
def authorizationPrincipal(self, request, authID, authnPrincipal):
@@ -238,31 +239,33 @@
# Substitute the authz value for principal look up
authz = authz[0]
+ @inlineCallbacks
def getPrincipalForType(type, name):
for collection in self.principalCollections():
- principal = collection.principalForShortName(type, name)
+ principal = (yield collection.principalForShortName(type, name))
if principal:
- return principal
+ returnValue(principal)
+ @inlineCallbacks
def isSudoUser(authzID):
- if getPrincipalForType(SudoDirectoryService.recordType_sudoers, authzID):
- return True
- return False
+ if (yield getPrincipalForType(SudoDirectoryService.recordType_sudoers, authzID)):
+ returnValue(True)
+ returnValue(False)
if (
hasattr(authnPrincipal, "record") and
authnPrincipal.record.recordType == SudoDirectoryService.recordType_sudoers
):
if authz:
- if isSudoUser(authz):
+ if (yield isSudoUser(authz)):
log.info("Cannot proxy as another proxy: user %r as user %r"
% (authID, authz))
raise HTTPError(responsecode.FORBIDDEN)
else:
- authzPrincipal = getPrincipalForType(DirectoryService.recordType_users, authz)
+ authzPrincipal = (yield getPrincipalForType(DirectoryService.recordType_users, authz))
if not authzPrincipal:
- authzPrincipal = self.findPrincipalForAuthID(authz)
+ authzPrincipal = (yield self.findPrincipalForAuthID(authz))
if authzPrincipal is not None:
log.info("Allow proxy: user %r as %r"
@@ -436,7 +439,7 @@
operand=operand, cuType=cuType))
for record in records:
- resource = principalCollection.principalForRecord(record)
+ resource = (yield principalCollection.principalForRecord(record))
matchingResources.append(resource)
# We've determined this is a matching resource
@@ -1076,7 +1079,7 @@
):
# Permissions here are fixed, and are not subject to
# inheritance rules, etc.
- return succeed(self.defaultAccessControlList())
+ return self.defaultAccessControlList()
class PropertyNotFoundError (HTTPError):
def __init__(self, qname):
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/freebusyurl.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/freebusyurl.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/freebusyurl.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -93,7 +93,7 @@
davxml.Protected(),
),
)
- return davxml.ACL(*aces)
+ return succeed(davxml.ACL(*aces))
def resourceType(self):
return succeed(davxml.ResourceType.freebusyurl)
@@ -199,7 +199,7 @@
# TODO: We should probably verify that the actual time-range is within sensible bounds (e.g. not too far in the past or future and not too long)
# Now lookup the principal details for the targeted user
- principal = self.parent.principalForRecord()
+ principal = (yield self.parent.principalForRecord())
# Pick the first mailto cu address or the first other type
cuaddr = None
@@ -211,7 +211,7 @@
break
# Get inbox details
- inboxURL = yield principal.scheduleInboxURL(request)
+ inboxURL = (yield principal.scheduleInboxURL(request))
if inboxURL is None:
raise HTTPError(StatusResponse(responsecode.INTERNAL_SERVER_ERROR, "No schedule inbox URL for principal: %s" % (principal,)))
try:
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/index.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/index.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/index.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -846,7 +846,7 @@
C{resource.isPseudoCalendarCollection()} returns C{True}.)
"""
# MOR: isCalendarCollection( ) is now deferred. What to do here?
- assert resource.isPseudoCalendarCollection() and not resource.isCalendarCollection(), "non-calendar collection resource %s has no index." % (resource,)
+ # assert resource.isPseudoCalendarCollection() and not resource.isCalendarCollection(), "non-calendar collection resource %s has no index." % (resource,)
super(IndexSchedule, self).__init__(resource)
def reserveUID(self, uid): #@UnusedVariable
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/mail.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/mail.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/mail.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -196,14 +196,15 @@
self.parent = parent
+ @inlineCallbacks
def accessControlList(self, request, inheritance=True,
expanding=False, inherited_aces=None):
if not hasattr(self, "iMIPACL"):
for principalCollection in self.principalCollections():
- principal = principalCollection.principalForShortName("users",
- config.Scheduling.iMIP.Username)
+ principal = (yield principalCollection.principalForShortName("users",
+ config.Scheduling.iMIP.Username))
if principal is not None:
break
else:
@@ -222,7 +223,7 @@
),
)
- return succeed(self.iMIPACL)
+ returnValue(self.iMIPACL)
def resourceType(self):
return succeed(davxml.ResourceType.ischeduleinbox)
@@ -280,13 +281,15 @@
)
if config.Scheduling.CalDAV.OldDraftCompatibility:
privs += (davxml.Privilege(caldavxml.Schedule()),)
- return davxml.ACL(
- # DAV:Read, CalDAV:schedule-deliver for all principals (includes anonymous)
- davxml.ACE(
- davxml.Principal(davxml.All()),
- davxml.Grant(*privs),
- davxml.Protected(),
- ),
+ return succeed(
+ davxml.ACL(
+ # DAV:Read, CalDAV:schedule-deliver for all principals (includes anonymous)
+ davxml.ACE(
+ davxml.Principal(davxml.All()),
+ davxml.Grant(*privs),
+ davxml.Protected(),
+ ),
+ )
)
def supportedPrivileges(self, request):
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_common.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_common.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_common.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -253,9 +253,9 @@
access = None
if calendar:
- propvalue = yield property.elementFromCalendarWithAccessRestrictions(calendar, access, timezone)
+ propvalue = (yield property.elementFromCalendarWithAccessRestrictions(calendar, access, timezone))
else:
- propvalue = yield property.elementFromResourceWithAccessRestrictions(resource, access, timezone)
+ propvalue = (yield property.elementFromResourceWithAccessRestrictions(resource, access, timezone))
if propvalue is None:
raise ValueError("Invalid CalDAV:calendar-data for request: %r" % (property,))
properties_by_status[responsecode.OK].append(propvalue)
@@ -318,7 +318,7 @@
returnValue(matchtotal)
# May need organizer principal
- organizer_principal = calresource.principalForCalendarUserAddress(organizer) if organizer else None
+ organizer_principal = (yield calresource.principalForCalendarUserAddress(organizer)) if organizer else None
organizer_uid = organizer_principal.principalUID() if organizer_principal else ""
#
@@ -352,9 +352,9 @@
filteredaces = (yield calresource.inheritedACEsforChildren(request))
try:
- resources = yield calresource.index().indexedSearch(filter, fbtype=True)
+ resources = (yield calresource.index().indexedSearch(filter, fbtype=True))
except IndexedSearchException:
- resources = yield calresource.index().bruteForceSearch()
+ resources = (yield calresource.index().bruteForceSearch())
# We care about separate instances for VEVENTs only
aggregated_resources = {}
@@ -387,7 +387,7 @@
if excludeuid:
# See if we have a UID match
if (excludeuid == uid):
- test_principal = calresource.principalForCalendarUserAddress(test_organizer) if test_organizer else None
+ test_principal = (yield calresource.principalForCalendarUserAddress(test_organizer)) if test_organizer else None
test_uid = test_principal.principalUID() if test_principal else ""
# Check that ORGANIZER's match (security requirement)
@@ -417,7 +417,7 @@
fbinfo[fbtype_index_mapper.get(fbtype, 0)].append(clipped)
else:
- calendar = yield calresource.iCalendar(name)
+ calendar = (yield calresource.iCalendar(name))
# The calendar may come back as None if the resource is being changed, or was deleted
# between our initial index query and getting here. For now we will ignore this error, but in
@@ -431,7 +431,7 @@
# See if we have a UID match
if (excludeuid == uid):
test_organizer = calendar.getOrganizer()
- test_principal = calresource.principalForCalendarUserAddress(test_organizer) if test_organizer else None
+ test_principal = (yield calresource.principalForCalendarUserAddress(test_organizer)) if test_organizer else None
test_uid = test_principal.principalUID() if test_principal else ""
# Check that ORGANIZER's match (security requirement)
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_multiget.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_multiget.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_multiget.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -138,7 +138,7 @@
for href in resources:
resource_uri = str(href)
name = unquote(resource_uri[resource_uri.rfind("/") + 1:])
- if not self._isChildURI(request, resource_uri) or self.getChild(name) is None:
+ if not self._isChildURI(request, resource_uri) or (yield self.getChild(name)) is None:
responses.append(davxml.StatusResponse(href, davxml.Status.fromResponseCode(responsecode.NOT_FOUND)))
else:
valid_names.append(name)
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/resource.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/resource.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -262,7 +262,7 @@
fbset = (yield principal.calendarFreeBusyURIs(request))
url = (yield self.canonicalURL(request))
opaque = url in fbset
- (yield self.writeDeadProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Opaque()) if opaque else caldavxml.Transparent()))
+ yield self.writeDeadProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Opaque() if opaque else caldavxml.Transparent()))
result = (yield super(CalDAVResource, self).readProperty(property, request))
returnValue(result)
@@ -671,6 +671,7 @@
"""
return self.iCalendar(name).addCallback(caldavxml.CalendarData.fromCalendar)
+ # Deferred
def iCalendarAddressDoNormalization(self, ical):
"""
Normalize calendar user addresses in the supplied iCalendar object into their
@@ -680,24 +681,26 @@
@type ical: L{Component}
"""
+ @inlineCallbacks
def lookupFunction(cuaddr):
- principal = self.principalForCalendarUserAddress(cuaddr)
+ principal = (yield self.principalForCalendarUserAddress(cuaddr))
if principal is None:
- return (None, None, None)
+ returnValue((None, None, None))
else:
- return (principal.record.fullName.decode("utf-8"),
+ returnValue((principal.record.fullName.decode("utf-8"),
principal.record.guid,
- principal.record.calendarUserAddresses)
+ principal.record.calendarUserAddresses))
- ical.normalizeCalendarUserAddresses(lookupFunction)
+ return ical.normalizeCalendarUserAddresses(lookupFunction)
+ @inlineCallbacks
def principalForCalendarUserAddress(self, address):
for principalCollection in self.principalCollections():
- principal = principalCollection.principalForCalendarUserAddress(address)
+ principal = (yield principalCollection.principalForCalendarUserAddress(address))
if principal is not None:
- return principal
- return None
+ returnValue(principal)
+ returnValue(None)
def supportedReports(self):
result = super(CalDAVResource, self).supportedReports()
@@ -794,7 +797,7 @@
return succeed(False)
def principalForCalendarUserAddress(self, address):
- return None
+ return succeed(None)
def supportedReports(self):
"""
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/schedule.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/schedule.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -98,12 +98,14 @@
if config.Scheduling.CalDAV.OldDraftCompatibility:
privs += (davxml.Privilege(caldavxml.Schedule()),)
- return davxml.ACL(
- # CalDAV:schedule-deliver for any authenticated user
- davxml.ACE(
- davxml.Principal(davxml.Authenticated()),
- davxml.Grant(*privs),
- ),
+ return succeed(
+ davxml.ACL(
+ # CalDAV:schedule-deliver for any authenticated user
+ davxml.ACE(
+ davxml.Principal(davxml.Authenticated()),
+ davxml.Grant(*privs),
+ ),
+ )
)
@inlineCallbacks
@@ -221,7 +223,7 @@
defaultCalendarURL = (yield joinURL(calendarHomeURL, "calendar"))
defaultCalendar = (yield request.locateResource(defaultCalendarURL))
if defaultCalendar is None or not defaultCalendar.exists():
- self.parent.provisionDefaultCalendars()
+ yield self.parent.provisionDefaultCalendars()
else:
yield self.writeDeadProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(defaultCalendarURL)))
returnValue(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(defaultCalendarURL)))
@@ -233,9 +235,10 @@
Extends L{DAVResource} to provide CalDAV functionality.
"""
+ @inlineCallbacks
def defaultAccessControlList(self):
if config.EnableProxyPrincipals:
- myPrincipal = self.parent.principalForRecord()
+ myPrincipal = (yield self.parent.principalForRecord())
privs = (
davxml.Privilege(caldavxml.ScheduleSend()),
@@ -243,16 +246,16 @@
if config.Scheduling.CalDAV.OldDraftCompatibility:
privs += (davxml.Privilege(caldavxml.Schedule()),)
- return davxml.ACL(
+ returnValue(davxml.ACL(
# CalDAV:schedule for associated write proxies
davxml.ACE(
davxml.Principal(davxml.HRef(joinURL(myPrincipal.principalURL(), "calendar-proxy-write"))),
davxml.Grant(*privs),
davxml.Protected(),
),
- )
+ ))
else:
- return super(ScheduleOutboxResource, self).defaultAccessControlList()
+ returnValue((yield super(ScheduleOutboxResource, self).defaultAccessControlList()))
def resourceType(self):
return succeed(davxml.ResourceType.scheduleOutbox)
@@ -302,13 +305,15 @@
if config.Scheduling.CalDAV.OldDraftCompatibility:
privs += (davxml.Privilege(caldavxml.Schedule()),)
- return davxml.ACL(
- # DAV:Read, CalDAV:schedule-deliver for all principals (includes anonymous)
- davxml.ACE(
- davxml.Principal(davxml.All()),
- davxml.Grant(*privs),
- davxml.Protected(),
- ),
+ return succeed(
+ davxml.ACL(
+ # DAV:Read, CalDAV:schedule-deliver for all principals (includes anonymous)
+ davxml.ACE(
+ davxml.Principal(davxml.All()),
+ davxml.Grant(*privs),
+ davxml.Protected(),
+ ),
+ )
)
def resourceType(self):
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/implicit.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/implicit.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/implicit.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -192,7 +192,7 @@
except ValueError:
# We have different ORGANIZERs in the same iCalendar object - this is an error
returnValue(False)
- organizerPrincipal = resource.principalForCalendarUserAddress(organizer) if organizer else None
+ organizerPrincipal = (yield resource.principalForCalendarUserAddress(organizer)) if organizer else None
yield resource.writeDeadProperty(TwistedSchedulingObjectResource("true" if organizerPrincipal != None else "false"))
log.debug("Implicit - checked scheduling object resource state for UID: '%s', result: %s" % (
calendar.resourceUID(),
@@ -274,7 +274,7 @@
# Get some useful information from the calendar
yield self.extractCalendarData()
- self.organizerPrincipal = self.resource.principalForCalendarUserAddress(self.organizer)
+ self.organizerPrincipal = (yield self.resource.principalForCalendarUserAddress(self.organizer))
self.organizerAddress = (yield addressmapping.mapper.getCalendarUser(self.organizer, self.organizerPrincipal))
# Originator is the organizer in this case
@@ -418,7 +418,7 @@
returnValue(False)
# Organizer must map to a valid principal
- self.organizerPrincipal = self.resource.principalForCalendarUserAddress(self.organizer)
+ self.organizerPrincipal = (yield self.resource.principalForCalendarUserAddress(self.organizer))
self.organizerAddress = (yield addressmapping.mapper.getCalendarUser(self.organizer, self.organizerPrincipal))
if not self.organizerPrincipal:
returnValue(False)
@@ -429,21 +429,22 @@
returnValue(True)
+ @inlineCallbacks
def isAttendeeScheduling(self):
# First must have organizer property
if not self.organizer:
- return False
+ returnValue(False)
# Check to see whether any attendee is the owner
for attendee in self.attendees:
- attendeePrincipal = self.resource.principalForCalendarUserAddress(attendee)
+ attendeePrincipal = (yield self.resource.principalForCalendarUserAddress(attendee))
if attendeePrincipal and attendeePrincipal.principalURL() == str(self.calendar_owner):
self.attendee = attendee
self.attendeePrincipal = attendeePrincipal
- return True
+ returnValue(True)
- return False
+ returnValue(False)
@inlineCallbacks
def doAccessControl(self, principal, is_organizer):
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/scheduler.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/scheduler.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/scheduler.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -436,20 +436,21 @@
log.err("Unauthenticated originators not allowed: %s" % (self.originator,))
raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
+ @inlineCallbacks
def checkOriginator(self):
"""
Check the validity of the Originator header. Extract the corresponding principal.
"""
# Verify that Originator is a valid calendar user
- originatorPrincipal = self.resource.principalForCalendarUserAddress(self.originator)
+ originatorPrincipal = (yield self.resource.principalForCalendarUserAddress(self.originator))
if originatorPrincipal is None:
# Local requests MUST have a principal.
log.err("Could not find principal for originator: %s" % (self.originator,))
raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
else:
# Must have a valid Inbox.
- inboxURL = originatorPrincipal.scheduleInboxURL()
+ inboxURL = (yield originatorPrincipal.scheduleInboxURL())
if inboxURL is None:
log.err("Could not find inbox for originator: %s" % (self.originator,))
raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
@@ -474,7 +475,7 @@
results = []
for recipient in self.recipients:
# Get the principal resource for this recipient
- principal = self.resource.principalForCalendarUserAddress(recipient)
+ principal = (yield self.resource.principalForCalendarUserAddress(recipient))
# If no principal we may have a remote recipient but we should check whether
# the address is one that ought to be on our server and treat that as a missing
@@ -487,7 +488,7 @@
else:
# Map recipient to their inbox
inbox = None
- inboxURL = yield principal.scheduleInboxURL()
+ inboxURL = (yield principal.scheduleInboxURL())
if inboxURL:
inbox = (yield self.request.locateResource(inboxURL))
@@ -508,7 +509,7 @@
# Verify that the ORGANIZER's cu address maps to a valid user
organizer = self.calendar.getOrganizer()
if organizer:
- organizerPrincipal = yield self.resource.principalForCalendarUserAddress(organizer)
+ organizerPrincipal = (yield self.resource.principalForCalendarUserAddress(organizer))
if organizerPrincipal:
outboxURL = organizerPrincipal.scheduleOutboxURL()
if outboxURL:
@@ -547,6 +548,7 @@
if self.doingPOST:
return self.organizer.principal.scheduleOutboxURL().addCallback(_checkoutboxurl)
+ @inlineCallbacks
def checkAttendeeAsOriginator(self):
"""
Check the validity of the ATTENDEE value as this is the originator of the iTIP message.
@@ -559,22 +561,20 @@
# Must have only one
if len(attendees) != 1:
log.err("Wrong number of ATTENDEEs in calendar data: %s" % (self.calendar,))
- return fail(HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed"))))
+ raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
attendee = attendees[0]
# Attendee's Outbox MUST be the request URI
- attendeePrincipal = self.resource.principalForCalendarUserAddress(attendee)
+ attendeePrincipal = (yield self.resource.principalForCalendarUserAddress(attendee))
if attendeePrincipal:
- d = attendeePrincipal.scheduleOutboxURL()
- def _gotOutboxURL(outboxURL):
- if self.doingPOST and outboxURL != self.request.uri:
- log.err("ATTENDEE in calendar data does not match owner of Outbox: %s" % (self.calendar,))
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
+ outboxURL = (yield attendeePrincipal.scheduleOutboxURL())
+ if self.doingPOST and outboxURL != self.request.uri:
+ log.err("ATTENDEE in calendar data does not match owner of Outbox: %s" % (self.calendar,))
+ raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
- return d.addCallback(_gotOutboxURL)
else:
log.err("Unknown ATTENDEE in calendar data: %s" % (self.calendar,))
- return fail(HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed"))))
+ raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
def securityChecks(self):
@@ -635,7 +635,7 @@
"""
# For remote requests we do not allow the originator to be a local user or one within our domain.
- originatorPrincipal = self.resource.principalForCalendarUserAddress(self.originator)
+ originatorPrincipal = (yield self.resource.principalForCalendarUserAddress(self.originator))
localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(self.originator))
if originatorPrincipal or localUser:
log.err("Cannot use originator that is on this server: %s" % (self.originator,))
@@ -696,7 +696,7 @@
results = []
for recipient in self.recipients:
# Get the principal resource for this recipient
- principal = self.resource.principalForCalendarUserAddress(recipient)
+ principal = (yield self.resource.principalForCalendarUserAddress(recipient))
# If no principal we may have a remote recipient but we should check whether
# the address is one that ought to be on our server and treat that as a missing
@@ -711,7 +711,7 @@
else:
# Map recipient to their inbox
inbox = None
- inboxURL = yield principal.scheduleInboxURL()
+ inboxURL = (yield principal.scheduleInboxURL())
if inboxURL:
inbox = (yield self.request.locateResource(inboxURL))
@@ -738,7 +738,7 @@
# Verify that the ORGANIZER's cu address does not map to a valid user
organizer = self.calendar.getOrganizer()
if organizer:
- organizerPrincipal = self.resource.principalForCalendarUserAddress(organizer)
+ organizerPrincipal = (yield self.resource.principalForCalendarUserAddress(organizer))
if organizerPrincipal:
log.err("Invalid ORGANIZER in calendar data: %s" % (self.calendar,))
raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed")))
@@ -770,7 +770,7 @@
attendee = attendees[0]
# Attendee cannot be local.
- attendeePrincipal = self.resource.principalForCalendarUserAddress(attendee)
+ attendeePrincipal = (yield self.resource.principalForCalendarUserAddress(attendee))
if attendeePrincipal:
log.err("Invalid ATTENDEE in calendar data: %s" % (self.calendar,))
raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
@@ -865,7 +865,7 @@
"""
# For remote requests we do not allow the originator to be a local user or one within our domain.
- originatorPrincipal = self.resource.principalForCalendarUserAddress(self.originator)
+ originatorPrincipal = (yield self.resource.principalForCalendarUserAddress(self.originator))
localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(self.originator))
if originatorPrincipal or localUser:
log.err("Cannot use originator that is on this server: %s" % (self.originator,))
@@ -883,7 +883,7 @@
results = []
for recipient in self.recipients:
# Get the principal resource for this recipient
- principal = self.resource.principalForCalendarUserAddress(recipient)
+ principal = (yield self.resource.principalForCalendarUserAddress(recipient))
# If no principal we may have a remote recipient but we should check whether
# the address is one that ought to be on our server and treat that as a missing
@@ -898,7 +898,7 @@
else:
# Map recipient to their inbox
inbox = None
- inboxURL = yield principal.scheduleInboxURL()
+ inboxURL = (yield principal.scheduleInboxURL())
if inboxURL:
inbox = (yield self.request.locateResource(inboxURL))
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/static.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/static.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -97,7 +97,7 @@
return succeed(cls(path, *args, **kwargs))
def __repr__(self):
- # MOR: I don't think we can defer __repr__ even though isCalendarCollection( ) now is
+ # MOR: I don't think we can defer __repr__, can we? Problem is, isCalendarCollection( ) now is deferred
if False and self.isCalendarCollection():
return "<%s (calendar collection): %s>" % (self.__class__.__name__, self.fp.path)
else:
@@ -555,11 +555,10 @@
class AutoProvisioningFileMixIn (AutoProvisioningResourceMixIn):
+ @inlineCallbacks
def provision(self):
- # MOR: Double check this:
- d = self.provisionFile()
- d.addCallback(super(AutoProvisioningFileMixIn, self).provision)
- return d
+ yield self.provisionFile()
+ returnValue((yield super(AutoProvisioningFileMixIn, self).provision()))
@inlineCallbacks
def provisionFile(self, request=None):
@@ -644,7 +643,7 @@
@inlineCallbacks
def provisionChild(self, name):
- record = self.directory.recordWithUID(name)
+ record = (yield self.directory.recordWithUID(name))
if record is None:
log.msg("No directory record with GUID %r" % (name,))
@@ -668,7 +667,7 @@
# Pre 2.0: All in one directory
self.fp.child(name),
# Pre 1.2: In types hierarchy instead of the GUID hierarchy
- (yield self.parent.getChild(record.recordType).fp.child(record.shortNames[0])),
+ (yield (yield self.parent.getChild(record.recordType)).fp.child(record.shortNames[0])),
):
if oldPath.exists():
# The child exists at an old location. Move to new location.
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_mkcalendar.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_mkcalendar.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_mkcalendar.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -92,7 +92,7 @@
(davxml.DisplayName.qname(), "Lisa's Events"),
(caldavxml.CalendarDescription.qname(), "Calendar restricted to events."),
):
- stored = yield resource.readProperty(qname, None)
+ stored = (yield resource.readProperty(qname, None))
stored = str(stored)
if stored != value:
self.fail("MKCALENDAR failed to set property %s: %s != %s"
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/timezoneservice.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/timezoneservice.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/timezoneservice.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -62,15 +62,17 @@
self.cache = {}
def defaultAccessControlList(self):
- return davxml.ACL(
- # DAV:Read for all principals (includes anonymous)
- davxml.ACE(
- davxml.Principal(davxml.All()),
- davxml.Grant(
- davxml.Privilege(davxml.Read()),
+ return succeed(
+ davxml.ACL(
+ # DAV:Read for all principals (includes anonymous)
+ davxml.ACE(
+ davxml.Principal(davxml.All()),
+ davxml.Grant(
+ davxml.Privilege(davxml.Read()),
+ ),
+ davxml.Protected(),
),
- davxml.Protected(),
- ),
+ )
)
def resourceType(self):
Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/upgrade.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/upgrade.py 2009-09-02 17:57:11 UTC (rev 4523)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/upgrade.py 2009-09-03 17:58:15 UTC (rev 4524)
@@ -86,24 +86,25 @@
def normalizeCUAddrs(data, directory):
cal = Component.fromString(data)
+ @inlineCallbacks
def lookupFunction(cuaddr):
try:
- principal = directory.principalForCalendarUserAddress(cuaddr)
+ principal = (yield directory.principalForCalendarUserAddress(cuaddr))
except Exception, e:
log.debug("Lookup of %s failed: %s" % (cuaddr, e))
principal = None
if principal is None:
- return (None, None, None)
+ returnValue((None, None, None))
else:
- return (principal.record.fullName.decode("utf-8"),
+ returnValue((principal.record.fullName.decode("utf-8"),
principal.record.guid,
- principal.record.calendarUserAddresses)
+ principal.record.calendarUserAddresses))
- cal.normalizeCalendarUserAddresses(lookupFunction)
+ yield cal.normalizeCalendarUserAddresses(lookupFunction)
newData = str(cal)
- return newData, not newData == data
+ returnValue((newData, not newData == data))
def upgradeCalendarCollection(calPath, directory):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090903/b2bebadd/attachment-0001.html>
More information about the calendarserver-changes
mailing list