Revision: 3617 http://trac.macosforge.org/projects/calendarserver/changeset/3617 Author: cdaboo@apple.com Date: 2009-01-28 08:47:18 -0800 (Wed, 28 Jan 2009) Log Message: ----------- Redo fix for invalid XML in resourceInfo attribute. Modified Paths: -------------- CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py CalendarServer/trunk/twistedcaldav/directory/test/test_opendirectoryrecords.py CalendarServer/trunk/twistedcaldav/directory/test/test_opendirectoryschema.py Modified: CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py =================================================================== --- CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py 2009-01-28 08:01:06 UTC (rev 3616) +++ CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py 2009-01-28 16:47:18 UTC (rev 3617) @@ -1,5 +1,5 @@ ## -# Copyright (c) 2006-2008 Apple Inc. All rights reserved. +# Copyright (c) 2006-2009 Apple Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -191,6 +191,33 @@ return result + def _parseResourceInfo(self, plist, guid, recordType, shortname): + """ + Parse OD ResourceInfo attribute and extract information that the server needs. + + @param plist: the plist that is the attribute value. + @type plist: str + @param guid: the directory GUID of the record being parsed. + @type guid: str + @param shortname: the record shortname of the record being parsed. + @type shortname: str + @return: a C{tuple} of C{bool} for auto-accept, C{str} for proxy GUID, C{str} for read-only proxy GUID. + """ + try: + plist = readPlistFromString(plist) + wpframework = plist.get("com.apple.WhitePagesFramework", {}) + autoaccept = wpframework.get("AutoAcceptsInvitation", False) + proxy = wpframework.get("CalendaringDelegate", None) + read_only_proxy = wpframework.get("ReadOnlyCalendaringDelegate", None) + except (ExpatError, AttributeError), e: + self.log_error( + "Failed to parse ResourceInfo attribute of record (%s)%s (guid=%s): %s\n%s" % + (recordType, shortname, guid, e, plist,) + ) + raise ValueError("Invalid ResourceInfo") + + return (autoaccept, proxy, read_only_proxy,) + def recordTypes(self): return ( DirectoryService.recordType_users, @@ -528,19 +555,9 @@ resourceInfo = value.get(dsattributes.kDSNAttrResourceInfo) if resourceInfo is not None: try: - plist = readPlistFromString(resourceInfo) - except ExpatError, e: - self.log_error( - "Failed to parse ResourceInfo attribute of record (%s)%s (guid=%s, name=%s): %s\n%s" % - (recordType, recordShortName, recordGUID, recordFullName, e, resourceInfo) - ) + autoSchedule, proxy, read_only_proxy = self._parseResourceInfo(resourceInfo, recordGUID, recordType, recordShortName) + except ValueError: continue - - wpframework = plist.get("com.apple.WhitePagesFramework", {}) - autoSchedule = wpframework.get("AutoAcceptsInvitation", False) - proxy = wpframework.get("CalendaringDelegate", None) - read_only_proxy = wpframework.get("ReadOnlyCalendaringDelegate", None) - if proxy: proxyGUIDs = (proxy,) if read_only_proxy: Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_opendirectoryrecords.py =================================================================== --- CalendarServer/trunk/twistedcaldav/directory/test/test_opendirectoryrecords.py 2009-01-28 08:01:06 UTC (rev 3616) +++ CalendarServer/trunk/twistedcaldav/directory/test/test_opendirectoryrecords.py 2009-01-28 16:47:18 UTC (rev 3617) @@ -608,7 +608,59 @@ self.verifyQuery(self.service.recordWithEmailAddress, "location05@example.com") self.verifyNoQuery(self.service.recordWithEmailAddress, "location05@example.com") -def fakeODRecord(fullName, shortName=None, guid=None, email=None, members=None): + def test_resourceinfo(self): + good_plist = """<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.WhitePagesFramework</key> + <dict> + <key>AutoAcceptsInvitation</key> + <true/> + <key>Label</key> + <string>Location</string> + <key>CalendaringDelegate</key> + <string></string> + <key>ReadOnlyCalendaringDelegate</key> + <string></string> + </dict> +</dict> +</plist> +""" + + bad_plist = """<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.WhitePagesFramework</key> + <string>bogus</string> +</dict> +</plist> +""" + + invalid_xml = """<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.WhitePagesFramework</key> + <string>R&D</string> +</dict> +</plist> +""" + + self.loadRecords({ + DirectoryService.recordType_locations: [ + fakeODRecord("Location 01", resourceInfo=good_plist), + fakeODRecord("Location 02", resourceInfo=bad_plist), + fakeODRecord("Location 03", resourceInfo=invalid_xml), + ], + }) + + self.verifyRecords(DirectoryService.recordType_locations, ("location01",)) + self.verifyDisabledRecords(DirectoryService.recordType_locations, (), ()) + + +def fakeODRecord(fullName, shortName=None, guid=None, email=None, members=None, resourceInfo=None): if shortName is None: shortName = shortNameForFullName(fullName) @@ -630,6 +682,9 @@ if members: attrs[dsattributes.kDSNAttrGroupMembers] = members + if resourceInfo: + attrs[dsattributes.kDSNAttrResourceInfo] = resourceInfo + return [ shortName, attrs ] def shortNameForFullName(fullName): Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_opendirectoryschema.py =================================================================== --- CalendarServer/trunk/twistedcaldav/directory/test/test_opendirectoryschema.py 2009-01-28 08:01:06 UTC (rev 3616) +++ CalendarServer/trunk/twistedcaldav/directory/test/test_opendirectoryschema.py 2009-01-28 16:47:18 UTC (rev 3617) @@ -114,20 +114,34 @@ </plist> """ + plist_invalid_xml = """<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.WhitePagesFramework</key> + <string>R&D</string> +</dict> +</plist> +""" + test_bool = ( - (plist_good_false, False, "1234-GUID-5678", "1234-GUID-5679"), - (plist_good_true, True, "", ""), - (plist_good_missing, False, None, None), - (plist_wrong, False, None, None), - (plist_bad, False, None, None), - (plist_invalid, False, None, None), + (plist_good_false, False, "1234-GUID-5678", "1234-GUID-5679", None), + (plist_good_true, True, "", "", None), + (plist_good_missing, False, None, None, None), + (plist_wrong, False, None, None, None), + (plist_bad, False, None, None, ValueError), + (plist_invalid, False, None, None, ValueError), + (plist_invalid_xml, False, None, None, ValueError), ) def test_plists(self): service = OpenDirectoryService(node="/Search", dosetup=False) for item in ODResourceInfoParse.test_bool: - item1, item2, item3 = service._parseResourceInfo(item[0], "guid", "name") - self.assertEqual(item1, item[1]) - self.assertEqual(item2, item[2]) - self.assertEqual(item3, item[3]) + if item[4] is None: + item1, item2, item3 = service._parseResourceInfo(item[0], "guid", "locations", "name") + self.assertEqual(item1, item[1]) + self.assertEqual(item2, item[2]) + self.assertEqual(item3, item[3]) + else: + self.assertRaises(item[4], service._parseResourceInfo, item[0], "guid", "locations", "name")