merge of '13eac3b68ef15a1ef039875fa0d5b9c4c2662728'
and '4520bccbe080f6685e84dc4ecd3ae2c5d9741940' Monotone-Parent: 13eac3b68ef15a1ef039875fa0d5b9c4c2662728 Monotone-Parent: 4520bccbe080f6685e84dc4ecd3ae2c5d9741940 Monotone-Revision: 1239295b979f0ffa4eaaaac3d20eda7873f1606d Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2010-07-14T22:30:00 Monotone-Branch: ca.inverse.sogo
This commit is contained in:
commit
12ab7913f3
18
ChangeLog
18
ChangeLog
|
@ -1,3 +1,21 @@
|
|||
2010-07-14 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* SoObjects/SOGo/SOGoGCSFolder.m (-aclSQLListingFilter): return an
|
||||
empty string when the active user is a super user.
|
||||
(-initializeQuickTablesAclsInContext:): set
|
||||
"userCanAccessAllObjects" to YES also when the active user is a
|
||||
super user.
|
||||
|
||||
* Tests/Integration/test-davacl.py
|
||||
(DAVCalendarAclTest._testEventIsSecureVersion): accept a differing
|
||||
SUMMARY since it will always change depending on the user's
|
||||
language and is a pain to adapt.
|
||||
(DAVCalendarPublicAclTest.testCollectionAccessNormalUser): added
|
||||
code to accept and handle the XML and ICS calendar variants.
|
||||
(DAVCalendarSuperUserAclTest.__init__): new test access class for
|
||||
ensuring that super users have full, inconditionnal and complete
|
||||
access to simple user's collections
|
||||
|
||||
2010-07-13 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* Tests/Integration/test-put.py: new test module executing X puts
|
||||
|
|
|
@ -594,14 +594,20 @@ static NSArray *childRecordFields = nil;
|
|||
[self _subscriberRenameTo: newName];
|
||||
}
|
||||
|
||||
/* Returns an empty string to indicate that the filter is empty and nil when
|
||||
the query should not even be performed. */
|
||||
- (NSString *) aclSQLListingFilter
|
||||
{
|
||||
NSString *filter, *login;
|
||||
NSArray *roles;
|
||||
SOGoUser *activeUser;
|
||||
|
||||
login = [[context activeUser] login];
|
||||
activeUser = [context activeUser];
|
||||
login = [activeUser login];
|
||||
if (activeUserIsOwner
|
||||
|| [[self ownerInContext: nil] isEqualToString: login])
|
||||
|| [[self ownerInContext: nil] isEqualToString: login]
|
||||
|| ([activeUser respondsToSelector: @selector (isSuperUser)]
|
||||
&& [activeUser isSuperUser]))
|
||||
filter = @"";
|
||||
else
|
||||
{
|
||||
|
@ -613,9 +619,6 @@ static NSArray *childRecordFields = nil;
|
|||
filter = nil;
|
||||
}
|
||||
|
||||
/* An empty string indicates that the filter is empty while a return value
|
||||
of nil indicates that the query should not even be performed. */
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
@ -1349,17 +1352,21 @@ static NSArray *childRecordFields = nil;
|
|||
- (void) initializeQuickTablesAclsInContext: (WOContext *) localContext
|
||||
{
|
||||
NSString *login;
|
||||
SOGoUser *activeUser;
|
||||
|
||||
activeUser = [localContext activeUser];
|
||||
if (activeUserIsOwner)
|
||||
userCanAccessAllObjects = activeUserIsOwner;
|
||||
else
|
||||
{
|
||||
login = [[localContext activeUser] login];
|
||||
login = [activeUser login];
|
||||
/* we only grant "userCanAccessAllObjects" for role "ObjectEraser" and
|
||||
not "ObjectCreator" because the latter doesn't imply we can read
|
||||
properties from subobjects or even know their existence. */
|
||||
userCanAccessAllObjects
|
||||
= [[self ownerInContext: localContext] isEqualToString: login];
|
||||
= ([[self ownerInContext: localContext] isEqualToString: login]
|
||||
|| ([activeUser respondsToSelector: @selector (isSuperUser)]
|
||||
&& [activeUser isSuperUser]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,149 @@ import utilities
|
|||
# originally
|
||||
# - test "current-user-acl-set"
|
||||
|
||||
class DAVCalendarSuperUserAclTest(unittest.TestCase):
|
||||
def __init__(self, arg):
|
||||
self.client = webdavlib.WebDAVClient(hostname, port,
|
||||
username, password)
|
||||
self.resource = "/SOGo/dav/%s/Calendar/test-dav-superuser-acl/" % subscriber_username
|
||||
self.filename = "suevent.ics"
|
||||
self.url = "%s%s" % (self.resource, self.filename)
|
||||
|
||||
unittest.TestCase.__init__(self, arg)
|
||||
|
||||
def setUp(self):
|
||||
delete = webdavlib.WebDAVDELETE(self.resource)
|
||||
self.client.execute(delete)
|
||||
mkcol = webdavlib.WebDAVMKCOL(self.resource)
|
||||
self.client.execute(mkcol)
|
||||
self.assertEquals(mkcol.response["status"], 201,
|
||||
"preparation: failure creating collection"
|
||||
"(code = %d)" % mkcol.response["status"])
|
||||
|
||||
def tearDown(self):
|
||||
delete = webdavlib.WebDAVDELETE(self.resource)
|
||||
self.client.execute(delete)
|
||||
|
||||
def _getEvent(self):
|
||||
get = webdavlib.HTTPGET(self.url)
|
||||
self.client.execute(get)
|
||||
|
||||
if get.response["status"] == 200:
|
||||
event = get.response["body"]
|
||||
else:
|
||||
event = None
|
||||
|
||||
return event
|
||||
|
||||
def _calendarDataInMultistatus(self, query, response_tag = "{DAV:}response"):
|
||||
event = None
|
||||
|
||||
# print "\n\n\n%s\n\n" % query.response["body"]
|
||||
# print "\n\n"
|
||||
response_nodes = query.response["document"].findall(response_tag)
|
||||
for response_node in response_nodes:
|
||||
href_node = response_node.find("{DAV:}href")
|
||||
href = href_node.text
|
||||
if href.endswith(self.filename):
|
||||
propstat_node = response_node.find("{DAV:}propstat")
|
||||
if propstat_node is not None:
|
||||
status_node = propstat_node.find("{DAV:}status")
|
||||
status = status_node.text
|
||||
if status.endswith("200 OK"):
|
||||
data_node = propstat_node.find("{DAV:}prop/{urn:ietf:params:xml:ns:caldav}calendar-data")
|
||||
event = data_node.text
|
||||
elif not (status.endswith("404 Resource Not Found")
|
||||
or status.endswith("404 Not Found")):
|
||||
self.fail("%s: unexpected status code: '%s'"
|
||||
% (self.filename, status))
|
||||
|
||||
return event
|
||||
|
||||
def _propfindEvent(self):
|
||||
propfind = webdavlib.WebDAVPROPFIND(self.resource,
|
||||
["{urn:ietf:params:xml:ns:caldav}calendar-data"],
|
||||
1)
|
||||
self.client.execute(propfind)
|
||||
if propfind.response["status"] != 404:
|
||||
event = self._calendarDataInMultistatus(propfind)
|
||||
|
||||
return event
|
||||
|
||||
def _multigetEvent(self):
|
||||
event = None
|
||||
|
||||
multiget = webdavlib.CalDAVCalendarMultiget(self.resource,
|
||||
["{urn:ietf:params:xml:ns:caldav}calendar-data"],
|
||||
[ self.url ])
|
||||
self.client.execute(multiget)
|
||||
if multiget.response["status"] != 404:
|
||||
event = self._calendarDataInMultistatus(multiget)
|
||||
|
||||
return event
|
||||
|
||||
def _webdavSyncEvent(self):
|
||||
event = None
|
||||
|
||||
sync_query = webdavlib.WebDAVSyncQuery(self.resource, None,
|
||||
["{urn:ietf:params:xml:ns:caldav}calendar-data"])
|
||||
self.client.execute(sync_query)
|
||||
if sync_query.response["status"] != 404:
|
||||
event = self._calendarDataInMultistatus(sync_query, "{DAV:}sync-response")
|
||||
|
||||
return event
|
||||
|
||||
def testSUAccess(self):
|
||||
"""create, read, modify, delete for superuser"""
|
||||
event = event_template % { "class": "PUBLIC",
|
||||
"filename": self.filename,
|
||||
"organizer_line": "",
|
||||
"attendee_line": "" }
|
||||
|
||||
# 1. Create
|
||||
put = webdavlib.HTTPPUT(self.url, event)
|
||||
put.content_type = "text/calendar; charset=utf-8"
|
||||
self.client.execute(put)
|
||||
self.assertEquals(put.response["status"], 201,
|
||||
"%s: event creation/modification:"
|
||||
" expected status code '201' (received '%d')"
|
||||
% (self.filename, put.response["status"]))
|
||||
|
||||
# 2. Read
|
||||
readEvent = self._getEvent()
|
||||
self.assertEquals(readEvent, event,
|
||||
"GET: returned event does not match")
|
||||
readEvent = self._propfindEvent()
|
||||
self.assertEquals(readEvent, event,
|
||||
"PROPFIND: returned event does not match")
|
||||
readEvent = self._multigetEvent()
|
||||
self.assertEquals(readEvent, event,
|
||||
"MULTIGET: returned event does not match")
|
||||
readEvent = self._webdavSyncEvent()
|
||||
self.assertEquals(readEvent, event,
|
||||
"WEBDAV-SYNC: returned event does not match")
|
||||
|
||||
# 3. Modify
|
||||
for eventClass in [ "CONFIDENTIAL", "PRIVATE", "PUBLIC" ]:
|
||||
event = event_template % { "class": eventClass,
|
||||
"filename": self.filename,
|
||||
"organizer_line": "",
|
||||
"attendee_line": "" }
|
||||
put = webdavlib.HTTPPUT(self.url, event)
|
||||
put.content_type = "text/calendar; charset=utf-8"
|
||||
self.client.execute(put)
|
||||
self.assertEquals(put.response["status"], 204,
|
||||
"%s: event modification failed"
|
||||
" expected status code '204' (received '%d')"
|
||||
% (self.filename, put.response["status"]))
|
||||
|
||||
# 4. Delete
|
||||
delete = webdavlib.WebDAVDELETE(self.url)
|
||||
self.client.execute(delete)
|
||||
self.assertEquals(delete.response["status"], 204,
|
||||
"%s: event deletion failed"
|
||||
" expected status code '204' (received '%d')"
|
||||
% (self.filename, put.response["status"]))
|
||||
|
||||
class DAVAclTest(unittest.TestCase):
|
||||
resource = None
|
||||
|
||||
|
@ -484,7 +627,8 @@ class DAVCalendarAclTest(DAVAclTest):
|
|||
for key in event_dict.keys():
|
||||
self.assertTrue(expected_dict.has_key(key),
|
||||
"key '%s' of secure event not expected" % key)
|
||||
self.assertTrue(expected_dict[key] == event_dict[key],
|
||||
self.assertTrue(expected_dict[key] == event_dict[key]
|
||||
or key == "SUMMARY",
|
||||
"value for key '%s' of secure does not match"
|
||||
" (exp: '%s', obtained: '%s'"
|
||||
% (key, expected_dict[key], event_dict[key] ))
|
||||
|
@ -853,13 +997,22 @@ class DAVCalendarPublicAclTest(unittest.TestCase):
|
|||
acl_utility.setupRights(subscriber_username, { "c": True })
|
||||
|
||||
self.subscriber_client.execute(propfind)
|
||||
hrefs = propfind.response["document"] \
|
||||
.findall("{DAV:}response/{DAV:}href")
|
||||
self.assertEquals(len(hrefs), 2, "expected two hrefs in response")
|
||||
hrefs = propfind.response["document"].findall("{DAV:}response/{DAV:}href")
|
||||
self.assertEquals(len(hrefs), 4,
|
||||
"expected 4 hrefs in response, got %d: %s"
|
||||
% (len(hrefs), ", ".join([ x.text for x in hrefs ])))
|
||||
self.assertEquals(hrefs[0].text, parentColl,
|
||||
"the first href is not a 'Calendar' parent coll.")
|
||||
self.assertEquals(hrefs[1].text, resource,
|
||||
"the 2nd href is not the accessible coll.")
|
||||
|
||||
resourceHrefs = { resource: False,
|
||||
"%s.xml" % resource[:-1]: False,
|
||||
"%s.ics" % resource[:-1]: False }
|
||||
for href in hrefs[1:]:
|
||||
self.assertTrue(resourceHrefs.has_key(href.text),
|
||||
"received unexpected href: %s" % href.text)
|
||||
self.assertFalse(resourceHrefs[href.text],
|
||||
"href was returned more than once: %s" % href.text)
|
||||
resourceHrefs[href.text] = True
|
||||
|
||||
acl_utility.setupRights(subscriber_username, {})
|
||||
|
||||
|
@ -870,13 +1023,21 @@ class DAVCalendarPublicAclTest(unittest.TestCase):
|
|||
self.subscriber_client.execute(propfind)
|
||||
hrefs = propfind.response["document"] \
|
||||
.findall("{DAV:}response/{DAV:}href")
|
||||
self.assertEquals(len(hrefs), 2,
|
||||
"expected two hrefs in response: %d received" \
|
||||
% len(hrefs))
|
||||
|
||||
self.assertEquals(len(hrefs), 4,
|
||||
"expected 4 hrefs in response, got %d: %s"
|
||||
% (len(hrefs), ", ".join([ x.text for x in hrefs ])))
|
||||
self.assertEquals(hrefs[0].text, parentColl,
|
||||
"the first href is not a 'Calendar' parent coll.")
|
||||
self.assertEquals(hrefs[1].text, resource,
|
||||
"the 2nd href is not the accessible coll.")
|
||||
resourceHrefs = { resource: False,
|
||||
"%s.xml" % resource[:-1]: False,
|
||||
"%s.ics" % resource[:-1]: False }
|
||||
for href in hrefs[1:]:
|
||||
self.assertTrue(resourceHrefs.has_key(href.text),
|
||||
"received unexpected href: %s" % href.text)
|
||||
self.assertFalse(resourceHrefs[href.text],
|
||||
"href was returned more than once: %s" % href.text)
|
||||
resourceHrefs[href.text] = True
|
||||
|
||||
anonParentColl = '/SOGo/dav/public/%s/Calendar/' % username
|
||||
anon_propfind = webdavlib.WebDAVPROPFIND(anonParentColl,
|
||||
|
@ -898,13 +1059,23 @@ class DAVCalendarPublicAclTest(unittest.TestCase):
|
|||
self.anon_client.execute(anon_propfind)
|
||||
hrefs = anon_propfind.response["document"] \
|
||||
.findall("{DAV:}response/{DAV:}href")
|
||||
self.assertEquals(len(hrefs), 2, "expected 2 hrefs in response")
|
||||
|
||||
|
||||
self.assertEquals(len(hrefs), 4,
|
||||
"expected 4 hrefs in response, got %d: %s"
|
||||
% (len(hrefs), ", ".join([ x.text for x in hrefs ])))
|
||||
self.assertEquals(hrefs[0].text, anonParentColl,
|
||||
"the first href is not a 'Calendar' parent coll.")
|
||||
anonResource = '%stest-dav-acl/' % anonParentColl
|
||||
self.assertEquals(hrefs[1].text, anonResource,
|
||||
"expected href '%s' instead of '%s'."\
|
||||
% (anonResource, hrefs[1].text))
|
||||
resourceHrefs = { anonResource: False,
|
||||
"%s.xml" % anonResource[:-1]: False,
|
||||
"%s.ics" % anonResource[:-1]: False }
|
||||
for href in hrefs[1:]:
|
||||
self.assertTrue(resourceHrefs.has_key(href.text),
|
||||
"received unexpected href: %s" % href.text)
|
||||
self.assertFalse(resourceHrefs[href.text],
|
||||
"href was returned more than once: %s" % href.text)
|
||||
resourceHrefs[href.text] = True
|
||||
|
||||
self.subscriber_client.execute(propfind)
|
||||
hrefs = propfind.response["document"] \
|
||||
|
|
80
Tests/Stress/webdavsync.py
Executable file
80
Tests/Stress/webdavsync.py
Executable file
|
@ -0,0 +1,80 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
from config import hostname, port
|
||||
|
||||
import webdavlib
|
||||
import random
|
||||
import time
|
||||
import threading
|
||||
|
||||
base=1127
|
||||
userscount=100
|
||||
password=""
|
||||
batchcount=10
|
||||
sleeptime=3
|
||||
durationHeader="sogorequestduration"
|
||||
#durationHeader="sogo-request-duration"
|
||||
|
||||
class StressIteration(threading.Thread):
|
||||
def __init__(self, username):
|
||||
threading.Thread.__init__(self)
|
||||
self.username = username
|
||||
self.time = 0.0
|
||||
self.sogoTime = 0.0
|
||||
|
||||
def run(self):
|
||||
client = webdavlib.WebDAVClient(hostname, port,
|
||||
self.username, password)
|
||||
resource = "/SOGo/dav/%s/Calendar/personal/" % self.username
|
||||
startTime = time.time()
|
||||
query = webdavlib.WebDAVSyncQuery(resource, None,
|
||||
[ "getetag", "calendar-data" ])
|
||||
client.execute(query)
|
||||
if query.response["status"] != 207:
|
||||
print "*** received unexpected code: %d (%s)" \
|
||||
% (query.response["status"], resource)
|
||||
endTime = time.time()
|
||||
headers = query.response["headers"]
|
||||
if headers.has_key(durationHeader):
|
||||
self.sogoTime = float(headers[durationHeader])
|
||||
self.time = endTime - startTime
|
||||
# print "%f, %f" % (self.time, self.sogoTime)
|
||||
|
||||
class StressTest:
|
||||
def __init__(self):
|
||||
self.usernames = [ "invite%d" % (base + x)
|
||||
for x in xrange(userscount) ]
|
||||
self.random = random.Random()
|
||||
|
||||
def iteration(self):
|
||||
usernames = self.random.sample(self.usernames, batchcount)
|
||||
startTime = time.time()
|
||||
threads = []
|
||||
for username in usernames:
|
||||
iteration = StressIteration(username)
|
||||
iteration.start()
|
||||
threads.append(iteration)
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
endTime = time.time()
|
||||
|
||||
programTime = endTime - startTime
|
||||
requestsTime = 0.0
|
||||
sogoTime = 0.0
|
||||
for thread in threads:
|
||||
requestsTime = requestsTime + thread.time
|
||||
sogoTime = sogoTime + thread.sogoTime
|
||||
|
||||
print "Iteration time: %f, Total Requests Time: %f, Total SOGo Time: %f" \
|
||||
% (programTime, requestsTime, sogoTime)
|
||||
|
||||
def start(self):
|
||||
while True:
|
||||
self.iteration()
|
||||
time.sleep(sleeptime)
|
||||
|
||||
if __name__ == "__main__":
|
||||
test = StressTest()
|
||||
test.start()
|
2
debian/sogo.docs
vendored
2
debian/sogo.docs
vendored
|
@ -1,4 +1,4 @@
|
|||
NEWS
|
||||
README
|
||||
TODO
|
||||
Scripts/sql-update-1.2.2_to_1.2.3.sh
|
||||
Scripts/sql-update-1.2.2_to_1.3.0.sh
|
||||
|
|
|
@ -188,7 +188,7 @@ rm -fr ${RPM_BUILD_ROOT}
|
|||
|
||||
%config %{_sysconfdir}/httpd/conf.d/SOGo.conf
|
||||
%config %{_sysconfdir}/sysconfig/sogo
|
||||
%doc ChangeLog README NEWS Scripts/sql-update-20070724.sh Scripts/sql-update-20070822.sh Scripts/sql-update-20080303.sh Scripts/sql-update-101_to_102.sh Scripts/sql-update-1.2.2_to_1.2.3.sh
|
||||
%doc ChangeLog README NEWS Scripts/sql-update-20070724.sh Scripts/sql-update-20070822.sh Scripts/sql-update-20080303.sh Scripts/sql-update-101_to_102.sh Scripts/sql-update-1.2.2_to_1.3.0.sh
|
||||
|
||||
%files -n sogo-tool
|
||||
%{prefix}/Tools/Admin/sogo-tool
|
||||
|
|
Loading…
Reference in a new issue