[CalendarServer-changes] [5967] CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/ directory
source_changes at macosforge.org
source_changes at macosforge.org
Mon Aug 2 13:52:32 PDT 2010
Revision: 5967
http://trac.macosforge.org/projects/calendarserver/changeset/5967
Author: cdaboo at apple.com
Date: 2010-08-02 13:52:32 -0700 (Mon, 02 Aug 2010)
Log Message:
-----------
Put back ServicesLocator and ResourceInfo stuff for deployment.
Modified Paths:
--------------
CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/appleopendirectory.py
CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/calendaruserproxy.py
CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/directory.py
CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/principal.py
Modified: CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/appleopendirectory.py 2010-08-02 18:12:04 UTC (rev 5966)
+++ CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/appleopendirectory.py 2010-08-02 20:52:32 UTC (rev 5967)
@@ -23,9 +23,12 @@
"OpenDirectoryInitError",
]
+import os
import sys
import signal
+from xml.parsers.expat import ExpatError
+
import opendirectory
import dsattributes
import dsquery
@@ -50,6 +53,8 @@
from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord
from twistedcaldav.directory.directory import DirectoryError, UnknownRecordTypeError
+from plistlib import readPlistFromString, readPlist
+
serverPreferences = '/Library/Preferences/com.apple.servermgr_info.plist'
saclGroup = 'com.apple.access_calendar'
@@ -62,9 +67,11 @@
def __repr__(self):
return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.node)
- def __init__(self, node="/Search", dosetup=True, doreload=True, cacheTimeout=30, signalIntervalSeconds=10, **kwds):
+ def __init__(self, node="/Search", requireComputerRecord=True, dosetup=True, doreload=True, cacheTimeout=30, signalIntervalSeconds=10, **kwds):
"""
@param node: an OpenDirectory node name to bind to.
+ @param requireComputerRecord: C{True} if the directory schema is to be used to determine
+ which calendar users are enabled.
@param dosetup: if C{True} then the directory records are initialized,
if C{False} they are not.
This should only be set to C{False} when doing unit tests.
@@ -78,6 +85,9 @@
self.realmName = node
self.directory = directory
self.node = node
+ self.requireComputerRecord = requireComputerRecord
+ self.computerRecords = {}
+ self.servicetags = set()
self.cacheTimeout = cacheTimeout
self.signalIntervalSeconds = signalIntervalSeconds
self._records = {}
@@ -87,6 +97,21 @@
self.isWorkgroupServer = False
if dosetup:
+ if self.requireComputerRecord:
+ try:
+ self._lookupVHostRecord()
+ except Exception, e:
+ self.log_error("Unable to locate virtual host record: %s" % (e,))
+ raise
+
+ if os.path.exists(serverPreferences):
+ serverInfo = readPlist(serverPreferences)
+
+ self.isWorkgroupServer = serverInfo.get('ServiceConfig', {}).get('IsWorkgroupServer', False)
+
+ if self.isWorkgroupServer:
+ self.log_info("Enabling Workgroup Server compatibility mode")
+
if doreload:
for recordType in self.recordTypes():
self.recordsForType(recordType)
@@ -260,6 +285,195 @@
return self.memcacheClient
+ def _lookupVHostRecord(self):
+ """
+ Get the OD service record for this host.
+ """
+
+ # The server must have been configured with a virtual hostname.
+ vhostname = config.ServerHostName
+ if not vhostname:
+ raise OpenDirectoryInitError(
+ "There is no virtual hostname configured for the server for use with Open Directory (node=%s)"
+ % (self.realmName,)
+ )
+
+ # Find a record in /Computers with an apple-serviceinfo attribute value equal to the virtual hostname
+ # and return some useful attributes.
+ attrs = [
+ dsattributes.kDS1AttrGeneratedUID,
+ dsattributes.kDSNAttrRecordName,
+ dsattributes.kDSNAttrMetaNodeLocation,
+ "dsAttrTypeNative:apple-serviceinfo",
+ ]
+
+ self.log_debug("opendirectory.queryRecordsWithAttribute_list(%r,%r,%r,%r,%r)" % (
+ self.directory,
+ dsquery.match(
+ "dsAttrTypeNative:apple-serviceinfo",
+ vhostname,
+ dsattributes.eDSContains,
+ ).generate(),
+ True, # case insentive for hostnames
+ dsattributes.kDSStdRecordTypeComputers,
+ attrs
+ ))
+ records = opendirectory.queryRecordsWithAttributes_list(
+ self.directory,
+ dsquery.match(
+ "dsAttrTypeNative:apple-serviceinfo",
+ vhostname,
+ dsattributes.eDSContains,
+ ).generate(),
+ True, # case insentive for hostnames
+ dsattributes.kDSStdRecordTypeComputers,
+ attrs
+ )
+ self._parseComputersRecords(records, vhostname)
+
+ def _parseComputersRecords(self, records, vhostname):
+ # Must have some results
+ if len(records) == 0:
+ raise OpenDirectoryInitError(
+ "Open Directory (node=%s) has no /Computers records with a virtual hostname: %s"
+ % (self.realmName, vhostname)
+ )
+
+ # Now find all appropriate records and determine the enabled (only) service tags for each.
+ for recordname, record in records:
+ self._parseServiceInfo(vhostname, recordname, record)
+
+ # Log all the matching records
+ for key, value in self.computerRecords.iteritems():
+ _ignore_recordname, enabled, servicetag = value
+ self.log_info("Matched Directory record: %s with ServicesLocator: %s, state: %s" % (
+ key,
+ servicetag,
+ {True:"enabled", False:"disabled"}[enabled]
+ ))
+
+ # Log all the enabled service tags - or generate an error if there are none
+ if self.servicetags:
+ for tag in self.servicetags:
+ self.log_info("Enabled ServicesLocator: %s" % (tag,))
+ else:
+ raise OpenDirectoryInitError(
+ "Open Directory (node=%s) no /Computers records with an enabled and valid "
+ "calendar service were found matching virtual hostname: %s"
+ % (self.realmName, vhostname)
+ )
+
+ def _parseServiceInfo(self, vhostname, recordname, record):
+
+ # Extract some useful attributes
+ recordguid = record[dsattributes.kDS1AttrGeneratedUID]
+ recordlocation = "%s/Computers/%s" % (record[dsattributes.kDSNAttrMetaNodeLocation], recordname)
+
+ # First check for apple-serviceinfo attribute
+ plist = record.get("dsAttrTypeNative:apple-serviceinfo", None)
+ if not plist:
+ return False
+
+ # Parse the plist and look for our special entry
+ plist = readPlistFromString(plist)
+ vhosts = plist.get("com.apple.macosxserver.virtualhosts", None)
+ if not vhosts:
+ self.log_error(
+ "Open Directory (node=%s) %s record does not have a "
+ "com.apple.macosxserver.virtualhosts in its apple-serviceinfo attribute value"
+ % (self.realmName, recordlocation)
+ )
+ return False
+
+ # Iterate over each vhost and find one that is a calendar service
+ hostguid = None
+ for key, value in vhosts.iteritems():
+ serviceTypes = value.get("serviceType", None)
+ if serviceTypes:
+ for type in serviceTypes:
+ if type == "calendar":
+ hostguid = key
+ break
+
+ if not hostguid:
+ # We can get false positives from the query - we ignore those.
+ return False
+
+ # Get host name
+ hostname = vhosts[hostguid].get("hostname", None)
+ if not hostname:
+ self.log_error(
+ "Open Directory (node=%s) %s record does not have "
+ "any host name in its apple-serviceinfo attribute value"
+ % (self.realmName, recordlocation)
+ )
+ return False
+ if hostname != vhostname:
+ # We can get false positives from the query - we ignore those.
+ return False
+
+ # Get host details. At this point we only check that it is present. We actually
+ # ignore the details themselves (scheme/port) as we use our own config for that.
+ hostdetails = vhosts[hostguid].get("hostDetails", None)
+ if not hostdetails:
+ self.log_error(
+ "Open Directory (node=%s) %s record does not have "
+ "any host details in its apple-serviceinfo attribute value"
+ % (self.realmName, recordlocation)
+ )
+ return False
+
+ # Look at the service data
+ serviceInfos = vhosts[hostguid].get("serviceInfo", None)
+ if not serviceInfos or not serviceInfos.has_key("calendar"):
+ self.log_error(
+ "Open Directory (node=%s) %s record does not have a "
+ "calendar service in its apple-serviceinfo attribute value"
+ % (self.realmName, recordlocation)
+ )
+ return False
+ serviceInfo = serviceInfos["calendar"]
+
+ # Check that this service is enabled
+ enabled = serviceInfo.get("enabled", True)
+
+ # Create the string we will use to match users with accounts on this server
+ servicetag = "%s:%s:calendar" % (recordguid, hostguid)
+
+ self.computerRecords[recordlocation] = (recordname, enabled, servicetag)
+
+ if enabled:
+ self.servicetags.add(servicetag)
+
+ return True
+
+ 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,
@@ -281,7 +495,7 @@
"""
@param recordType: a record type
@return: a dictionary containing all records for the given record
- type. Keys are short names and values are the cooresponding
+ type. Keys are short names and values are the corresponding
OpenDirectoryRecord for the given record type.
"""
return self._storage(recordType)["records"]
@@ -457,7 +671,16 @@
if recordType == DirectoryService.recordType_groups:
groupsForGUID = {}
+ elif recordType in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ proxiesForGUID = {}
+ readOnlyProxiesForGUID = {}
+ def allowForACLs():
+ return recordType in (
+ DirectoryService.recordType_users,
+ DirectoryService.recordType_groups,
+ )
+
def _setFromAttribute(attribute, lower=False):
if attribute:
if isinstance(attribute, str):
@@ -486,7 +709,31 @@
del cuaddrs[cuaddr]
for (recordShortName, value) in results:
+ enabledForCalendaring = True
+ if self.requireComputerRecord:
+ servicesLocators = value.get(dsattributes.kDSNAttrServicesLocator)
+
+ if servicesLocators:
+ if type(servicesLocators) is str:
+ servicesLocators = (servicesLocators,)
+
+ for locator in servicesLocators:
+ if locator in self.servicetags:
+ break
+ else:
+ if allowForACLs():
+ enabledForCalendaring = False
+ else:
+ invalidRecord(recordShortName)
+ continue
+ else:
+ if allowForACLs():
+ enabledForCalendaring = False
+ else:
+ invalidRecord(recordShortName)
+ continue
+
# Now get useful record info.
recordGUID = value.get(dsattributes.kDS1AttrGeneratedUID)
recordFullName = value.get(dsattributes.kDS1AttrDistinguishedName)
@@ -513,6 +760,22 @@
else:
memberGUIDs = ()
+ # Special case for resources and locations
+ autoSchedule = False
+ proxyGUIDs = ()
+ readOnlyProxyGUIDs = ()
+ if recordType in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ resourceInfo = value.get(dsattributes.kDSNAttrResourceInfo)
+ if resourceInfo is not None:
+ try:
+ autoSchedule, proxy, read_only_proxy = self._parseResourceInfo(resourceInfo, recordGUID, recordType, recordShortName)
+ except ValueError:
+ continue
+ if proxy:
+ proxyGUIDs = (proxy,)
+ if read_only_proxy:
+ readOnlyProxyGUIDs = (read_only_proxy,)
+
record = OpenDirectoryRecord(
service = self,
recordType = recordType,
@@ -522,6 +785,8 @@
fullName = recordFullName,
emailAddresses = recordEmailAddresses,
memberGUIDs = memberGUIDs,
+ proxyGUIDs = proxyGUIDs,
+ readOnlyProxyGUIDs = readOnlyProxyGUIDs,
)
# Look up augment information
@@ -529,6 +794,12 @@
# we know it is completing immediately.
d = augment.AugmentService.getAugmentRecord(record.guid, recordType)
d.addCallback(lambda x:record.addAugmentInformation(x))
+
+ # Override based on ServicesLocator and ResourceInfo
+ if not enabledForCalendaring:
+ record.enabledForCalendaring = False
+ if autoSchedule:
+ record.autoSchedule = True
# Check for disabled items
if record.shortName in disabledNames or record.guid in disabledGUIDs:
@@ -557,6 +828,11 @@
if recordType == DirectoryService.recordType_groups:
self._indexGroup(record, record._memberGUIDs, groupsForGUID)
+ # Do proxy indexing if needed
+ elif recordType in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ self._indexGroup(record, record._proxyGUIDs, proxiesForGUID)
+ self._indexGroup(record, record._readOnlyProxyGUIDs, readOnlyProxiesForGUID)
+
#
# Replace the entire cache
#
@@ -574,6 +850,11 @@
if recordType == DirectoryService.recordType_groups:
storage["groupsForGUID"] = groupsForGUID
+ # Add proxy indexing if needed
+ elif recordType in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ storage["proxiesForGUID"] = proxiesForGUID
+ storage["readOnlyProxiesForGUID"] = readOnlyProxiesForGUID
+
self._records[recordType] = storage
self.log_info(
@@ -590,6 +871,7 @@
dsattributes.kDSNAttrMetaNodeLocation,
]
+ query = None
if recordType == DirectoryService.recordType_users:
listRecordType = dsattributes.kDSStdRecordTypeUsers
@@ -600,24 +882,128 @@
elif recordType == DirectoryService.recordType_locations:
listRecordType = dsattributes.kDSStdRecordTypePlaces
+ attrs.append(dsattributes.kDSNAttrResourceInfo)
elif recordType == DirectoryService.recordType_resources:
listRecordType = dsattributes.kDSStdRecordTypeResources
+ attrs.append(dsattributes.kDSNAttrResourceInfo)
else:
raise UnknownRecordTypeError("Unknown Open Directory record type: %s" % (recordType))
+ if self.requireComputerRecord:
+ if self.isWorkgroupServer and recordType == DirectoryService.recordType_users:
+ self.log_debug("opendirectory.queryRecordsWithAttribute_list(%r,%r,%r,%r,%r,%r,%r)" % (
+ self.directory,
+ dsattributes.kDSNAttrRecordName,
+ saclGroup,
+ dsattributes.eDSExact,
+ False,
+ dsattributes.kDSStdRecordTypeGroups,
+ [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups],
+ ))
+ results = opendirectory.queryRecordsWithAttribute_list(
+ self.directory,
+ dsattributes.kDSNAttrRecordName,
+ saclGroup,
+ dsattributes.eDSExact,
+ False,
+ dsattributes.kDSStdRecordTypeGroups,
+ [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups]
+ )
+
+ if len(results) == 1:
+ members = results[0][1].get(dsattributes.kDSNAttrGroupMembers, [])
+ nestedGroups = results[0][1].get(dsattributes.kDSNAttrNestedGroups, [])
+ else:
+ members = []
+ nestedGroups = []
+
+ guidQueries = []
+
+ for GUID in self._expandGroupMembership(members, nestedGroups):
+ guidQueries.append(
+ dsquery.match(dsattributes.kDS1AttrGeneratedUID, GUID, dsattributes.eDSExact)
+ )
+
+ if not guidQueries:
+ self.log_warn("No SACL enabled users found.")
+ return ()
+
+ query = dsquery.expression(dsquery.expression.OR, guidQueries)
+
+ #
+ # For users and groups, we'll load all entries, even if
+ # they don't have a services locator for this server.
+ #
+ elif (
+ recordType != DirectoryService.recordType_users and
+ recordType != DirectoryService.recordType_groups
+ ):
+ tag_queries = []
+
+ for tag in self.servicetags:
+ tag_queries.append(dsquery.match(dsattributes.kDSNAttrServicesLocator, tag, dsattributes.eDSExact))
+
+ if len(tag_queries) == 1:
+ subquery = tag_queries[0]
+ else:
+ subquery = dsquery.expression(dsquery.expression.OR, tag_queries)
+
+ if query is None:
+ query = subquery
+ else:
+ query = dsquery.expression(dsquery.expression.AND, (subquery, query))
+
+ subquery = None
+
try:
- self.log_debug("opendirectory.listAllRecordsWithAttributes_list(%r,%r,%r)" % (
- self.directory,
- listRecordType,
- attrs,
- ))
- results = opendirectory.listAllRecordsWithAttributes_list(
- self.directory,
- listRecordType,
- attrs,
- )
+ if query:
+ if isinstance(query, dsquery.match):
+ self.log_debug("opendirectory.queryRecordsWithAttribute_list(%r,%r,%r,%r,%r,%r,%r)" % (
+ self.directory,
+ query.attribute,
+ query.value,
+ query.matchType,
+ False,
+ listRecordType,
+ attrs,
+ ))
+ results = opendirectory.queryRecordsWithAttribute_list(
+ self.directory,
+ query.attribute,
+ query.value,
+ query.matchType,
+ False,
+ listRecordType,
+ attrs,
+ )
+ else:
+ self.log_debug("opendirectory.queryRecordsWithAttribute_list(%r,%r,%r,%r,%r)" % (
+ self.directory,
+ query.generate(),
+ False,
+ listRecordType,
+ attrs,
+ ))
+ results = opendirectory.queryRecordsWithAttributes_list(
+ self.directory,
+ query.generate(),
+ False,
+ listRecordType,
+ attrs,
+ )
+ else:
+ self.log_debug("opendirectory.listAllRecordsWithAttributes_list(%r,%r,%r)" % (
+ self.directory,
+ listRecordType,
+ attrs,
+ ))
+ results = opendirectory.listAllRecordsWithAttributes_list(
+ self.directory,
+ listRecordType,
+ attrs,
+ )
except opendirectory.ODError, ex:
self.log_error("Open Directory (node=%s) error: %s" % (self.realmName, str(ex)))
raise
@@ -630,7 +1016,7 @@
"""
def __init__(
self, service, recordType, guid, nodeName, shortName, fullName,
- emailAddresses, memberGUIDs,
+ emailAddresses, memberGUIDs, proxyGUIDs, readOnlyProxyGUIDs,
):
super(OpenDirectoryRecord, self).__init__(
service = service,
@@ -642,6 +1028,8 @@
)
self.nodeName = nodeName
self._memberGUIDs = tuple(memberGUIDs)
+ self._proxyGUIDs = tuple(proxyGUIDs)
+ self._readOnlyProxyGUIDs = tuple(readOnlyProxyGUIDs)
def __repr__(self):
if self.service.realmName == self.nodeName:
@@ -671,6 +1059,41 @@
def groups(self):
return self.service.groupsForGUID(self.guid)
+ def proxies(self):
+ if self.recordType not in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ return
+
+ for guid in self._proxyGUIDs:
+ proxyRecord = self.service.recordWithGUID(guid)
+ if proxyRecord is None:
+ self.log_error("No record for proxy in %s with GUID %s" % (self.shortName, guid))
+ else:
+ yield proxyRecord
+
+ def proxyFor(self):
+ result = set()
+ result.update(self.service.proxiesForGUID(DirectoryService.recordType_resources, self.guid))
+ result.update(self.service.proxiesForGUID(DirectoryService.recordType_locations, self.guid))
+ return result
+
+ def readOnlyProxies(self):
+ if self.recordType not in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ return
+
+ for guid in self._readOnlyProxyGUIDs:
+ proxyRecord = self.service.recordWithGUID(guid)
+ if proxyRecord is None:
+ self.log_error("No record for proxy in %s with GUID %s" % (self.shortName, guid))
+ else:
+ yield proxyRecord
+
+ def readOnlyProxyFor(self):
+ result = set()
+ result.update(self.service.readOnlyProxiesForGUID(DirectoryService.recordType_resources, self.guid))
+ result.update(self.service.readOnlyProxiesForGUID(DirectoryService.recordType_locations, self.guid))
+ return result
+
+
def getMemcacheKey(self, shortName):
key = "auth-%s" % (md5(shortName).hexdigest(),)
return key
Modified: CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/calendaruserproxy.py 2010-08-02 18:12:04 UTC (rev 5966)
+++ CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/calendaruserproxy.py 2010-08-02 20:52:32 UTC (rev 5967)
@@ -160,7 +160,15 @@
assert isinstance(property, davxml.WebDAVElement)
if property.qname() == (dav_namespace, "group-member-set"):
- return self.setGroupMemberSet(property, request)
+ if self.hasEditableMembership():
+ return self.setGroupMemberSet(property, request)
+ else:
+ raise HTTPError(
+ StatusResponse(
+ responsecode.FORBIDDEN,
+ "Proxies cannot be changed."
+ )
+ )
return super(CalendarUserProxyPrincipalResource, self).writeProperty(property, request)
@@ -320,28 +328,35 @@
@inlineCallbacks
def _directGroupMembers(self):
- # Get member UIDs from database and map to principal resources
- members = yield self._index().getMembers(self.uid)
- found = []
- missing = []
- for uid in members:
- p = self.pcollection.principalForUID(uid)
- if p:
- found.append(p)
- # Make sure any outstanding deletion timer entries for
- # existing principals are removed
- yield self._index().refreshPrincipal(uid)
+ if self.hasEditableMembership():
+ # Get member UIDs from database and map to principal resources
+ members = yield self._index().getMembers(self.uid)
+ found = []
+ missing = []
+ for uid in members:
+ p = self.pcollection.principalForUID(uid)
+ if p:
+ found.append(p)
+ # Make sure any outstanding deletion timer entries for
+ # existing principals are removed
+ yield self._index().refreshPrincipal(uid)
+ else:
+ missing.append(uid)
+
+ # Clean-up ones that are missing
+ for uid in missing:
+ cacheTimeout = config.DirectoryService.params.get("cacheTimeout", 30) * 60 # in seconds
+
+ yield self._index().removePrincipal(uid, delay=cacheTimeout*2)
+
+ returnValue(found)
+ else:
+ # Fixed proxies
+ if self.proxyType == "calendar-proxy-write":
+ returnValue(self.parent.proxies())
else:
- missing.append(uid)
+ returnValue(self.parent.readOnlyProxies())
- # Clean-up ones that are missing
- for uid in missing:
- cacheTimeout = config.DirectoryService.params.get("cacheTimeout", 30) * 60 # in seconds
-
- yield self._index().removePrincipal(uid, delay=cacheTimeout*2)
-
- returnValue(found)
-
def groupMembers(self):
return self._expandMemberUIDs()
@@ -351,6 +366,9 @@
memberships = yield self._index().getMemberships(self.uid)
returnValue([p for p in [self.pcollection.principalForUID(uid) for uid in memberships] if p])
+ def hasEditableMembership(self):
+ return self.parent.hasEditableProxyMembership()
+
class ProxyDB(AbstractADBAPIDatabase, LoggingMixIn):
"""
A database to maintain calendar user proxy group memberships.
Modified: CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/directory.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/directory.py 2010-08-02 18:12:04 UTC (rev 5966)
+++ CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/directory.py 2010-08-02 20:52:32 UTC (rev 5967)
@@ -245,6 +245,21 @@
def groups(self):
return ()
+ def proxies(self):
+ return ()
+
+ def proxyFor(self):
+ return ()
+
+ def readOnlyProxies(self):
+ return ()
+
+ def readOnlyProxyFor(self):
+ return ()
+
+ def hasEditableProxyMembership(self):
+ return self.recordType in (DirectoryService.recordType_users, DirectoryService.recordType_groups)
+
def verifyCredentials(self, credentials):
return False
Modified: CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/principal.py 2010-08-02 18:12:04 UTC (rev 5966)
+++ CalendarServer/branches/users/wsanchez/deployment/twistedcaldav/directory/principal.py 2010-08-02 20:52:32 UTC (rev 5967)
@@ -534,6 +534,10 @@
groups = self._getRelatives("groups")
if config.EnableProxyPrincipals:
+ # Get any directory specified proxies
+ groups.update(self._getRelatives("proxyFor", proxy='read-write'))
+ groups.update(self._getRelatives("readOnlyProxyFor", proxy='read-only'))
+
# Get proxy group UIDs and map to principal resources
proxies = []
d = waitForDeferred(self._calendar_user_proxy_index().getMemberships(self.principalUID()))
@@ -565,6 +569,13 @@
proxyFors.update(results)
if config.EnableProxyPrincipals:
+ # Get any directory specified proxies
+ if read_write:
+ directoryProxies = self._getRelatives("proxyFor", proxy='read-write')
+ else:
+ directoryProxies = self._getRelatives("readOnlyProxyFor", proxy='read-only')
+ proxyFors.update([subprincipal.parent for subprincipal in directoryProxies])
+
# Get proxy group UIDs and map to principal resources
proxies = []
d = waitForDeferred(self._calendar_user_proxy_index().getMemberships(self.principalUID()))
@@ -712,6 +723,15 @@
def autoSchedule(self):
return self.record.autoSchedule
+ def proxies(self):
+ return self._getRelatives("proxies")
+
+ def readOnlyProxies(self):
+ return self._getRelatives("readOnlyProxies")
+
+ def hasEditableProxyMembership(self):
+ return self.record.hasEditableProxyMembership()
+
def scheduleInbox(self, request):
home = self._calendarHome()
if home is None:
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100802/b58c0671/attachment-0001.html>
More information about the calendarserver-changes
mailing list