[CalendarServer-changes] [7540] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Tue May 31 17:24:02 PDT 2011
Revision: 7540
http://trac.macosforge.org/projects/calendarserver/changeset/7540
Author: sagen at apple.com
Date: 2011-05-31 17:24:02 -0700 (Tue, 31 May 2011)
Log Message:
-----------
Delegates can now access wiki calendars that have been shared into the delegator's account (with same access as delegator) 9516310
Modified Paths:
--------------
CalendarServer/trunk/calendarserver/provision/root.py
CalendarServer/trunk/twistedcaldav/directory/principal.py
CalendarServer/trunk/twistedcaldav/directory/wiki.py
CalendarServer/trunk/twistedcaldav/sharing.py
CalendarServer/trunk/twistedcaldav/test/test_sharing.py
Modified: CalendarServer/trunk/calendarserver/provision/root.py
===================================================================
--- CalendarServer/trunk/calendarserver/provision/root.py 2011-05-31 14:56:50 UTC (rev 7539)
+++ CalendarServer/trunk/calendarserver/provision/root.py 2011-06-01 00:24:02 UTC (rev 7540)
@@ -323,10 +323,13 @@
if segments[0] in ("inbox", "timezones"):
request.checkedSACL = True
- elif (len(segments) > 2 and (segments[1] == "wikis" or
- (segments[1] == "__uids__" and segments[2].startswith("wiki-")))):
-
- # This is a wiki-related resource. SACLs are not checked.
+ elif (len(segments) > 2 and segments[0] == "calendars" and
+ (
+ segments[1] == "wikis" or
+ (segments[1] == "__uids__" and segments[2].startswith("wiki-"))
+ )
+ ):
+ # This is a wiki-related calendar resource. SACLs are not checked.
request.checkedSACL = True
# The authzuser value is set to that of the wiki principal if
Modified: CalendarServer/trunk/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/principal.py 2011-05-31 14:56:50 UTC (rev 7539)
+++ CalendarServer/trunk/twistedcaldav/directory/principal.py 2011-06-01 00:24:02 UTC (rev 7540)
@@ -70,18 +70,9 @@
def defaultAccessControlList(self):
return authReadACL
- @inlineCallbacks
def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
- wikiACL = (yield getWikiACL(self, request))
- if wikiACL is not None:
- # ACL depends on wiki server...
- log.debug("Wiki ACL: %s" % (wikiACL.toxml(),))
- returnValue(wikiACL)
- else:
- # ...otherwise permissions are fixed, and are not subject to
- # inheritance rules, etc.
- returnValue(self.defaultAccessControlList())
+ return succeed(self.defaultAccessControlList())
Modified: CalendarServer/trunk/twistedcaldav/directory/wiki.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/wiki.py 2011-05-31 14:56:50 UTC (rev 7539)
+++ CalendarServer/trunk/twistedcaldav/directory/wiki.py 2011-06-01 00:24:02 UTC (rev 7540)
@@ -128,7 +128,38 @@
self.enabled = True
+ at inlineCallbacks
+def getWikiAccess(userID, wikiID):
+ """
+ Ask the wiki server we're paired with what level of access the userID has
+ for the given wikiID. Possible values are "read", "write", and "admin"
+ (which we treat as "write").
+ """
+ wikiConfig = config.Authentication.Wiki
+ proxy = Proxy(wikiConfig["URL"])
+ try:
+ log.debug("Looking up Wiki ACL for: user [%s], wiki [%s]" % (userID,
+ wikiID))
+ access = (yield proxy.callRemote(wikiConfig["WikiMethod"],
+ userID, wikiID))
+
+ log.debug("Wiki ACL result: user [%s], wiki [%s], access [%s]" % (userID,
+ wikiID, access))
+ returnValue(access)
+
+ except Fault, fault:
+
+ log.debug("Wiki ACL result: user [%s], wiki [%s], FAULT [%s]" % (userID,
+ wikiID, fault))
+
+ if fault.faultCode == 2: # non-existent user
+ raise HTTPError(StatusResponse(responsecode.FORBIDDEN, fault.faultString))
+
+ else: # fault.faultCode == 12, non-existent wiki
+ raise HTTPError(StatusResponse(responsecode.NOT_FOUND, fault.faultString))
+
+
@inlineCallbacks
def getWikiACL(resource, request):
"""
@@ -151,7 +182,6 @@
if hasattr(request, 'wikiACL'):
returnValue(request.wikiACL)
- wikiConfig = config.Authentication.Wiki
userID = "unauthenticated"
wikiID = resource.record.shortNames[0]
@@ -164,17 +194,9 @@
# TODO: better error handling
pass
- proxy = Proxy(wikiConfig["URL"])
try:
+ access = (yield getWikiAccess(userID, wikiID))
- log.debug("Looking up Wiki ACL for: user [%s], wiki [%s]" % (userID,
- wikiID))
- access = (yield proxy.callRemote(wikiConfig["WikiMethod"],
- userID, wikiID))
-
- log.debug("Wiki ACL result: user [%s], wiki [%s], access [%s]" % (userID,
- wikiID, access))
-
# The ACL we returns has ACEs for the end-user and the wiki principal
# in case authzUser is the wiki principal.
if access == "read":
@@ -246,18 +268,6 @@
)
)
-
- except Fault, fault:
-
- log.error("Wiki ACL result: user [%s], wiki [%s], FAULT [%s]" % (userID,
- wikiID, fault))
-
- if fault.faultCode == 2: # non-existent user
- raise HTTPError(StatusResponse(responsecode.FORBIDDEN, fault.faultString))
-
- else: # fault.faultCode == 12, non-existent wiki
- raise HTTPError(StatusResponse(responsecode.NOT_FOUND, fault.faultString))
-
except HTTPError:
# pass through the HTTPError we might have raised above
raise
Modified: CalendarServer/trunk/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/sharing.py 2011-05-31 14:56:50 UTC (rev 7539)
+++ CalendarServer/trunk/twistedcaldav/sharing.py 2011-06-01 00:24:02 UTC (rev 7540)
@@ -38,6 +38,7 @@
from twistedcaldav import customxml, caldavxml
from twistedcaldav.config import config
from twistedcaldav.customxml import calendarserver_namespace
+from twistedcaldav.directory.wiki import WikiDirectoryService, getWikiAccess
from twistedcaldav.linkresource import LinkFollowerMixIn
from twistedcaldav.sql import AbstractSQLDatabase, db_prefix
@@ -267,11 +268,28 @@
assert self._isVirtualShare, "Only call this for a virtual share"
+ wikiAccessMethod = kwargs.get("wikiAccessMethod", getWikiAccess)
+
# Direct shares use underlying privileges of shared collection
if self._share.sharetype == SHARETYPE_DIRECT:
original = (yield request.locateResource(self._share.hosturl))
- result = (yield original.accessControlList(request, *args, **kwargs))
- returnValue(result)
+ owner = yield original.ownerPrincipal(request)
+ if owner.record.recordType == WikiDirectoryService.recordType_wikis:
+ # Access level comes from what the wiki has granted to the
+ # sharee
+ userID = self._shareePrincipal.record.guid
+ wikiID = owner.record.shortNames[0]
+ inviteAccess = (yield wikiAccessMethod(userID, wikiID))
+ if inviteAccess == "read":
+ inviteAccess = "read-only"
+ elif inviteAccess in ("write", "admin"):
+ inviteAccess = "read-write"
+ else:
+ inviteAccess = None
+ else:
+ result = (yield original.accessControlList(request, *args,
+ **kwargs))
+ returnValue(result)
else:
# Invite shares use access mode from the invite
@@ -281,68 +299,69 @@
)
if invite is None:
returnValue(davxml.ACL())
+ inviteAccess = invite.access
- userprivs = [
- ]
- if invite.access in ("read-only", "read-write", "read-write-schedule",):
- userprivs.append(davxml.Privilege(davxml.Read()))
- userprivs.append(davxml.Privilege(davxml.ReadACL()))
- userprivs.append(davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()))
- if invite.access in ("read-only",):
- userprivs.append(davxml.Privilege(davxml.WriteProperties()))
- if invite.access in ("read-write", "read-write-schedule",):
- userprivs.append(davxml.Privilege(davxml.Write()))
- proxyprivs = list(userprivs)
- proxyprivs.remove(davxml.Privilege(davxml.ReadACL()))
+ userprivs = [
+ ]
+ if inviteAccess in ("read-only", "read-write", "read-write-schedule",):
+ userprivs.append(davxml.Privilege(davxml.Read()))
+ userprivs.append(davxml.Privilege(davxml.ReadACL()))
+ userprivs.append(davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()))
+ if inviteAccess in ("read-only",):
+ userprivs.append(davxml.Privilege(davxml.WriteProperties()))
+ if inviteAccess in ("read-write", "read-write-schedule",):
+ userprivs.append(davxml.Privilege(davxml.Write()))
+ proxyprivs = list(userprivs)
+ proxyprivs.remove(davxml.Privilege(davxml.ReadACL()))
- aces = (
- # Inheritable specific access for the resource's associated principal.
+ aces = (
+ # Inheritable specific access for the resource's associated principal.
+ davxml.ACE(
+ davxml.Principal(davxml.HRef(self._shareePrincipal.principalURL())),
+ davxml.Grant(*userprivs),
+ davxml.Protected(),
+ TwistedACLInheritable(),
+ ),
+ )
+
+ if self.isCalendarCollection():
+ aces += (
+ # Inheritable CALDAV:read-free-busy access for authenticated users.
davxml.ACE(
- davxml.Principal(davxml.HRef(self._shareePrincipal.principalURL())),
- davxml.Grant(*userprivs),
- davxml.Protected(),
+ davxml.Principal(davxml.Authenticated()),
+ davxml.Grant(davxml.Privilege(caldavxml.ReadFreeBusy())),
TwistedACLInheritable(),
),
)
- if self.isCalendarCollection():
- aces += (
- # Inheritable CALDAV:read-free-busy access for authenticated users.
- davxml.ACE(
- davxml.Principal(davxml.Authenticated()),
- davxml.Grant(davxml.Privilege(caldavxml.ReadFreeBusy())),
- TwistedACLInheritable(),
- ),
- )
+ # Give read access to config.ReadPrincipals
+ aces += config.ReadACEs
- # Give read access to config.ReadPrincipals
- aces += config.ReadACEs
+ # Give all access to config.AdminPrincipals
+ aces += config.AdminACEs
- # Give all access to config.AdminPrincipals
- aces += config.AdminACEs
-
- if config.EnableProxyPrincipals:
- aces += (
- # DAV:read/DAV:read-current-user-privilege-set access for this principal's calendar-proxy-read users.
- davxml.ACE(
- davxml.Principal(davxml.HRef(joinURL(self._shareePrincipal.principalURL(), "calendar-proxy-read/"))),
- davxml.Grant(
- davxml.Privilege(davxml.Read()),
- davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()),
- ),
- davxml.Protected(),
- TwistedACLInheritable(),
+ if config.EnableProxyPrincipals:
+ aces += (
+ # DAV:read/DAV:read-current-user-privilege-set access for this principal's calendar-proxy-read users.
+ davxml.ACE(
+ davxml.Principal(davxml.HRef(joinURL(self._shareePrincipal.principalURL(), "calendar-proxy-read/"))),
+ davxml.Grant(
+ davxml.Privilege(davxml.Read()),
+ davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()),
),
- # DAV:read/DAV:read-current-user-privilege-set/DAV:write access for this principal's calendar-proxy-write users.
- davxml.ACE(
- davxml.Principal(davxml.HRef(joinURL(self._shareePrincipal.principalURL(), "calendar-proxy-write/"))),
- davxml.Grant(*proxyprivs),
- davxml.Protected(),
- TwistedACLInheritable(),
- ),
- )
+ davxml.Protected(),
+ TwistedACLInheritable(),
+ ),
+ # DAV:read/DAV:read-current-user-privilege-set/DAV:write access for this principal's calendar-proxy-write users.
+ davxml.ACE(
+ davxml.Principal(davxml.HRef(joinURL(self._shareePrincipal.principalURL(), "calendar-proxy-write/"))),
+ davxml.Grant(*proxyprivs),
+ davxml.Protected(),
+ TwistedACLInheritable(),
+ ),
+ )
- returnValue(davxml.ACL(*aces))
+ returnValue(davxml.ACL(*aces))
def validUserIDForShare(self, userid):
"""
Modified: CalendarServer/trunk/twistedcaldav/test/test_sharing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_sharing.py 2011-05-31 14:56:50 UTC (rev 7539)
+++ CalendarServer/trunk/twistedcaldav/test/test_sharing.py 2011-06-01 00:24:02 UTC (rev 7540)
@@ -18,16 +18,20 @@
from twext.web2 import responsecode
from twext.web2.dav import davxml
from twext.web2.http_headers import MimeType
+from twext.web2.iweb import IResource
from twext.web2.stream import MemoryStream
from twext.web2.test.test_server import SimpleRequest
from twisted.internet.defer import inlineCallbacks, returnValue, succeed
from twistedcaldav import customxml
from twistedcaldav.config import config
from twistedcaldav.test.util import HomeTestCase, norequest
+from twistedcaldav.sharing import SharedCollectionMixin, SHARETYPE_DIRECT, WikiDirectoryService
from twistedcaldav.resource import CalDAVResource
from txdav.common.datastore.test.util import buildStore, StubNotifierFactory
+from zope.interface import implements
+
sharedOwnerType = davxml.ResourceType.sharedownercalendar #@UndefinedVariable
regularCalendarType = davxml.ResourceType.calendar #@UndefinedVariable
@@ -542,7 +546,85 @@
self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite())
+ @inlineCallbacks
+ def test_wikiACL(self):
+ """
+ Ensure shareeAccessControlList( ) honors the access granted by the wiki
+ to the sharee, so that delegates of the sharee get the same level of
+ access.
+ """
+ def stubWikiAccessMethod(userID, wikiID):
+ return access
+
+ class StubCollection(object):
+ def __init__(self):
+ self._isVirtualShare = True
+ self._shareePrincipal = StubUserPrincipal()
+ def isCalendarCollection(self):
+ return True
+
+ class StubShare(object):
+ def __init__(self):
+ self.sharetype = SHARETYPE_DIRECT
+ self.hosturl = "/wikifoo"
+
+ class TestCollection(SharedCollectionMixin, StubCollection):
+ pass
+
+ class StubRecord(object):
+ def __init__(self, recordType, name, guid):
+ self.recordType = recordType
+ self.shortNames = [name]
+ self.guid = guid
+
+ class StubUserPrincipal(object):
+ def __init__(self):
+ self.record = StubRecord(
+ "users",
+ "testuser",
+ "4F364813-0415-45CB-9FD4-DBFEF7A0A8E0"
+ )
+ def principalURL(self):
+ return "/principals/__uids__/%s/" % (self.record.guid,)
+
+ class StubWikiPrincipal(object):
+ def __init__(self):
+ self.record = StubRecord(
+ WikiDirectoryService.recordType_wikis,
+ "wikifoo",
+ "foo"
+ )
+
+ class StubWikiResource(object):
+ implements(IResource)
+
+ def locateChild(self, req, segments):
+ pass
+ def renderHTTP(req):
+ pass
+ def ownerPrincipal(self, req):
+ return succeed(StubWikiPrincipal())
+
+
+ collection = TestCollection()
+ collection._share = StubShare()
+ self.site.resource.putChild("wikifoo", StubWikiResource())
+ request = SimpleRequest(self.site, "GET", "/wikifoo")
+
+ # Simulate the wiki server granting Read access
+ access = "read"
+ acl = (yield collection.shareeAccessControlList(request,
+ wikiAccessMethod=stubWikiAccessMethod))
+ self.assertFalse("<write/>" in acl.toxml())
+
+ # Simulate the wiki server granting Read-Write access
+ access = "write"
+ acl = (yield collection.shareeAccessControlList(request,
+ wikiAccessMethod=stubWikiAccessMethod))
+ self.assertTrue("<write/>" in acl.toxml())
+
+
class DatabaseSharingTests(SharingTests):
@inlineCallbacks
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110531/37c80b82/attachment-0001.html>
More information about the calendarserver-changes
mailing list