[CalendarServer-changes] [3573] CalendarServer/trunk/twistedcaldav/directory
source_changes at macosforge.org
source_changes at macosforge.org
Wed Jan 7 10:15:57 PST 2009
Revision: 3573
http://trac.macosforge.org/projects/calendarserver/changeset/3573
Author: cdaboo at apple.com
Date: 2009-01-07 10:15:56 -0800 (Wed, 07 Jan 2009)
Log Message:
-----------
Delete entries from the delegate DB if users are no longer in the directory.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/directory/calendaruserproxy.py
CalendarServer/trunk/twistedcaldav/directory/principal.py
CalendarServer/trunk/twistedcaldav/directory/test/test_proxyprincipaldb.py
CalendarServer/trunk/twistedcaldav/directory/test/test_proxyprincipalmembers.py
Modified: CalendarServer/trunk/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/calendaruserproxy.py 2009-01-06 20:23:10 UTC (rev 3572)
+++ CalendarServer/trunk/twistedcaldav/directory/calendaruserproxy.py 2009-01-07 18:15:56 UTC (rev 3573)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2006-2008 Apple Inc. All rights reserved.
+# 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.
@@ -70,7 +70,7 @@
return davxml.ACL(*aces)
def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
- # Permissions here are fixed, and are not subject to inherritance rules, etc.
+ # Permissions here are fixed, and are not subject to inheritance rules, etc.
return succeed(self.defaultAccessControlList())
class CalendarUserProxyPrincipalResource (CalDAVComplianceMixIn, PermissionsMixIn, DAVPrincipalResource, DAVFile):
@@ -196,12 +196,15 @@
principals.append(principal)
yield principal.cacheNotifier.changed()
+ yield self.setGroupMemberSetPrincipals(principals)
+ yield self.parent.cacheNotifier.changed()
+ returnValue(True)
+
+ @inlineCallbacks
+ def setGroupMemberSetPrincipals(self, principals):
# Map the principals to UIDs.
uids = [p.principalUID() for p in principals]
-
yield self._index().setGroupMembers(self.uid, uids)
- yield self.parent.cacheNotifier.changed()
- returnValue(True)
##
# HTTP
@@ -314,7 +317,20 @@
if self.hasEditableMembership():
# Get member UIDs from database and map to principal resources
members = yield self._index().getMembers(self.uid)
- returnValue([p for p in [self.pcollection.principalForUID(uid) for uid in members] if p])
+ found = []
+ missing = []
+ for uid in members:
+ p = self.pcollection.principalForUID(uid)
+ if p:
+ found.append(p)
+ else:
+ missing.append(uid)
+
+ # Clean-up ones that are missing
+ for uid in missing:
+ yield self._index().removePrincipal(uid)
+
+ returnValue(found)
else:
# Fixed proxies
if self.proxyType == "calendar-proxy-write":
@@ -357,10 +373,10 @@
class ProxyDBMemcacher(Memcacher):
def setMembers(self, guid, members):
- return self.set("members:%s" % (guid,), str(",".join(members)))
+ return self.set("members:%s" % (str(guid),), str(",".join(members)))
def setMemberships(self, guid, memberships):
- return self.set("memberships:%s" % (guid,), str(",".join(memberships)))
+ return self.set("memberships:%s" % (str(guid),), str(",".join(memberships)))
def getMembers(self, guid):
def _value(value):
@@ -370,7 +386,7 @@
return None
else:
return set()
- d = self.get("members:%s" % (guid,))
+ d = self.get("members:%s" % (str(guid),))
d.addCallback(_value)
return d
@@ -382,15 +398,15 @@
return None
else:
return set()
- d = self.get("memberships:%s" % (guid,))
+ d = self.get("memberships:%s" % (str(guid),))
d.addCallback(_value)
return d
def deleteMember(self, guid):
- return self.delete("members:%s" % (guid,))
+ return self.delete("members:%s" % (str(guid),))
def deleteMembership(self, guid):
- return self.delete("memberships:%s" % (guid,))
+ return self.delete("memberships:%s" % (str(guid),))
def __init__(self, path):
path = os.path.join(path, CalendarUserProxyDatabase.dbFilename)
@@ -435,17 +451,46 @@
@param principalUID: the UID of the group principal to remove.
"""
+ # Need to get the members before we do the delete
+ members = yield self.getMembers(principalUID)
+
self._delete_from_db(principalUID)
self._db_commit()
# Update cache
- members = yield self.getMembers(principalUID)
if members:
for member in members:
yield self._memcacher.deleteMembership(member)
yield self._memcacher.deleteMember(principalUID)
@inlineCallbacks
+ def removePrincipal(self, principalUID):
+ """
+ Remove a group membership record.
+
+ @param principalUID: the UID of the principal to remove.
+ """
+
+ for suffix in ("calendar-proxy-read", "calendar-proxy-write",):
+ groupUID = "%s#%s" % (principalUID, suffix,)
+ self._delete_from_db(groupUID)
+
+ # Update cache
+ members = yield self.getMembers(groupUID)
+ if members:
+ for member in members:
+ yield self._memcacher.deleteMembership(member)
+ yield self._memcacher.deleteMember(groupUID)
+
+ memberships = (yield self.getMemberships(principalUID))
+ for groupUID in memberships:
+ yield self._memcacher.deleteMember(groupUID)
+
+ self._delete_from_db_member(principalUID)
+ yield self._memcacher.deleteMembership(principalUID)
+ self._db_commit()
+
+ @inlineCallbacks
def getMembers(self, principalUID):
"""
Return the list of group member UIDs for the specified principal.
@@ -454,10 +499,7 @@
"""
def _members():
- members = set()
- for row in self._db_execute("select MEMBER from GROUPS where GROUPNAME = :1", principalUID):
- members.add(row[0])
- return members
+ return set([row[0] for row in self._db_execute("select MEMBER from GROUPS where GROUPNAME = :1", principalUID)])
# Pull from cache
result = yield self._memcacher.getMembers(principalUID)
@@ -475,10 +517,7 @@
"""
def _members():
- members = set()
- for row in self._db_execute("select GROUPNAME from GROUPS where MEMBER = :1", principalUID):
- members.add(row[0])
- return members
+ return set([row[0] for row in self._db_execute("select GROUPNAME from GROUPS where MEMBER = :1", principalUID)])
# Pull from cache
result = yield self._memcacher.getMemberships(principalUID)
@@ -510,6 +549,14 @@
"""
self._db_execute("delete from GROUPS where GROUPNAME = :1", principalUID)
+ def _delete_from_db_member(self, principalUID):
+ """
+ Deletes the specified member entry from the database.
+
+ @param principalUID: the UID of the member principal to remove.
+ """
+ self._db_execute("delete from GROUPS where MEMBER = :1", principalUID)
+
def _db_version(self):
"""
@return: the schema version assigned to this index.
Modified: CalendarServer/trunk/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/principal.py 2009-01-06 20:23:10 UTC (rev 3572)
+++ CalendarServer/trunk/twistedcaldav/directory/principal.py 2009-01-07 18:15:56 UTC (rev 3573)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2006-2007 Apple Inc. All rights reserved.
+# 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.
@@ -645,6 +645,8 @@
subprincipal = self.parent.principalForUID(uid)
if subprincipal:
proxies.append(subprincipal)
+ else:
+ yield self._calendar_user_proxy_index().removeGroup(uid)
groups.update(proxies)
@@ -677,8 +679,11 @@
memberships = (yield self._calendar_user_proxy_index().getMemberships(self.principalUID()))
for uid in memberships:
subprincipal = self.parent.principalForUID(uid)
- if subprincipal and subprincipal.isProxyType(read_write):
- proxies.append(subprincipal.parent)
+ if subprincipal:
+ if subprincipal.isProxyType(read_write):
+ proxies.append(subprincipal.parent)
+ else:
+ yield self._calendar_user_proxy_index().removeGroup(uid)
proxyFors.update(proxies)
Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_proxyprincipaldb.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_proxyprincipaldb.py 2009-01-06 20:23:10 UTC (rev 3572)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_proxyprincipaldb.py 2009-01-07 18:15:56 UTC (rev 3573)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
+# Copyright (c) 2005-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.
@@ -270,6 +270,82 @@
self.assertEqual(membershipsD, set())
@inlineCallbacks
+ def test_cachingDBRemoveSpecial(self):
+
+ for processType in ("Single", "Combined",):
+ config.ProcessType = processType
+
+ # Get the DB
+ db_path = self.mktemp()
+ os.mkdir(db_path)
+ db = CalendarUserProxyDatabase(db_path)
+
+ # Do one insert and check the result
+ yield db.setGroupMembers("A", ("B", "C", "D",))
+ yield db.setGroupMembers("X", ("B", "C",))
+
+ membershipsB = yield db.getMemberships("B")
+ membershipsC = yield db.getMemberships("C")
+ membershipsD = yield db.getMemberships("D")
+
+ # Remove and check the result
+ yield db.removeGroup("A")
+
+ membersA = yield db.getMembers("A")
+ membersX = yield db.getMembers("X")
+ membershipsB = yield db.getMemberships("B")
+ membershipsC = yield db.getMemberships("C")
+ membershipsD = yield db.getMemberships("D")
+
+ self.assertEqual(membersA, set())
+ self.assertEqual(membersX, set(("B", "C",)))
+ self.assertEqual(membershipsB, set("X",))
+ self.assertEqual(membershipsC, set("X",))
+ self.assertEqual(membershipsD, set())
+
+ @inlineCallbacks
+ def test_cachingDBRemovePrincipal(self):
+
+ for processType in ("Single", "Combined",):
+ config.ProcessType = processType
+
+ # Get the DB
+ db_path = self.mktemp()
+ os.mkdir(db_path)
+ db = CalendarUserProxyDatabase(db_path)
+
+ # Do one insert and check the result
+ yield db.setGroupMembers("A", ("B", "C", "D",))
+ yield db.setGroupMembers("X", ("B", "C",))
+
+ membersA = yield db.getMembers("A")
+ membersX = yield db.getMembers("X")
+ membershipsB = yield db.getMemberships("B")
+ membershipsC = yield db.getMemberships("C")
+ membershipsD = yield db.getMemberships("D")
+
+ self.assertEqual(membersA, set(("B", "C", "D",)))
+ self.assertEqual(membersX, set(("B", "C",)))
+ self.assertEqual(membershipsB, set(("A", "X",)))
+ self.assertEqual(membershipsC, set(("A", "X",)))
+ self.assertEqual(membershipsD, set(("A",)))
+
+ # Remove and check the result
+ yield db.removePrincipal("B")
+
+ membersA = yield db.getMembers("A")
+ membersX = yield db.getMembers("X")
+ membershipsB = yield db.getMemberships("B")
+ membershipsC = yield db.getMemberships("C")
+ membershipsD = yield db.getMemberships("D")
+
+ self.assertEqual(membersA, set(("C", "D",)))
+ self.assertEqual(membersX, set(("C",)))
+ self.assertEqual(membershipsB, set())
+ self.assertEqual(membershipsC, set(("A", "X",)))
+ self.assertEqual(membershipsD, set(("A",),))
+
+ @inlineCallbacks
def test_cachingDBInsertUncached(self):
for processType in ("Single", "Combined",):
Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_proxyprincipalmembers.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_proxyprincipalmembers.py 2009-01-06 20:23:10 UTC (rev 3572)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_proxyprincipalmembers.py 2009-01-07 18:15:56 UTC (rev 3573)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
+# Copyright (c) 2005-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.
@@ -18,10 +18,11 @@
from twisted.web2.dav import davxml
from twistedcaldav.directory.directory import DirectoryService
-from twistedcaldav.directory.xmlfile import XMLDirectoryService
from twistedcaldav.directory.test.test_xmlfile import xmlFile
from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
from twistedcaldav.directory.principal import DirectoryPrincipalResource
+from twistedcaldav.directory.xmlaccountsparser import XMLAccountsParser
+from twistedcaldav.directory.xmlfile import XMLDirectoryService
import twistedcaldav.test.util
@@ -76,6 +77,42 @@
return d
@inlineCallbacks
+ def _addProxy(self, principal, subPrincipalName, proxyPrincipal):
+
+ if isinstance(principal, tuple):
+ principal = self._getPrincipalByShortName(principal[0], principal[1])
+ principal = principal.getChild(subPrincipalName)
+ members = (yield principal.groupMembers())
+
+ if isinstance(proxyPrincipal, tuple):
+ proxyPrincipal = self._getPrincipalByShortName(proxyPrincipal[0], proxyPrincipal[1])
+ members.add(proxyPrincipal)
+
+ principal.setGroupMemberSetPrincipals(members)
+
+ @inlineCallbacks
+ def _removeProxy(self, recordType, recordName, subPrincipalName, proxyRecordType, proxyRecordName):
+
+ principal = self._getPrincipalByShortName(recordType, recordName)
+ principal = principal.getChild(subPrincipalName)
+ members = (yield principal.groupMembers())
+
+ proxyPrincipal = self._getPrincipalByShortName(proxyRecordType, proxyRecordName)
+ for p in members:
+ if p.principalUID() == proxyPrincipal.principalUID():
+ members.remove(p)
+ break
+
+ principal.setGroupMemberSetPrincipals(members)
+
+ def _clearProxy(self, principal, subPrincipalName):
+
+ if isinstance(principal, tuple):
+ principal = self._getPrincipalByShortName(principal[0], principal[1])
+ principal = principal.getChild(subPrincipalName)
+ principal.setGroupMemberSetPrincipals(set())
+
+ @inlineCallbacks
def _proxyForTest(self, recordType, recordName, expectedProxies, read_write):
principal = self._getPrincipalByShortName(recordType, recordName)
proxies = (yield principal.proxyFor(read_write))
@@ -278,3 +315,121 @@
False
)
+ @inlineCallbacks
+ def test_UserProxy(self):
+
+ for proxyType in ("calendar-proxy-read", "calendar-proxy-write"):
+
+ yield self._addProxy(
+ (DirectoryService.recordType_users, "wsanchez",),
+ proxyType,
+ (DirectoryService.recordType_users, "cdaboo",),
+ )
+
+ yield self._groupMembersTest(
+ DirectoryService.recordType_users, "wsanchez",
+ proxyType,
+ ("Cyrus Daboo",),
+ )
+
+ yield self._addProxy(
+ (DirectoryService.recordType_users, "wsanchez",),
+ proxyType,
+ (DirectoryService.recordType_users, "lecroy",),
+ )
+
+ yield self._groupMembersTest(
+ DirectoryService.recordType_users, "wsanchez",
+ proxyType,
+ ("Cyrus Daboo", "Chris Lecroy",),
+ )
+
+ yield self._removeProxy(
+ DirectoryService.recordType_users, "wsanchez",
+ proxyType,
+ DirectoryService.recordType_users, "cdaboo",
+ )
+
+ yield self._groupMembersTest(
+ DirectoryService.recordType_users, "wsanchez",
+ proxyType,
+ ("Chris Lecroy",),
+ )
+
+ @inlineCallbacks
+ def test_InvalidUserProxy(self):
+
+ 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)
+
+ testPrincipal = self._getPrincipalByShortName(DirectoryService.recordType_users, "cdaboo")
+
+ fakePrincipal = self._getPrincipalByShortName(DirectoryService.recordType_users, "dreid")
+ fakeProxyGroup = fakePrincipal.getChild(proxyType)
+
+ yield self._addProxy(
+ principal,
+ proxyType,
+ testPrincipal,
+ )
+ members = yield proxyGroup._index().getMembers(proxyGroup.uid)
+ self.assertEquals(len(members), 1)
+
+ yield self._addProxy(
+ fakePrincipal,
+ proxyType,
+ testPrincipal,
+ )
+ members = yield fakeProxyGroup._index().getMembers(fakeProxyGroup.uid)
+ self.assertEquals(len(members), 1)
+
+ uids = [p.principalUID() for p in (yield testPrincipal.groupMemberships())]
+ self.assertTrue("5FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1#%s" % (proxyType,) in uids)
+
+ memberships = yield testPrincipal._calendar_user_proxy_index().getMemberships(testPrincipal.principalUID())
+ self.assertEquals(len(memberships), 2)
+
+ yield self._addProxy(
+ principal,
+ proxyType,
+ fakePrincipal,
+ )
+ members = yield proxyGroup._index().getMembers(proxyGroup.uid)
+ self.assertEquals(len(members), 2)
+
+ # Remove the dreid user from the directory service
+ del directoryService._accounts()[DirectoryService.recordType_users]["dreid"]
+
+ @inlineCallbacks
+ def _membershipTest():
+ uids = [p.principalUID() for p in (yield testPrincipal.groupMemberships())]
+ self.assertTrue("5FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1#%s" % (proxyType,) not in uids)
+
+ memberships = yield testPrincipal._calendar_user_proxy_index().getMemberships(testPrincipal.principalUID())
+ self.assertEquals(len(memberships), 1)
+
+ @inlineCallbacks
+ def _membersTest():
+ yield self._groupMembersTest(
+ DirectoryService.recordType_users, "wsanchez",
+ proxyType,
+ ("Cyrus Daboo",),
+ )
+ members = yield proxyGroup._index().getMembers(proxyGroup.uid)
+ self.assertEquals(len(members), 1)
+
+ if doMembershipFirst:
+ yield _membershipTest()
+ yield _membersTest()
+ else:
+ yield _membersTest()
+ yield _membershipTest()
+
+ # Restore removed user
+ parser = XMLAccountsParser(directoryService.xmlFile)
+ directoryService._parsedAccounts = parser.items
+
+ self._clearProxy(principal, proxyType)
+ self._clearProxy(fakePrincipal, proxyType)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090107/746b3c14/attachment-0001.html>
More information about the calendarserver-changes
mailing list