Skip to content
This repository has been archived by the owner on Feb 13, 2020. It is now read-only.

Commit

Permalink
Fix exception with missing sharee when examining an attachment path.
Browse files Browse the repository at this point in the history
  • Loading branch information
cyrusdaboo committed Jul 16, 2015
1 parent f34c217 commit 7310b47
Show file tree
Hide file tree
Showing 2 changed files with 194 additions and 33 deletions.
41 changes: 21 additions & 20 deletions twistedcaldav/storebridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -2006,34 +2006,35 @@ def sharedDropboxACEs(self):
userprivs.extend(privileges)

principal = self.principalForUID(invite.shareeUID())
aces += (
# Inheritable specific access for the resource's associated principal.
davxml.ACE(
davxml.Principal(davxml.HRef(principal.principalURL())),
davxml.Grant(*userprivs),
davxml.Protected(),
TwistedACLInheritable(),
),
)

if config.EnableProxyPrincipals:
if principal is not None:
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(principal.principalURL(), "calendar-proxy-read/"))),
davxml.Grant(*userprivs),
davxml.Protected(),
TwistedACLInheritable(),
),
# DAV:read/DAV:read-current-user-privilege-set/DAV:write access for this principal's calendar-proxy-write users.
# Inheritable specific access for the resource's associated principal.
davxml.ACE(
davxml.Principal(davxml.HRef(joinURL(principal.principalURL(), "calendar-proxy-write/"))),
davxml.Principal(davxml.HRef(principal.principalURL())),
davxml.Grant(*userprivs),
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(principal.principalURL(), "calendar-proxy-read/"))),
davxml.Grant(*userprivs),
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(principal.principalURL(), "calendar-proxy-write/"))),
davxml.Grant(*userprivs),
davxml.Protected(),
TwistedACLInheritable(),
),
)

returnValue(aces)


Expand Down
186 changes: 173 additions & 13 deletions twistedcaldav/test/test_sharing.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
from twext.web2.dav.util import allDataFromStream
from twext.web2.http_headers import MimeType
from twext.web2.iweb import IResponse
from twext.web2.stream import MemoryStream

from twisted.internet.defer import inlineCallbacks, returnValue, succeed

from twistedcaldav import customxml
from twistedcaldav import sharing
from twistedcaldav.config import config
from twistedcaldav.directory.principal import DirectoryCalendarPrincipalResource
from twistedcaldav.ical import Component
from twistedcaldav.resource import CalDAVResource
from twistedcaldav.sharing import WikiDirectoryService
from twistedcaldav.test.test_cache import StubResponseCacheResource
Expand All @@ -35,6 +37,7 @@
from txdav.xml.parser import WebDAVDocument

from xml.etree.cElementTree import XML
import urlparse


sharedOwnerType = davxml.ResourceType.sharedownercalendar #@UndefinedVariable
Expand Down Expand Up @@ -81,6 +84,7 @@ def __init__(self, name, cuaddr):
class FakePrincipal(DirectoryCalendarPrincipalResource):

invalid_names = set()
missing_names = set()

def __init__(self, cuaddr, test):
if cuaddr.startswith("mailto:"):
Expand Down Expand Up @@ -124,20 +128,20 @@ def displayName(self):



class SharingTests(StoreTestCase):
class BaseSharingTests(StoreTestCase):

def configure(self):
"""
Override configuration hook to turn on sharing.
"""
super(SharingTests, self).configure()
super(BaseSharingTests, self).configure()
self.patch(config.Sharing, "Enabled", True)
self.patch(config.Sharing.Calendars, "Enabled", True)


@inlineCallbacks
def setUp(self):
yield super(SharingTests, self).setUp()
yield super(BaseSharingTests, self).setUp()

def patched(c):
"""
Expand Down Expand Up @@ -183,7 +187,7 @@ def validUserIDForShare(resourceSelf, userid, request):

@patched
def principalForUID(resourceSelf, principalUID):
return FakePrincipal("urn:uuid:" + principalUID, self)
return FakePrincipal("urn:uuid:" + principalUID, self) if principalUID not in FakePrincipal.missing_names else None

self.resource = yield self._getResource()

Expand All @@ -192,7 +196,7 @@ def principalForUID(resourceSelf, principalUID):
def _refreshRoot(self, request=None):
if request is None:
request = norequest()
result = yield super(SharingTests, self)._refreshRoot(request)
result = yield super(BaseSharingTests, self)._refreshRoot(request)
self.resource = (
yield self.site.resource.locateChild(request, ["calendar"])
)[0]
Expand Down Expand Up @@ -344,6 +348,9 @@ def _getHRefElementValue(self, xml):
return None



class SharingTests(BaseSharingTests):

@inlineCallbacks
def test_upgradeToShare(self):

Expand Down Expand Up @@ -928,7 +935,7 @@ def test_POSTDowngradeWithMissingInvitee(self):
))

self.directory.destroyRecord("users", "user02")
self.patch(FakePrincipal, "invalid_names", set(("user02",)))
self.patch(FakePrincipal, "missing_names", set(("user02",)))
yield self.resource.downgradeFromShare(norequest())


Expand Down Expand Up @@ -959,7 +966,7 @@ def test_POSTRemoveWithMissingInvitee(self):
))

self.directory.destroyRecord("users", "user02")
self.patch(FakePrincipal, "invalid_names", set(("user02",)))
self.patch(FakePrincipal, "missing_names", set(("user02",)))

yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
Expand Down Expand Up @@ -1075,7 +1082,7 @@ def test_POSTShareeRemoveWithMissingSharer(self):
href = self._getHRefElementValue(result) + "/"

self.directory.destroyRecord("users", "user01")
self.patch(FakePrincipal, "invalid_names", set(("user01",)))
self.patch(FakePrincipal, "missing_names", set(("user01",)))

resource = (yield self._getResourceSharer(href))
yield resource.removeShareeResource(SimpleStoreRequest(self, "DELETE", href))
Expand Down Expand Up @@ -1112,7 +1119,7 @@ def test_POSTShareeAcceptNewWithMissingSharer(self):
))

self.directory.destroyRecord("users", "user01")
self.patch(FakePrincipal, "invalid_names", set(("user01",)))
self.patch(FakePrincipal, "missing_names", set(("user01",)))

yield self._doPOSTSharerAccept("""<?xml version='1.0' encoding='UTF-8'?>
<invite-reply xmlns='http://calendarserver.org/ns/'>
Expand Down Expand Up @@ -1199,7 +1206,7 @@ def test_POSTShareeAcceptExistingWithMissingSharer(self):
))

self.directory.destroyRecord("users", "user01")
self.patch(FakePrincipal, "invalid_names", set(("user01",)))
self.patch(FakePrincipal, "missing_names", set(("user01",)))

yield self._doPOSTSharerAccept("""<?xml version='1.0' encoding='UTF-8'?>
<invite-reply xmlns='http://calendarserver.org/ns/'>
Expand Down Expand Up @@ -1247,7 +1254,7 @@ def test_POSTShareeDeclineNewWithMissingSharer(self):
))

self.directory.destroyRecord("users", "user01")
self.patch(FakePrincipal, "invalid_names", set(("user01",)))
self.patch(FakePrincipal, "missing_names", set(("user01",)))

yield self._doPOSTSharerAccept("""<?xml version='1.0' encoding='UTF-8'?>
<invite-reply xmlns='http://calendarserver.org/ns/'>
Expand Down Expand Up @@ -1334,7 +1341,7 @@ def test_POSTShareeDeclineExistingWithMissingSharer(self):
))

self.directory.destroyRecord("users", "user01")
self.patch(FakePrincipal, "invalid_names", set(("user01",)))
self.patch(FakePrincipal, "missing_names", set(("user01",)))

yield self._doPOSTSharerAccept("""<?xml version='1.0' encoding='UTF-8'?>
<invite-reply xmlns='http://calendarserver.org/ns/'>
Expand Down Expand Up @@ -1454,7 +1461,7 @@ def test_shareeInviteWithMissingSharer(self):
href = self._getHRefElementValue(result) + "/"

self.directory.destroyRecord("users", "user01")
self.patch(FakePrincipal, "invalid_names", set(("user01",)))
self.patch(FakePrincipal, "missing_names", set(("user01",)))

data = yield self._doPROPFINDHome()
self.assertTrue(data is not None)
Expand Down Expand Up @@ -1557,3 +1564,156 @@ def test_hideInvalidSharers(self):
customxml.InviteStatusAccepted(),
),
))



class DropboxSharingTests(BaseSharingTests):

def configure(self):
"""
Override configuration hook to turn on dropbox.
"""
super(DropboxSharingTests, self).configure()
self.patch(config, "EnableDropBox", True)
self.patch(config, "EnableManagedAttachments", False)


@inlineCallbacks
def test_dropboxWithMissingInvitee(self):

yield self.resource.upgradeToShare()

yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
<CS:set>
<D:href>mailto:user02@example.com</D:href>
<CS:summary>My Shared Calendar</CS:summary>
<CS:read-write/>
</CS:set>
</CS:share>
""")

propInvite = (yield self.resource.readProperty(customxml.Invite, None))
uid = self._getUIDElementValue(propInvite)

yield self._doPOSTSharerAccept("""<?xml version='1.0' encoding='UTF-8'?>
<invite-reply xmlns='http://calendarserver.org/ns/'>
<href xmlns='DAV:'>mailto:user01@example.com</href>
<invite-accepted/>
<hosturl>
<href xmlns='DAV:'>/calendars/__uids__/user01/calendar/</href>
</hosturl>
<in-reply-to>%s</in-reply-to>
<summary>The Shared Calendar</summary>
<common-name>User 02</common-name>
<first-name>user</first-name>
<last-name>02</last-name>
</invite-reply>
""" % (uid,)
)

calendar = yield self.calendarUnderTest(name="calendar", home="user01")
component = Component.fromString("""BEGIN:VCALENDAR
CALSCALE:GREGORIAN
PRODID:-//Example Inc.//Example Calendar//EN
VERSION:2.0
BEGIN:VEVENT
DTSTAMP:20051222T205953Z
CREATED:20060101T150000Z
DTSTART:20060101T100000Z
DURATION:PT1H
SUMMARY:event 1
UID:event1@ninevah.local
ATTACH;VALUE=URI:/calendars/users/home1/some-dropbox-id/some-dropbox-id/caldavd.plist
X-APPLE-DROPBOX:/calendars/users/home1/dropbox/some-dropbox-id
END:VEVENT
END:VCALENDAR
""")
yield calendar.createCalendarObjectWithName("dropbox.ics", component)
yield self.commit()

self.directory.destroyRecord("users", "user02")
self.patch(FakePrincipal, "missing_names", set(("user02",)))

# Get dropbox and test ACLs
request = SimpleStoreRequest(self, "GET", "/calendars/__uids__/user01/dropbox/some-dropbox-id/")
resource = yield request.locateResource("/calendars/__uids__/user01/dropbox/some-dropbox-id/")
acl = yield resource.accessControlList(request)
self.assertTrue(acl is not None)



class MamnagedAttachmentSharingTests(BaseSharingTests):

def configure(self):
"""
Override configuration hook to turn on managed attachments.
"""
super(MamnagedAttachmentSharingTests, self).configure()
self.patch(config, "EnableDropBox", False)
self.patch(config, "EnableManagedAttachments", True)


@inlineCallbacks
def test_attachmentWithMissingInvitee(self):

yield self.resource.upgradeToShare()

yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
<CS:set>
<D:href>mailto:user02@example.com</D:href>
<CS:summary>My Shared Calendar</CS:summary>
<CS:read-write/>
</CS:set>
</CS:share>
""")

propInvite = (yield self.resource.readProperty(customxml.Invite, None))
uid = self._getUIDElementValue(propInvite)

yield self._doPOSTSharerAccept("""<?xml version='1.0' encoding='UTF-8'?>
<invite-reply xmlns='http://calendarserver.org/ns/'>
<href xmlns='DAV:'>mailto:user01@example.com</href>
<invite-accepted/>
<hosturl>
<href xmlns='DAV:'>/calendars/__uids__/user01/calendar/</href>
</hosturl>
<in-reply-to>%s</in-reply-to>
<summary>The Shared Calendar</summary>
<common-name>User 02</common-name>
<first-name>user</first-name>
<last-name>02</last-name>
</invite-reply>
""" % (uid,)
)

calendar = yield self.calendarUnderTest(name="calendar", home="user01")
component = Component.fromString("""BEGIN:VCALENDAR
CALSCALE:GREGORIAN
PRODID:-//Example Inc.//Example Calendar//EN
VERSION:2.0
BEGIN:VEVENT
DTSTAMP:20051222T205953Z
CREATED:20060101T150000Z
DTSTART:20060101T100000Z
DURATION:PT1H
SUMMARY:event 1
UID:event1@ninevah.local
END:VEVENT
END:VCALENDAR
""")
obj = yield calendar.createCalendarObjectWithName("dropbox.ics", component)
_ignore_attachment, location = yield obj.addAttachment(None, MimeType("text", "plain"), "new.txt", MemoryStream("new attachment text"))
yield self.commit()

self.directory.destroyRecord("users", "user02")
self.patch(FakePrincipal, "missing_names", set(("user02",)))

# Get dropbox and test ACLs
location = urlparse.urlparse(location)[2]
location = "/".join(location.split("/")[:-1])
request = SimpleStoreRequest(self, "GET", location)
resource = yield request.locateResource(location)
acl = yield resource.accessControlList(request)
self.assertTrue(acl is not None)

0 comments on commit 7310b47

Please sign in to comment.