[CalendarServer-changes] [10826] CalendarServer/branches/users/gaya/sharedgroups
source_changes at macosforge.org
source_changes at macosforge.org
Fri Mar 1 22:22:42 PST 2013
Revision: 10826
http://trac.calendarserver.org//changeset/10826
Author: gaya at apple.com
Date: 2013-03-01 22:22:42 -0800 (Fri, 01 Mar 2013)
Log Message:
-----------
add per-vCard ACLs
Modified Paths:
--------------
CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py
CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/storebridge.py
CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py
CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py
CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/upgrade/migrate.py
Modified: CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py 2013-03-01 20:22:14 UTC (rev 10825)
+++ CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py 2013-03-02 06:22:42 UTC (rev 10826)
@@ -380,7 +380,8 @@
@rtype: L{davxml.ACL}
"""
- assert self._isShareeResource, "Only call this for a sharee collection"
+ assert self._isShareeResource, "Only call this for a sharee resource"
+ assert self.isCalendarCollection() or self.isAddressBookCollection(), "Only call this for a address book or calendar resource"
sharee = self.principalForUID(self._share.shareeUID())
access = yield self._checkAccessControl()
@@ -392,8 +393,7 @@
returnValue(result)
# Direct shares use underlying privileges of shared collection
- userprivs = [
- ]
+ userprivs = []
if access in ("read-only", "read-write",):
userprivs.append(element.Privilege(element.Read()))
userprivs.append(element.Privilege(element.ReadACL()))
@@ -435,7 +435,7 @@
# Give all access to config.AdminPrincipals
aces += config.AdminACEs
- if config.EnableProxyPrincipals:
+ if self.isCalendarCollection() and config.EnableProxyPrincipals:
aces += (
# DAV:read/DAV:read-current-user-privilege-set access for this principal's calendar-proxy-read users.
element.ACE(
Modified: CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/storebridge.py 2013-03-01 20:22:14 UTC (rev 10825)
+++ CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/storebridge.py 2013-03-02 06:22:42 UTC (rev 10826)
@@ -1734,7 +1734,7 @@
return davxml.ACL(*aces)
- def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
+ def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None): #@UnusedVariable
# Permissions here are fixed, and are not subject to inheritance rules, etc.
return succeed(self.defaultAccessControlList())
@@ -2958,7 +2958,69 @@
"Sharee cannot delete a shared group",)
)
+ @inlineCallbacks
+ def accessControlList(self, request, *a, **kw):
+ """
+ Return WebDAV ACLs appropriate for the current user accessing the
+ a vcard in a shared addressbook or shared group.
+
+ Items in an "invite" share get read-onlly privileges.
+ (It's not clear if that case ever occurs)
+
+ "direct" shares are not supported.
+ @param request: the request used to locate the owner resource.
+ @type request: L{twext.web2.iweb.IRequest}
+
+ @param args: The arguments for
+ L{twext.web2.dav.idav.IDAVResource.accessControlList}
+
+ @param kwargs: The keyword arguments for
+ L{twext.web2.dav.idav.IDAVResource.accessControlList}, plus
+ keyword-only arguments.
+
+ @return: the appropriate WebDAV ACL for the sharee
+ @rtype: L{davxml.ACL}
+ """
+ if not self.exists():
+ log.debug("Resource not found: %s" % (self,))
+ raise HTTPError(NOT_FOUND)
+
+ if self._newStoreObject.addressbook().owned():
+ returnValue((yield super(AddressBookObjectResource, self).accessControlList(request, *a, **kw)))
+
+ # Direct shares use underlying privileges of shared collection
+ userprivs = []
+ userprivs.append(davxml.Privilege(davxml.Read()))
+ userprivs.append(davxml.Privilege(davxml.ReadACL()))
+ userprivs.append(davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()))
+
+ if (yield self._newStoreObject.readWriteAccess()):
+ userprivs.append(davxml.Privilege(davxml.Write()))
+ else:
+ userprivs.append(davxml.Privilege(davxml.WriteProperties()))
+
+ sharee = self.principalForUID(self._newStoreObject.viewerHome().uid())
+ aces = (
+ # Inheritable specific access for the resource's associated principal.
+ davxml.ACE(
+ davxml.Principal(davxml.HRef(sharee.principalURL())),
+ davxml.Grant(*userprivs),
+ davxml.Protected(),
+ TwistedACLInheritable(),
+ ),
+ )
+
+ # Give read access to config.ReadPrincipals
+ aces += config.ReadACEs
+
+ # Give all access to config.AdminPrincipals
+ aces += config.AdminACEs
+
+ returnValue(davxml.ACL(*aces))
+
+
+
class _NotificationChildHelper(object):
"""
Methods for things which are like notification objects.
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py 2013-03-01 20:22:14 UTC (rev 10825)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py 2013-03-02 06:22:42 UTC (rev 10826)
@@ -662,7 +662,6 @@
returnValue(child)
#all shared address books now
-
rows = None
queryCacher = home._txn._queryCacher
ownerHome = None
@@ -892,7 +891,7 @@
@classmethod
@inlineCallbacks
- def _objectIDsInExpandedGroupIDs(cls, txn, groupIDs, includeGroupIDs=True):
+ def expandGroupIDs(cls, txn, groupIDs, includeGroupIDs=True):
"""
Get all AddressBookObject resource IDs contains in the given shared groups with the given groupIDs
"""
@@ -942,32 +941,32 @@
groupBindRows = yield AddressBookObject._acceptedBindWithHomeIDAndAddressBookID.on(
self._txn, homeID=self._home._resourceID, addressbookID=self._resourceID
)
- readwriteGroupIDs = []
- readonlyGroupIDs = []
+ readWriteGroupIDs = []
+ readOnlyGroupIDs = []
for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@UnusedVariable
if bindMode == _BIND_MODE_WRITE:
- readwriteGroupIDs.append(resourceID)
+ readWriteGroupIDs.append(resourceID)
else:
- readonlyGroupIDs.append(resourceID)
+ readOnlyGroupIDs.append(resourceID)
- if readonlyGroupIDs and readwriteGroupIDs:
+ if readOnlyGroupIDs and readWriteGroupIDs:
# expand read-write groups and remove any subgroups from read-only group list
- allWriteableIDs = yield self._objectIDsInExpandedGroupIDs(self._txn, readwriteGroupIDs)
- adjustedReadOnlyGroupIDs = set(readonlyGroupIDs) - set(allWriteableIDs)
- adjustedReadWriteGroupIDs = set(readwriteGroupIDs) | (set(readonlyGroupIDs) - adjustedReadOnlyGroupIDs)
+ allWriteableIDs = yield self.expandGroupIDs(self._txn, readWriteGroupIDs)
+ adjustedReadOnlyGroupIDs = set(readOnlyGroupIDs) - set(allWriteableIDs)
+ adjustedReadWriteGroupIDs = set(readWriteGroupIDs) | (set(readOnlyGroupIDs) - adjustedReadOnlyGroupIDs)
else:
- adjustedReadOnlyGroupIDs = readonlyGroupIDs
- adjustedReadWriteGroupIDs = readwriteGroupIDs
+ adjustedReadOnlyGroupIDs = readOnlyGroupIDs
+ adjustedReadWriteGroupIDs = readWriteGroupIDs
returnValue((tuple(adjustedReadOnlyGroupIDs), tuple(adjustedReadWriteGroupIDs)))
-
+ '''
@inlineCallbacks
- def readonlyGroupIDs(self):
+ def readOnlyGroupIDs(self):
returnValue((yield self.accessControlGroupIDs())[0])
-
-
+ '''
+
@inlineCallbacks
- def writeableGroupIDs(self):
+ def readWriteGroupIDs(self):
returnValue((yield self.accessControlGroupIDs())[1])
@@ -1244,9 +1243,9 @@
# convert delete in sharee shared group address book to remove of memberships
# that make this object visible to the sharee
- writeableGroupIDs = yield self._addressbook.writeableGroupIDs()
- if writeableGroupIDs:
- objectsIDs = yield self._addressbook._objectIDsInExpandedGroupIDs(self._txn, writeableGroupIDs)
+ readWriteGroupIDs = yield self._addressbook.readWriteGroupIDs()
+ if readWriteGroupIDs:
+ objectsIDs = yield self._addressbook.expandGroupIDs(self._txn, readWriteGroupIDs)
yield self._deleteMembersWithMemberIDAndGroupIDsQuery(self._resourceID, objectsIDs).on(
self._txn, groupIDs=objectsIDs
)
@@ -1278,6 +1277,22 @@
self._component = None
+ @inlineCallbacks
+ def readWriteAccess(self):
+ assert not self.owned(), "Don't call items in owned address book"
+
+ # if fully shared and rw, must be RW since sharing group read-only has no affect
+ if self._addressbook.fullyShared() and self._addressbook.shareMode() == _BIND_MODE_WRITE:
+ yield None
+ returnValue(True)
+
+ readWriteGroupIDs = yield self._addressbook.readWriteGroupIDs()
+ if self._resourceID in (yield self._addressbook.expandGroupIDs(self._txn, readWriteGroupIDs)):
+ returnValue(True)
+
+ returnValue(False)
+
+
@classmethod
def _allColumnsWithResourceIDsAnd(cls, resourceIDs, column, paramName):
"""
@@ -1350,7 +1365,7 @@
rows = [(yield self._addressbook._groupForEntireAB_Row())]
else:
acceptedGroupIDs = yield self._addressbook.acceptedGroupIDs()
- allowedObjectIDs = yield self._addressbook._objectIDsInExpandedGroupIDs(self._txn, acceptedGroupIDs)
+ allowedObjectIDs = yield self._addressbook.expandGroupIDs(self._txn, acceptedGroupIDs)
if self._name:
if allowedObjectIDs:
rows = (yield self._allColumnsWithResourceIDsAndName(allowedObjectIDs).on(
@@ -1400,14 +1415,6 @@
returnValue(None)
- @inlineCallbacks
- def _objectIDsInExpandedGroup(self):
- """
- Get all AddressBookObject resource IDs contained in this shared group
- """
- returnValue((yield self._addressbook._objectIDsInExpandedGroupIDs(self._txn, [self._resourceID])))
-
-
@classproperty
def _allColumns(cls): #@NoSelf
"""
@@ -1463,7 +1470,7 @@
rows.append((yield addressbook._groupForEntireAB_Row()))
else:
acceptedGroupIDs = addressbook.acceptedGroupIDs()
- allowedObjectIDs = yield addressbook._objectIDsInExpandedGroupIDs(addressbook._txn, acceptedGroupIDs)
+ allowedObjectIDs = yield addressbook.expandGroupIDs(addressbook._txn, acceptedGroupIDs)
rows = yield cls._columnsWithResourceIDsQuery(cls._allColumns, allowedObjectIDs).on(
addressbook._txn, resourceIDs=allowedObjectIDs
)
@@ -1488,7 +1495,7 @@
rows.append((yield addressbook._groupForEntireAB_Row()))
else:
acceptedGroupIDs = addressbook.acceptedGroupIDs()
- allowedObjectIDs = yield addressbook._objectIDsInExpandedGroupIDs(addressbook._txn, acceptedGroupIDs)
+ allowedObjectIDs = yield addressbook.expandGroupIDs(addressbook._txn, acceptedGroupIDs)
rows = yield cls._allColumnsWithResourceIDsAndNamesQuery(allowedObjectIDs, names).on(
addressbook._txn, resourceIDs=allowedObjectIDs, names=names
)
@@ -1631,7 +1638,7 @@
raise GroupWithUnsharedAddressNotAllowedError
acceptedGroupIDs = yield self._addressbook.acceptedGroupIDs()
- allowedObjectIDs = yield self._addressbook._objectIDsInExpandedGroupIDs(self._txn, acceptedGroupIDs)
+ allowedObjectIDs = yield self._addressbook.expandGroupIDs(self._txn, acceptedGroupIDs)
if set(memberIDs) - set(allowedObjectIDs):
raise GroupWithUnsharedAddressNotAllowedError
@@ -1694,12 +1701,12 @@
).on(self._txn)
groupIDs = [groupIDRow[0] for groupIDRow in groupIDRows]
- # FIXME: Is this correct?
+ # FIXME: Is this correct? Write test case
if not self.owned():
if not self._addressbook.fullyShared() or self._addressbook.shareMode() != _BIND_MODE_WRITE:
- writeableGroupIDs = yield self._addressbook.writeableGroupIDs()
- assert writeableGroupIDs, "no access"
- groupIDs.extend(writeableGroupIDs)
+ readWriteGroupIDs = yield self._addressbook.readWriteGroupIDs()
+ assert readWriteGroupIDs, "no access"
+ groupIDs.extend(readWriteGroupIDs)
# add to member table rows
for groupID in groupIDs:
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py 2013-03-01 20:22:14 UTC (rev 10825)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py 2013-03-02 06:22:42 UTC (rev 10826)
@@ -3104,16 +3104,27 @@
"""
rows = yield cls._bindForResourceIDAndHomeID.on(
home._txn, resourceID=resourceID, homeID=home._resourceID)
- if rows:
- bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
- if bindStatus == _BIND_STATUS_ACCEPTED:
- returnValue((yield home.childWithName(resourceName)))
- else:
- returnValue((yield cls.objectWithName(home, resourceName, accepted=False)))
+ if not rows:
+ returnValue(None)
- returnValue(None)
+ bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
+ if bindMode == _BIND_MODE_OWN:
+ ownerHome = home
+ else:
+ ownerHomeID = (yield cls._ownerHomeWithResourceID.on(
+ home._txn, resourceID=resourceID))[0][0]
+ ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
+ child = cls(
+ home=home,
+ name=resourceName, resourceID=resourceID,
+ mode=bindMode, status=bindStatus,
+ message=bindMessage, ownerHome=ownerHome,
+ )
+ yield child.initFromStore()
+ returnValue(child)
+
@classproperty
def _insertHomeChild(cls): #@NoSelf
"""
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/upgrade/migrate.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/upgrade/migrate.py 2013-03-01 20:22:14 UTC (rev 10825)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/upgrade/migrate.py 2013-03-02 06:22:42 UTC (rev 10826)
@@ -409,8 +409,7 @@
for homeType, eachFunc in [
("calendar", self.fileStore.withEachCalendarHomeDo),
- # FIXME:
- # ("addressbook", self.fileStore.withEachAddressbookHomeDo),
+ ("addressbook", self.fileStore.withEachAddressbookHomeDo),
]:
yield eachFunc(
lambda txn, home: self._upgradeAction(
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130301/08d46a61/attachment-0001.html>
More information about the calendarserver-changes
mailing list