[CalendarServer-changes] [10007] CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/ datastore/sql.py

source_changes at macosforge.org source_changes at macosforge.org
Wed Nov 7 20:53:48 PST 2012


Revision: 10007
          http://trac.calendarserver.org//changeset/10007
Author:   gaya at apple.com
Date:     2012-11-07 20:53:48 -0800 (Wed, 07 Nov 2012)
Log Message:
-----------
fix foreign group tracking.  Change delete of vcard inside shared group to a group member modification.  Prevent group change inside of shared group from adding new members to group.

Modified Paths:
--------------
    CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py

Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py	2012-11-07 04:09:23 UTC (rev 10006)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py	2012-11-08 04:53:48 UTC (rev 10007)
@@ -31,7 +31,10 @@
 
 from twext.python.clsprop import classproperty
 from twext.web2.http_headers import MimeType
+from twext.web2 import responsecode
+from twext.web2.http import HTTPError
 
+
 from twisted.internet.defer import inlineCallbacks, returnValue
 from twisted.python import hashlib
 from twistedcaldav import carddavxml, customxml
@@ -54,6 +57,7 @@
     ADDRESSBOOK_OBJECT_REVISIONS_AND_BIND_TABLE, \
     _ABO_KIND_PERSON, _ABO_KIND_GROUP, _ABO_KIND_RESOURCE, _ABO_KIND_LOCATION, \
     schema
+from txdav.common.icommondatastore import NoSuchObjectResourceError
 from txdav.xml.rfc2518 import ResourceType
 
 from uuid import uuid4
@@ -366,22 +370,43 @@
 
         print("remove:%s, name=%s" % (self, self._name))
 
-        if not self._addressbook.owned():
+        if self._addressbook.owned():
+            if self._kind == _ABO_KIND_GROUP:
+                # need to invalidate queryCacher of sharee's home
+                queryCacher = self._txn._queryCacher
+                if queryCacher:
+                    for shareeAddressBook in (yield self.asShared()):
+                        cacheKey = queryCacher.keyForObjectWithName(shareeAddressBook._home._resourceID, shareeAddressBook._name)
+                        yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+
+        else:
             ownerGroup, ownerAddressBook = yield self._ownerGroupAndAddressBook()  #@UnusedVariable 
+            print("remove:%s, ownerGroup=%s, ownerAddressBook=%s" % (self, ownerGroup, ownerAddressBook,))
             if ownerGroup:
-                ownerGroupComponent = yield ownerGroup.component()
+                # convert a delete inside of a shared group to a remove of in shared group and subgroups
+
+                groupIDRows = yield Select(
+                    [aboMembers.GROUP_ID],
+                    From=aboMembers,
+                    Where=(aboMembers.MEMBER_ID == self._resourceID).And(
+                            aboMembers.GROUP_ID != ownerAddressBook._resourceID),
+                ).on(self._txn)
+                groupIDs = [groupID[0] for groupID in groupIDRows]
+                print("remove:self=%s, groupIDs=%s" % (self, groupIDs,))
+
+                objectResources = yield ownerAddressBook.objectResources()
+                groupObjects = [groupObject for groupObject in objectResources
+                                    if groupObject._resourceID in groupIDs]
+
+                print("remove:self=%s, groupIDs=%s, objectResources=%s, groupObjects=%s" % (self, groupIDs, objectResources, groupObjects,))
                 member = "urn:uuid:" + self._uid
-                if member in ownerGroupComponent.resourceMembers():
-                    ownerGroupComponent.removeProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", member))
-                    ownerGroup.updateDatabase(ownerGroupComponent)
+                for groupObject in groupObjects:
+                    groupObjectComponent = yield groupObject.component()
+                    if member in groupObjectComponent.resourceMembers():
+                        groupObjectComponent.removeProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", member))
+                        groupObject.updateDatabase(groupObjectComponent)
 
-        elif self._kind == _ABO_KIND_GROUP:
-            # need to invalidate queryCacher
-            queryCacher = self._txn._queryCacher
-            if queryCacher:
-                for shareeAddressBook in (yield self.asShared()):
-                    cacheKey = queryCacher.keyForObjectWithName(shareeAddressBook._home._resourceID, shareeAddressBook._name)
-                    yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+                return
 
         # delete members table row for this object
         groupIDs = yield Delete(
@@ -619,20 +644,54 @@
         assert inserting or self._kind == kind  # can't change kind. Should be checked in upper layers
         self._kind = kind
 
-        ''' FIXME: 
-            SECURITY HOLE on for shared groups:  Non owner may NOT add group members not currently in group!
-            (Or it would be possible to troll for unshared vCard UIDs and make them shared.)
-            Fixes: just prevent it, but may make some clients fail when sharee adds groups + members to shared group.
-        '''
+        ''' : 
+         '''
 
         print("updateDatabase:self=%s self._addressbook.=%s self._ownerAddressBookResourceID=%s" % (self, self._addressbook, self._ownerAddressBookResourceID,))
         print("updateDatabase:self=%s insert=%s, component=%s" % (self, inserting, component))
-        if inserting:
 
+        # SECURITY Fix on for shared groups:  Non owner may NOT add group members not currently in group!
+        # (Or it would be possible to troll for unshared vCard UIDs and make them shared.)
+
+        if inserting or self._kind == _ABO_KIND_GROUP:
+
             ownerGroup, ownerAddressBook = yield self._ownerGroupAndAddressBook()
             assert ownerAddressBook
             self._ownerAddressBookResourceID = ownerAddressBook._resourceID
 
+        assert self._ownerAddressBookResourceID
+
+        if self._kind == _ABO_KIND_GROUP:
+
+            # get member ids
+            memberIDs = []
+            foreignMemberAddrs = []
+            resourceMembers = component.resourceMembers()
+            for memberAddr in resourceMembers:
+                memberRow = []
+                if len(memberAddr) > len("urn:uuid:") and memberAddr.startswith("urn:uuid:"):
+                    memberUID = memberAddr[len("urn:uuid:"):]
+                    memberRow = yield Select([abo.RESOURCE_ID],
+                                     From=abo,
+                                     Where=((abo.ADDRESSBOOK_RESOURCE_ID == self._ownerAddressBookResourceID)
+                                            ).And(abo.VCARD_UID == memberUID)).on(self._txn)
+                if memberRow:
+                    memberIDs.append(memberRow[0][0])
+                else:
+                    foreignMemberAddrs.append(memberAddr)
+
+            #in shared group, all members must be inside the shared group
+            if ownerGroup:
+                if len(resourceMembers) != len(memberIDs):
+                    raise NoSuchObjectResourceError
+                    raise HTTPError(responsecode.NOT_FOUND)
+                elif set(memberIDs) - set((yield self._addressbook._addressBookObjectIDs())):
+                    print("e2")
+                    raise NoSuchObjectResourceError
+                    raise HTTPError(responsecode.NOT_FOUND)
+
+        if inserting:
+
             self._resourceID, self._created, self._modified = (
                 yield self._insertABObject.on(
                     self._txn,
@@ -660,7 +719,6 @@
                  aboMembers.MEMBER_ID: self._resourceID, }
             ).on(self._txn)
 
-            # update existing group member tables for this new object
             # delete foreign members table row for this object
             groupIDs = yield Delete(
                 aboForeignMembers,
@@ -689,21 +747,6 @@
         if self._kind == _ABO_KIND_GROUP:
 
             assert self._ownerAddressBookResourceID
-            # get member resource ID for each member string, or keep as string
-            memberIDs = []
-            foreignMemberAddrs = []
-            for memberAddr in component.resourceMembers():
-                memberRow = []
-                if len(memberAddr) > len("urn:uuid:") and memberAddr.startswith("urn:uuid:"):
-                    memberUID = memberAddr[len("urn:uuid:"):]
-                    memberRow = yield Select([abo.RESOURCE_ID],
-                                     From=abo,
-                                     Where=((abo.ADDRESSBOOK_RESOURCE_ID == self._ownerAddressBookResourceID)
-                                            ).And(abo.VCARD_UID == memberUID)).on(self._txn)
-                if memberRow:
-                    memberIDs.append(memberRow[0][0])
-                else:
-                    foreignMemberAddrs.append(memberAddr)
 
             #get current members
             currentMemberRows = yield Select([aboMembers.MEMBER_ID],
@@ -718,7 +761,8 @@
             for memberIDToDelete in memberIDsToDelete:
                 yield Delete(
                     aboMembers,
-                    Where=((aboMembers.GROUP_ID == self._resourceID).And(aboMembers.MEMBER_ID == memberIDToDelete))
+                    Where=((aboMembers.GROUP_ID == self._resourceID).And(
+                            aboMembers.MEMBER_ID == memberIDToDelete))
                 ).on(self._txn)
 
             for memberIDToAdd in memberIDsToAdd:
@@ -731,17 +775,21 @@
                 ).on(self._txn)
 
             #get current foreign members 
-            currentForeignMemberAddrs = yield Select([aboForeignMembers.MEMBER_ADDRESS],
+            currentForeignMemberRows = yield Select([aboForeignMembers.MEMBER_ADDRESS],
                                                  From=aboForeignMembers,
                                                  Where=(aboForeignMembers.GROUP_ID == self._resourceID)).on(self._txn)
+            currentForeignMemberAddrs = [currentForeignMemberRow[0] for currentForeignMemberRow in currentForeignMemberRows]
 
             foreignMemberAddrsToDelete = set(currentForeignMemberAddrs) - set(foreignMemberAddrs)
             foreignMemberAddrsToAdd = set(foreignMemberAddrs) - set(currentForeignMemberAddrs)
+            print("updateDatabase4:self=%s component.resourceMembers()=%s, currentForeignMemberAddrs:%s,  foreignMemberAddrsToAdd:%s, foreignMemberAddrsToDelete:%s" %
+                  (self, component.resourceMembers(), currentForeignMemberAddrs, foreignMemberAddrsToAdd, foreignMemberAddrsToDelete,))
 
             for foreignMemberAddrToDelete in foreignMemberAddrsToDelete:
                 yield Delete(
                     aboForeignMembers,
-                    Where=((aboMembers.GROUP_ID == self._resourceID).And(aboForeignMembers.MEMBER_ADDRESS == foreignMemberAddrToDelete))
+                    Where=((aboForeignMembers.GROUP_ID == self._resourceID).And(
+                            aboForeignMembers.MEMBER_ADDRESS == foreignMemberAddrToDelete))
                 ).on(self._txn)
 
             for foreignMemberAddrToAdd in foreignMemberAddrsToAdd:
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20121107/88233b57/attachment-0001.html>


More information about the calendarserver-changes mailing list