diff --git a/ChangeLog b/ChangeLog index 73d7ac1ca..ffdb51e37 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2010-02-02 Wolfgang Sourdeau + + * SoObjects/Appointments/SOGoAppointmentObject.m + (+webdavAclManager): view-whole-component and view-date-and-time + are now independent and children of "all". "read" is declared as + equivalent to the new "SOGoDAVReadPermission". This hack avoids + problems with ACL hierarchy. + + * Tests/Integration/test-davacl.py (DAVCalendarAclTest._putTask): + new method that create tasks in the test collection based on a + template. + (DAVCalendarAclTest._currentUserPrivilegeSet): new method that + request the {DAV:}current-user-privilege-set property on the + specified DAV resource. Also checks whether the request expectedly + fails or succeeds. + (DAVCalendarAclTest._comparePrivilegeSets): new helper method to + compare to arrays. + (DAVCalendarAclTest._testCollectionDAVAcl): new test helper method + for ensure that DAV permissions are conform to the SOGo + permissions on collections. + (DAVCalendarAclTest._testEventDAVAcl): same as above for events. + 2010-01-30 Wolfgang Sourdeau * SoObjects/SOGo/SOGoWebAuthenticator.h: conforms to diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 0fd78abe6..2c0eb25b5 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -107,121 +107,122 @@ static NSNumber *sharedYes = nil; aclManager = [SOGoWebDAVAclManager new]; [aclManager registerDAVPermission: davElement (@"read", XMLNS_WEBDAV) - abstract: YES - withEquivalent: SoPerm_WebDAVAccess - asChildOf: davElement (@"all", XMLNS_WEBDAV)]; - [aclManager registerDAVPermission: davElement (@"read-current-user-privilege-set", XMLNS_WEBDAV) - abstract: YES - withEquivalent: SoPerm_WebDAVAccess - asChildOf: davElement (@"read", XMLNS_WEBDAV)]; + abstract: YES + withEquivalent: SoPerm_WebDAVAccess + asChildOf: davElement (@"all", XMLNS_WEBDAV)]; + [aclManager + registerDAVPermission: davElement (@"read-current-user-privilege-set", XMLNS_WEBDAV) + abstract: YES + withEquivalent: SoPerm_WebDAVAccess + asChildOf: davElement (@"read", XMLNS_WEBDAV)]; [aclManager registerDAVPermission: davElement (@"read-free-busy", XMLNS_CALDAV) - abstract: NO - withEquivalent: SOGoCalendarPerm_ReadFreeBusy - asChildOf: davElement (@"read", XMLNS_WEBDAV)]; + abstract: NO + withEquivalent: SOGoCalendarPerm_ReadFreeBusy + asChildOf: davElement (@"all", XMLNS_WEBDAV)]; [aclManager registerDAVPermission: davElement (@"write", XMLNS_WEBDAV) - abstract: YES - withEquivalent: nil - asChildOf: davElement (@"all", XMLNS_WEBDAV)]; + abstract: YES + withEquivalent: nil + asChildOf: davElement (@"all", XMLNS_WEBDAV)]; [aclManager registerDAVPermission: davElement (@"bind", XMLNS_WEBDAV) - abstract: NO - withEquivalent: SoPerm_AddDocumentsImagesAndFiles - asChildOf: davElement (@"write", XMLNS_WEBDAV)]; + abstract: NO + withEquivalent: SoPerm_AddDocumentsImagesAndFiles + asChildOf: davElement (@"write", XMLNS_WEBDAV)]; [aclManager registerDAVPermission: davElement (@"schedule", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"bind", XMLNS_WEBDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"bind", XMLNS_WEBDAV)]; [aclManager registerDAVPermission: davElement (@"schedule-post", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"schedule", XMLNS_CALDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule", XMLNS_CALDAV)]; [aclManager registerDAVPermission: davElement (@"schedule-post-vevent", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"schedule-post", XMLNS_CALDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-post", XMLNS_CALDAV)]; [aclManager registerDAVPermission: davElement (@"schedule-post-vtodo", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"schedule-post", XMLNS_CALDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-post", XMLNS_CALDAV)]; [aclManager registerDAVPermission: davElement (@"schedule-post-vjournal", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"schedule-post", XMLNS_CALDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-post", XMLNS_CALDAV)]; [aclManager registerDAVPermission: davElement (@"schedule-post-vfreebusy", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"schedule-post", XMLNS_CALDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-post", XMLNS_CALDAV)]; [aclManager registerDAVPermission: davElement (@"schedule-deliver", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"schedule", XMLNS_CALDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule", XMLNS_CALDAV)]; [aclManager registerDAVPermission: davElement (@"schedule-deliver-vevent", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"schedule-deliver", XMLNS_CALDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-deliver", XMLNS_CALDAV)]; [aclManager registerDAVPermission: davElement (@"schedule-deliver-vtodo", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"schedule-deliver", XMLNS_CALDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-deliver", XMLNS_CALDAV)]; [aclManager registerDAVPermission: davElement (@"schedule-deliver-vjournal", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"schedule-deliver", XMLNS_CALDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-deliver", XMLNS_CALDAV)]; [aclManager registerDAVPermission: davElement (@"schedule-deliver-vfreebusy", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"schedule-deliver", XMLNS_CALDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-deliver", XMLNS_CALDAV)]; [aclManager registerDAVPermission: davElement (@"schedule-respond", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"schedule", XMLNS_CALDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule", XMLNS_CALDAV)]; [aclManager registerDAVPermission: davElement (@"schedule-respond-vevent", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"schedule-respond", XMLNS_CALDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-respond", XMLNS_CALDAV)]; [aclManager registerDAVPermission: davElement (@"schedule-respond-vtodo", XMLNS_CALDAV) - abstract: NO - withEquivalent: nil - asChildOf: davElement (@"schedule-respond", XMLNS_CALDAV)]; + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-respond", XMLNS_CALDAV)]; [aclManager registerDAVPermission: davElement (@"unbind", XMLNS_WEBDAV) - abstract: NO - withEquivalent: SoPerm_DeleteObjects - asChildOf: davElement (@"write", XMLNS_WEBDAV)]; + abstract: NO + withEquivalent: SoPerm_DeleteObjects + asChildOf: davElement (@"write", XMLNS_WEBDAV)]; [aclManager registerDAVPermission: davElement (@"write-properties", XMLNS_WEBDAV) - abstract: NO - withEquivalent: SoPerm_ChangePermissions /* hackish */ - asChildOf: davElement (@"write", XMLNS_WEBDAV)]; + abstract: NO + withEquivalent: SoPerm_ChangePermissions /* hackish */ + asChildOf: davElement (@"write", XMLNS_WEBDAV)]; [aclManager registerDAVPermission: davElement (@"write-content", XMLNS_WEBDAV) - abstract: NO - withEquivalent: SoPerm_AddDocumentsImagesAndFiles - asChildOf: davElement (@"write", XMLNS_WEBDAV)]; + abstract: NO + withEquivalent: SoPerm_AddDocumentsImagesAndFiles + asChildOf: davElement (@"write", XMLNS_WEBDAV)]; [aclManager registerDAVPermission: davElement (@"admin", nsI) - abstract: YES - withEquivalent: nil - asChildOf: davElement (@"all", XMLNS_WEBDAV)]; + abstract: YES + withEquivalent: nil + asChildOf: davElement (@"all", XMLNS_WEBDAV)]; [aclManager registerDAVPermission: davElement (@"read-acl", XMLNS_WEBDAV) - abstract: YES - withEquivalent: SOGoPerm_ReadAcls - asChildOf: davElement (@"admin", nsI)]; + abstract: YES + withEquivalent: SOGoPerm_ReadAcls + asChildOf: davElement (@"admin", nsI)]; [aclManager registerDAVPermission: davElement (@"write-acl", XMLNS_WEBDAV) - abstract: YES - withEquivalent: SoPerm_ChangePermissions - asChildOf: davElement (@"admin", nsI)]; + abstract: YES + withEquivalent: SoPerm_ChangePermissions + asChildOf: davElement (@"admin", nsI)]; } return aclManager; diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index d412e6a6b..da903985c 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -72,24 +72,25 @@ nsI = @"urn:inverse:params:xml:ns:inverse-dav"; aclManager = [SOGoWebDAVAclManager new]; + [aclManager registerDAVPermission: davElement (@"read", nsD) - abstract: YES - withEquivalent: nil + abstract: NO + withEquivalent: @"SOGoDAVReadPermission" /* hackish */ asChildOf: davElement (@"all", nsD)]; - [aclManager registerDAVPermission: davElement (@"read-current-user-privilege-set", nsD) - abstract: YES - withEquivalent: SoPerm_WebDAVAccess - asChildOf: davElement (@"read", nsD)]; [aclManager registerDAVPermission: davElement (@"view-whole-component", nsI) abstract: NO withEquivalent: SOGoCalendarPerm_ViewAllComponent - asChildOf: davElement (@"read", nsD)]; + asChildOf: davElement (@"all", nsD)]; [aclManager registerDAVPermission: davElement (@"view-date-and-time", nsI) abstract: NO withEquivalent: SOGoCalendarPerm_ViewDAndT - asChildOf: davElement (@"view-whole-component", nsI)]; + asChildOf: davElement (@"all", nsD)]; + [aclManager registerDAVPermission: davElement (@"read-current-user-privilege-set", nsD) + abstract: NO + withEquivalent: SoPerm_WebDAVAccess + asChildOf: davElement (@"all", nsD)]; [aclManager registerDAVPermission: davElement (@"write", nsD) - abstract: YES + abstract: NO withEquivalent: SOGoCalendarPerm_ModifyComponent asChildOf: davElement (@"all", nsD)]; [aclManager diff --git a/SoObjects/Appointments/product.plist b/SoObjects/Appointments/product.plist index 5dcbe09f1..22df3dfcd 100644 --- a/SoObjects/Appointments/product.plist +++ b/SoObjects/Appointments/product.plist @@ -33,8 +33,8 @@ SOGoAppointmentFolder = { superclass = "SOGoGCSFolder"; defaultRoles = { - "Read FreeBusy" = ( "Authenticated" ); - "Access Contents Information" = ( "Owner", "PublicResponder", "PublicModifier", "PublicViewer", "PublicDAndTViewer", "PrivateResponder", "PrivateModifier", "PrivateViewer", "PrivateDAndTViewer", "ConfidentialResponder", "ConfidentialModifier", "ConfidentialViewer", "ConfidentialDAndTViewer" ); + "Read FreeBusy" = ( "Owner", "AuthorizedSubscriber", "ObjectEraser" ); + "Access Contents Information" = ( "Owner", "PublicResponder", "PublicModifier", "PublicViewer", "PublicDAndTViewer", "PrivateResponder", "PrivateModifier", "PrivateViewer", "PrivateDAndTViewer", "ConfidentialResponder", "ConfidentialModifier", "ConfidentialViewer", "ConfidentialDAndTViewer", "AuthorizedSubscriber" ); "ViewWholePublicRecords" = ( "Owner", "PublicResponder", "PublicModifier", "PublicViewer" ); "ViewDAndTOfPublicRecords" = ( "Owner", "PublicDAndTViewer" ); "ModifyPublicRecords" = ( "Owner", "PublicModifier" ); @@ -58,14 +58,15 @@ SOGoCalendarComponent = { superclass = "SOGoContentObject"; defaultRoles = { - "ViewAllComponent" = ( "Owner", "Organizer", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer" ); - "ViewDAndT" = ( "Organizer", "Participant", "ComponentDAndTViewer" ); + "SOGoDAVReadPermission" = ( "Owner", "ComponentDAndTViewer", "ComponentViewer", "ComponentResponder", "ComponentModifier" ); + "ViewDAndT" = ( "Owner", "ComponentDAndTViewer", "ComponentViewer", "ComponentResponder", "ComponentModifier", "ObjectEditor" ); + "ViewAllComponent" = ( "Owner", "ComponentViewer", "ComponentResponder", "ComponentModifier", "ObjectEditor" ); + "RespondToComponent" = ( "Owner", "ComponentResponder", "ComponentModifier", "ObjectEditor" ); "ModifyComponent" = ( "Owner", "ComponentModifier", "ObjectEditor" ); - "RespondToComponent" = ( "Owner", "ComponentModifier", "ComponentResponder" ); - "Access Object" = ( "Owner", "Organizer", "ObjectCreator", "ObjectEraser", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" ); - "Change Images and Files" = ( "Owner", "Organizer", "ComponentModifier", "ComponentResponder", "ObjectEditor" ); - "Access Contents Information" = ( "Owner", "Organizer", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" ); - "WebDAV Access" = ( "Owner", "Organizer", "ObjectCreator", "ObjectEraser", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" ); + "Access Object" = ( "Owner", "ObjectCreator", "ObjectEraser", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" ); + "Change Images and Files" = ( "Owner", "ComponentModifier", "ComponentResponder", "ObjectEditor" ); + "Access Contents Information" = ( "Owner", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" ); + "WebDAV Access" = ( "Owner", "ObjectCreator", "ObjectEraser", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" ); }; }; SOGoAppointmentObject = { @@ -78,14 +79,15 @@ superclass = "SOGoObject"; protectedBy = "Access Object"; defaultRoles = { - "ViewAllComponent" = ( "Owner", "Organizer", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer" ); - "ViewDAndT" = ( "Organizer", "Participant", "ComponentDAndTViewer" ); + "SOGoDAVReadPermission" = ( "Owner", "ComponentDAndTViewer", "ComponentViewer", "ComponentResponder", "ComponentModifier" ); + "ViewDAndT" = ( "Owner", "ComponentDAndTViewer", "ComponentViewer", "ComponentResponder", "ComponentModifier" ); + "ViewAllComponent" = ( "Owner", "ComponentViewer", "ComponentResponder", "ComponentModifier" ); + "RespondToComponent" = ( "Owner", "ComponentResponder", "ComponentModifier" ); "ModifyComponent" = ( "Owner", "ComponentModifier" ); - "RespondToComponent" = ( "Participant", "ComponentModifier", "ComponentResponder" ); - "Access Object" = ( "Owner", "Organizer", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" ); - "Change Images and Files" = ( "Owner", "Organizer", "ComponentModifier", "ComponentResponder" ); - "Access Contents Information" = ( "Owner", "Organizer", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" ); - "WebDAV Access" = ( "Owner", "Organizer", "Participant", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" ); + "Access Object" = ( "Owner", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" ); + "Change Images and Files" = ( "Owner", "ComponentModifier", "ComponentResponder" ); + "Access Contents Information" = ( "Owner", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" ); + "WebDAV Access" = ( "Owner", "ComponentModifier", "ComponentResponder", "ComponentViewer", "ComponentDAndTViewer" ); }; }; SOGoAppointmentOccurence = { diff --git a/Tests/Integration/test-davacl.py b/Tests/Integration/test-davacl.py index 932572487..450da33d9 100755 --- a/Tests/Integration/test-davacl.py +++ b/Tests/Integration/test-davacl.py @@ -80,6 +80,22 @@ DTSTAMP:20090805T100000Z END:VEVENT END:VCALENDAR""" +task_template = """BEGIN:VCALENDAR +PRODID:-//Inverse//Event Generator//EN +VERSION:2.0 +BEGIN:VTODO +CREATED:20100122T201440Z +LAST-MODIFIED:20100201T175246Z +DTSTAMP:20100201T175246Z +UID:12345-%(class)s-%(filename)s +SUMMARY:%(class)s event (orig. title) +CLASS:%(class)s +DESCRIPTION:%(class)s description +STATUS:IN-PROCESS +PERCENT-COMPLETE:0 +END:VTODO +END:VCALENDAR""" + class DAVCalendarAclTest(DAVAclTest): resource = '/SOGo/dav/%s/Calendar/test-dav-acl/' % username user_email = None @@ -95,9 +111,12 @@ class DAVCalendarAclTest(DAVAclTest): self.classToICSClass = { "pu": "PUBLIC", "pr": "PRIVATE", "co": "CONFIDENTIAL" } - self._putEvent(self.client, "public.ics", "PUBLIC") - self._putEvent(self.client, "private.ics", "PRIVATE") - self._putEvent(self.client, "confidential.ics", "CONFIDENTIAL") + self._putEvent(self.client, "public-event.ics", "PUBLIC") + self._putEvent(self.client, "private-event.ics", "PRIVATE") + self._putEvent(self.client, "confidential-event.ics", "CONFIDENTIAL") + self._putTask(self.client, "public-task.ics", "PUBLIC") + self._putTask(self.client, "private-task.ics", "PRIVATE") + self._putTask(self.client, "confidential-task.ics", "CONFIDENTIAL") def testViewAllPublic(self): """'view all' on a specific class (PUBLIC)""" @@ -153,6 +172,20 @@ class DAVCalendarAclTest(DAVAclTest): " expected status code '%d' (received '%d')" % (filename, exp_status, put.response["status"])) + def _putTask(self, client, filename, + task_class = "PUBLIC", + exp_status = 201): + url = "%s%s" % (self.resource, filename) + task = task_template % { "class": task_class, + "filename": filename } + put = webdavlib.HTTPPUT(url, task) + put.content_type = "text/calendar; charset=utf-8" + client.execute(put) + self.assertEquals(put.response["status"], exp_status, + "%s: task creation/modification:" + " expected status code '%d' (received '%d')" + % (filename, exp_status, put.response["status"])) + def _deleteEvent(self, client, filename, exp_status = 204): url = "%s%s" % (self.resource, filename) delete = webdavlib.WebDAVDELETE(url) @@ -162,9 +195,109 @@ class DAVCalendarAclTest(DAVAclTest): " (received '%d')" % (filename, exp_status, delete.response["status"])) + def _currentUserPrivilegeSet(self, resource, expectFailure = False): + propfind = webdavlib.WebDAVPROPFIND(resource, + ["{DAV:}current-user-privilege-set"], + 0) + self.subscriber_client.execute(propfind) + if expectFailure: + expStatus = 403 + else: + expStatus = 207 + self.assertEquals(propfind.response["status"], expStatus, + "unexected status code when reading privileges:" + + " %s instead of %d" + % (propfind.response["status"], expStatus)) + + privileges = [] + if not expectFailure: + propfind.xpath_namespace = { "D": "DAV:" } + response_nodes = propfind.xpath_evaluate("/D:multistatus/D:response/D:propstat/D:prop/D:current-user-privilege-set/D:privilege") + for node in response_nodes: + privilegeNode = node.childNodes[0] + tagName = privilegeNode.tagName + indexColon = tagName.find(":") + if indexColon > -1: + tagName = tagName[indexColon+1:] + privileges.append("{%s}%s" % (privilegeNode.namespaceURI, tagName)) + + return privileges + + def _comparePrivilegeSets(self, expectedPrivileges, privileges): + testHash = dict(map(lambda x: (x, True), privileges)) + for privilege in expectedPrivileges: + self.assertTrue(testHash.has_key(privilege), + "expected privilege '%s' not found" % privilege) + testHash = dict(map(lambda x: (x, True), expectedPrivileges)) + for privilege in privileges: + self.assertTrue(testHash.has_key(privilege), + "excessive privilege '%s' found" % privilege) + + def _testCollectionDAVAcl(self, rights): + if len(rights) > 0: + expectedPrivileges = ['{DAV:}read', + '{DAV:}read-current-user-privilege-set', + '{urn:ietf:params:xml:ns:caldav}read-free-busy'] + else: + expectedPrivileges = [] + if rights.has_key("c"): + extraPrivileges = ["{DAV:}bind", + "{DAV:}write-content", + '{urn:ietf:params:xml:ns:caldav}schedule', + '{urn:ietf:params:xml:ns:caldav}schedule-post', + '{urn:ietf:params:xml:ns:caldav}schedule-post-vevent', + '{urn:ietf:params:xml:ns:caldav}schedule-post-vtodo', + '{urn:ietf:params:xml:ns:caldav}schedule-post-vjournal', + '{urn:ietf:params:xml:ns:caldav}schedule-post-vfreebusy', + '{urn:ietf:params:xml:ns:caldav}schedule-deliver', + '{urn:ietf:params:xml:ns:caldav}schedule-deliver-vevent', + '{urn:ietf:params:xml:ns:caldav}schedule-deliver-vtodo', + '{urn:ietf:params:xml:ns:caldav}schedule-deliver-vjournal', + '{urn:ietf:params:xml:ns:caldav}schedule-deliver-vfreebusy', + '{urn:ietf:params:xml:ns:caldav}schedule-respond', + '{urn:ietf:params:xml:ns:caldav}schedule-respond-vevent', + '{urn:ietf:params:xml:ns:caldav}schedule-respond-vtodo'] + expectedPrivileges.extend(extraPrivileges) + if rights.has_key("d"): + extraPrivileges = ["{DAV:}unbind"] + expectedPrivileges.extend(extraPrivileges) + privileges = self._currentUserPrivilegeSet(self.resource, + len(expectedPrivileges) == 0) + self._comparePrivilegeSets(expectedPrivileges, privileges) + + def _testEventDAVAcl(self, event_class, right): + icsClass = self.classToICSClass[event_class].lower() + filename = "%s-event.ics" % icsClass + url = "%s%s" % (self.resource, filename) + + if right is None: + expectFailure = True + expectedPrivileges = None + else: + expectFailure = False + expectedPrivileges = ['{DAV:}read-current-user-privilege-set', + '{urn:inverse:params:xml:ns:inverse-dav}view-date-and-time', + '{DAV:}read'] + if right != "d": + extraPrivilege = '{urn:inverse:params:xml:ns:inverse-dav}view-whole-component' + expectedPrivileges.append(extraPrivilege) + if right != "v": + extraPrivileges = ['{urn:inverse:params:xml:ns:inverse-dav}respond-to-component', + '{DAV:}write-content'] + expectedPrivileges.extend(extraPrivileges) + if right != "r": + extraPrivileges = ['{DAV:}write-properties', + '{DAV:}write'] + expectedPrivileges.extend(extraPrivileges) + + privileges = self._currentUserPrivilegeSet(url, expectFailure) + if not expectFailure: + self._comparePrivilegeSets(expectedPrivileges, privileges) + def _testRights(self, rights): self.acl_utility.setupRights(subscriber_username, rights) self._testCreate(rights) + self._testCollectionDAVAcl(rights) self._testEventRight("pu", rights) self._testEventRight("pr", rights) self._testEventRight("co", rights) @@ -183,9 +316,11 @@ class DAVCalendarAclTest(DAVAclTest): exp_code = 204 else: exp_code = 403 - self._deleteEvent(self.subscriber_client, "public.ics", exp_code) - self._deleteEvent(self.subscriber_client, "private.ics", exp_code) - self._deleteEvent(self.subscriber_client, "confidential.ics", + self._deleteEvent(self.subscriber_client, "public-event.ics", + exp_code) + self._deleteEvent(self.subscriber_client, "private-event.ics", + exp_code) + self._deleteEvent(self.subscriber_client, "confidential-event.ics", exp_code) def _testEventRight(self, event_class, rights): @@ -205,6 +340,7 @@ class DAVCalendarAclTest(DAVAclTest): self._testModify(event_class, right) self._testRespondTo(event_class, right) + self._testEventDAVAcl(event_class, right) def _getEvent(self, event_class, is_invitation = False): icsClass = self.classToICSClass[event_class] @@ -212,7 +348,7 @@ class DAVCalendarAclTest(DAVAclTest): filename = "invitation-%s" % icsClass.lower() else: filename = "%s" % icsClass.lower() - url = "%s%s.ics" % (self.resource, filename) + url = "%s%s-event.ics" % (self.resource, filename) get = webdavlib.HTTPGET(url) self.subscriber_client.execute(get) @@ -223,6 +359,19 @@ class DAVCalendarAclTest(DAVAclTest): return event + def _getTask(self, task_class): + filename = "%s" % self.classToICSClass[task_class].lower() + url = "%s%s-task.ics" % (self.resource, filename) + get = webdavlib.HTTPGET(url) + self.subscriber_client.execute(get) + + if get.response["status"] == 200: + task = get.response["body"] + else: + task = None + + return task + def _calendarDataInMultistatus(self, query, filename, response_tag = "D:response"): event = None @@ -257,7 +406,7 @@ class DAVCalendarAclTest(DAVAclTest): event = None icsClass = self.classToICSClass[event_class] - filename = "%s.ics" % icsClass.lower() + filename = "%s-event.ics" % icsClass.lower() propfind = webdavlib.WebDAVPROPFIND(self.resource, ["{urn:ietf:params:xml:ns:caldav}calendar-data"], 1) @@ -271,7 +420,7 @@ class DAVCalendarAclTest(DAVAclTest): event = None icsClass = self.classToICSClass[event_class] - url = "%s%s.ics" % (self.resource, icsClass.lower()) + url = "%s%s-event.ics" % (self.resource, icsClass.lower()) multiget = webdavlib.CalDAVCalendarMultiget(self.resource, ["{urn:ietf:params:xml:ns:caldav}calendar-data"], [ url ]) @@ -285,7 +434,7 @@ class DAVCalendarAclTest(DAVAclTest): event = None icsClass = self.classToICSClass[event_class] - url = "%s%s.ics" % (self.resource, icsClass.lower()) + url = "%s%s-event.ics" % (self.resource, icsClass.lower()) sync_query = webdavlib.WebDAVSyncQuery(self.resource, None, ["{urn:ietf:params:xml:ns:caldav}calendar-data"]) self.subscriber_client.execute(sync_query) @@ -307,7 +456,7 @@ class DAVCalendarAclTest(DAVAclTest): if right == "v" or right == "r" or right == "m": icsClass = self.classToICSClass[event_class] complete_event = (event_template % { "class": icsClass, - "filename": "%s.ics" % icsClass.lower(), + "filename": "%s-event.ics" % icsClass.lower(), "organizer_line": "", "attendee_line": ""}) self.assertTrue(event.strip() == complete_event.strip(), @@ -325,7 +474,7 @@ class DAVCalendarAclTest(DAVAclTest): "PRODID": "-//Inverse//Event Generator//EN", "SEQUENCE": "0", "TRANSP": "OPAQUE", - "UID": "12345-%s-%s.ics" % (icsClass, + "UID": "12345-%s-%s-event.ics" % (icsClass, icsClass.lower()), "SUMMARY": "(%s event)" % icsClass.capitalize(), "DTSTART": "20090805T100000Z", @@ -354,13 +503,13 @@ class DAVCalendarAclTest(DAVAclTest): else: exp_code = 403 icsClass = self.classToICSClass[event_class] - filename = "%s.ics" % icsClass.lower() + filename = "%s-event.ics" % icsClass.lower() self._putEvent(self.subscriber_client, filename, icsClass, exp_code) def _testRespondTo(self, event_class, right): icsClass = self.classToICSClass[event_class] - filename = "invitation-%s.ics" % icsClass.lower() + filename = "invitation-%s-event.ics" % icsClass.lower() self._putEvent(self.client, filename, icsClass, 201, "mailto:nobody@somewhere.com", self.user_email, @@ -535,7 +684,7 @@ END:VCARD""" } self._testRights({ "d": True }) def testCreateDelete(self): - """'create' only""" + """'create', 'delete'""" self._testRights({ "c": True, "d": True }) diff --git a/UI/MainUI/product.plist b/UI/MainUI/product.plist index 80ce5f22e..af79789f0 100644 --- a/UI/MainUI/product.plist +++ b/UI/MainUI/product.plist @@ -59,8 +59,8 @@ "Change Images And Files" = ( "Owner", "ObjectEditor", "PROPPATCHer" ); "View" = ( "Owner", "ObjectViewer", "ObjectEditor" ); "Access Object" = ( "Owner", "AuthorizedSubscriber" ); - "Access Contents Information" = ( "Owner", "ObjectViewer", "ObjectEditor" ); - "WebDAV Access" = ( "Owner", "AuthorizedSubscriber" ); + "Access Contents Information" = ( "Owner", "ObjectViewer", "ObjectEditor", "ObjectCreator", "ObjectEraser" ); + "WebDAV Access" = ( "Owner", "AuthorizedSubscriber", "ObjectCreator", "ObjectEraser" ); "Delete Object" = ( "Owner" ); "Delete Objects" = ( "Owner", "ObjectEraser" ); };