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

Commit

Permalink
Allow LDAP config to use multiple LDAP attributes for emailAddresses …
Browse files Browse the repository at this point in the history
…(so that both primary address and email aliases may be used for principal-property-search and faulting in individual records).

git-svn-id: https://svn.calendarserver.org/repository/calendarserver/CalendarServer/trunk@9424 e27351fd-9f3e-4f54-a53b-843176b1656c
  • Loading branch information
m0rgen committed Jul 11, 2012
1 parent a68cd71 commit fcffe3b
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 26 deletions.
8 changes: 6 additions & 2 deletions conf/caldavd-test.plist
Expand Up @@ -267,7 +267,9 @@
<key>fullName</key> <key>fullName</key>
<string>cn</string> <string>cn</string>
<key>emailAddresses</key> <key>emailAddresses</key>
<string>mail</string> <array>
<string>mail</string>
</array>
<key>firstName</key> <key>firstName</key>
<string>givenName</string> <string>givenName</string>
<key>lastName</key> <key>lastName</key>
Expand All @@ -291,7 +293,9 @@
<key>fullName</key> <key>fullName</key>
<string>cn</string> <string>cn</string>
<key>emailAddresses</key> <key>emailAddresses</key>
<string>mail</string> <array>
<string>mail</string>
</array>
<key>firstName</key> <key>firstName</key>
<string>givenName</string> <string>givenName</string>
<key>lastName</key> <key>lastName</key>
Expand Down
53 changes: 40 additions & 13 deletions twistedcaldav/directory/ldapdirectory.py
Expand Up @@ -118,7 +118,7 @@ def __init__(self, params):
"mapping" : { # maps internal record names to LDAP "mapping" : { # maps internal record names to LDAP
"recordName": "uid", "recordName": "uid",
"fullName" : "cn", "fullName" : "cn",
"emailAddresses" : "mail", "emailAddresses" : ["mail"], # multiple LDAP fields supported
"firstName" : "givenName", "firstName" : "givenName",
"lastName" : "sn", "lastName" : "sn",
}, },
Expand All @@ -131,7 +131,7 @@ def __init__(self, params):
"mapping" : { # maps internal record names to LDAP "mapping" : { # maps internal record names to LDAP
"recordName": "cn", "recordName": "cn",
"fullName" : "cn", "fullName" : "cn",
"emailAddresses" : "mail", "emailAddresses" : ["mail"], # multiple LDAP fields supported
"firstName" : "givenName", "firstName" : "givenName",
"lastName" : "sn", "lastName" : "sn",
}, },
Expand All @@ -146,7 +146,7 @@ def __init__(self, params):
"mapping" : { # maps internal record names to LDAP "mapping" : { # maps internal record names to LDAP
"recordName": "cn", "recordName": "cn",
"fullName" : "cn", "fullName" : "cn",
"emailAddresses" : "mail", "emailAddresses" : ["mail"], # multiple LDAP fields supported
"firstName" : "givenName", "firstName" : "givenName",
"lastName" : "sn", "lastName" : "sn",
}, },
Expand All @@ -161,7 +161,7 @@ def __init__(self, params):
"mapping" : { # maps internal record names to LDAP "mapping" : { # maps internal record names to LDAP
"recordName": "cn", "recordName": "cn",
"fullName" : "cn", "fullName" : "cn",
"emailAddresses" : "mail", "emailAddresses" : ["mail"], # multiple LDAP fields supported
"firstName" : "givenName", "firstName" : "givenName",
"lastName" : "sn", "lastName" : "sn",
}, },
Expand Down Expand Up @@ -235,9 +235,14 @@ def __init__(self, params):
attrSet.add(self.rdnSchema[recordType]["attr"]) attrSet.add(self.rdnSchema[recordType]["attr"])
if self.rdnSchema[recordType].get("calendarEnabledAttr", False): if self.rdnSchema[recordType].get("calendarEnabledAttr", False):
attrSet.add(self.rdnSchema[recordType]["calendarEnabledAttr"]) attrSet.add(self.rdnSchema[recordType]["calendarEnabledAttr"])
for attr in self.rdnSchema[recordType]["mapping"].values(): for attrList in self.rdnSchema[recordType]["mapping"].values():
if attr: if attrList:
attrSet.add(attr) # Since emailAddresses can map to multiple LDAP fields,
# support either string or list
if isinstance(attrList, str):
attrList = [attrList]
for attr in attrList:
attrSet.add(attr)
# Also put the guidAttr attribute into the mappings for each type # Also put the guidAttr attribute into the mappings for each type
# so recordsMatchingFields can query on guid # so recordsMatchingFields can query on guid
self.rdnSchema[recordType]["mapping"]["guid"] = self.rdnSchema["guidAttr"] self.rdnSchema[recordType]["mapping"]["guid"] = self.rdnSchema["guidAttr"]
Expand Down Expand Up @@ -646,9 +651,10 @@ def _getMultipleLdapAttributes(self, attrs, *keys):
""" """
results = [] results = []
for key in keys: for key in keys:
values = attrs.get(key) if key:
if values is not None: values = attrs.get(key)
results += values if values is not None:
results += values
return results return results




Expand Down Expand Up @@ -686,7 +692,13 @@ def _ldapResultToRecord(self, dn, attrs, recordType):
raise MissingGuidException() raise MissingGuidException()


# Find or build email # Find or build email
emailAddresses = set(self._getMultipleLdapAttributes(attrs, self.rdnSchema[recordType]["mapping"]["emailAddresses"])) # (The emailAddresses mapping is a list of ldap fields)
emailAddressesMappedTo = self.rdnSchema[recordType]["mapping"]["emailAddresses"]
# Supporting either string or list for emailAddresses:
if isinstance(emailAddressesMappedTo, str):
emailAddresses = set(self._getMultipleLdapAttributes(attrs, self.rdnSchema[recordType]["mapping"]["emailAddresses"]))
else:
emailAddresses = set(self._getMultipleLdapAttributes(attrs, *self.rdnSchema[recordType]["mapping"]["emailAddresses"]))
emailSuffix = self.rdnSchema[recordType]["emailSuffix"] emailSuffix = self.rdnSchema[recordType]["emailSuffix"]


if len(emailAddresses) == 0 and emailSuffix: if len(emailAddresses) == 0 and emailSuffix:
Expand Down Expand Up @@ -885,7 +897,16 @@ def queryDirectory(self, recordTypes, indexType, indexKey):
ldapEsc(email) ldapEsc(email)
) )
else: else:
filterstr = "(&%s(mail=%s))" % (filterstr, ldapEsc(email)) # emailAddresses can map to multiple LDAP fields
ldapFields = self.rdnSchema[recordType]["mapping"]["emailAddresses"]
if isinstance(ldapFields, str):
subfilter = "(%s=%s)" % (ldapFields, ldapEsc(email))
else:
subfilter = []
for ldapField in ldapFields:
subfilter.append("(%s=%s)" % (ldapField, ldapEsc(email)))
subfilter = "(|%s)" % ("".join(subfilter))
filterstr = "(&%s%s)" % (filterstr, subfilter)


elif indexType == self.INDEX_TYPE_AUTHID: elif indexType == self.INDEX_TYPE_AUTHID:
return return
Expand Down Expand Up @@ -1157,7 +1178,13 @@ def buildFilter(recordType, mapping, fields, operand="or", optimizeMultiName=Fal
if ldapField: if ldapField:
combined.setdefault(field, []).append((value, caseless, matchType)) combined.setdefault(field, []).append((value, caseless, matchType))
value = _convertValue(value, matchType) value = _convertValue(value, matchType)
converted.append("(%s=%s)" % (ldapField, value)) if isinstance(ldapField, str):
converted.append("(%s=%s)" % (ldapField, value))
else:
subConverted = []
for lf in ldapField:
subConverted.append("(%s=%s)" % (lf, value))
converted.append("(|%s)" % "".join(subConverted))


if len(converted) == 0: if len(converted) == 0:
return None return None
Expand Down
4 changes: 2 additions & 2 deletions twistedcaldav/directory/principal.py
Expand Up @@ -631,7 +631,7 @@ def enabledForCalendaring(self, request, tag):
if record.enabledForCalendaring: if record.enabledForCalendaring:
return tag.fillSlots( return tag.fillSlots(
calendarUserAddresses=formatLinks( calendarUserAddresses=formatLinks(
resource.calendarUserAddresses() sorted(resource.calendarUserAddresses())
), ),
calendarHomes=formatLinks(resource.calendarHomeURLs()) calendarHomes=formatLinks(resource.calendarHomeURLs())
) )
Expand Down Expand Up @@ -755,7 +755,7 @@ def readProperty(self, property, request):


elif name == "email-address-set": elif name == "email-address-set":
returnValue(customxml.EmailAddressSet( returnValue(customxml.EmailAddressSet(
*[customxml.EmailAddressProperty(addr) for addr in self.record.emailAddresses] *[customxml.EmailAddressProperty(addr) for addr in sorted(self.record.emailAddresses)]
)) ))


result = (yield super(DirectoryPrincipalResource, self).readProperty(property, request)) result = (yield super(DirectoryPrincipalResource, self).readProperty(property, request))
Expand Down
8 changes: 4 additions & 4 deletions twistedcaldav/directory/test/test_ldapdirectory.py
Expand Up @@ -410,7 +410,7 @@ def setUp(self):
"mapping": { # maps internal record names to LDAP "mapping": { # maps internal record names to LDAP
"recordName": "uid", "recordName": "uid",
"fullName" : "cn", "fullName" : "cn",
"emailAddresses" : "mail", "emailAddresses" : ["mail", "emailAliases"],
"firstName" : "givenName", "firstName" : "givenName",
"lastName" : "sn", "lastName" : "sn",
}, },
Expand All @@ -423,7 +423,7 @@ def setUp(self):
"mapping": { # maps internal record names to LDAP "mapping": { # maps internal record names to LDAP
"recordName": "cn", "recordName": "cn",
"fullName" : "cn", "fullName" : "cn",
"emailAddresses" : "mail", "emailAddresses" : ["mail", "emailAliases"],
"firstName" : "givenName", "firstName" : "givenName",
"lastName" : "sn", "lastName" : "sn",
}, },
Expand All @@ -438,7 +438,7 @@ def setUp(self):
"mapping": { # maps internal record names to LDAP "mapping": { # maps internal record names to LDAP
"recordName": "cn", "recordName": "cn",
"fullName" : "cn", "fullName" : "cn",
"emailAddresses" : "mail", "emailAddresses" : ["mail", "emailAliases"],
"firstName" : "givenName", "firstName" : "givenName",
"lastName" : "sn", "lastName" : "sn",
}, },
Expand All @@ -453,7 +453,7 @@ def setUp(self):
"mapping": { # maps internal record names to LDAP "mapping": { # maps internal record names to LDAP
"recordName": "cn", "recordName": "cn",
"fullName" : "cn", "fullName" : "cn",
"emailAddresses" : "mail", "emailAddresses" : ["mail", "emailAliases"],
"firstName" : "givenName", "firstName" : "givenName",
"lastName" : "sn", "lastName" : "sn",
}, },
Expand Down
2 changes: 1 addition & 1 deletion twistedcaldav/resource.py
Expand Up @@ -1908,7 +1908,7 @@ def readProperty(self, property, request):


elif name == "calendar-user-address-set": elif name == "calendar-user-address-set":
returnValue(caldavxml.CalendarUserAddressSet( returnValue(caldavxml.CalendarUserAddressSet(
*[element.HRef(uri) for uri in self.calendarUserAddresses()] *[element.HRef(uri) for uri in sorted(self.calendarUserAddresses())]
)) ))


elif name == "schedule-inbox-URL": elif name == "schedule-inbox-URL":
Expand Down
8 changes: 4 additions & 4 deletions twistedcaldav/stdconfig.py
Expand Up @@ -97,7 +97,7 @@
"mapping" : { # maps internal record names to LDAP "mapping" : { # maps internal record names to LDAP
"recordName": "uid", "recordName": "uid",
"fullName" : "cn", "fullName" : "cn",
"emailAddresses" : "mail", "emailAddresses" : ["mail"],
"firstName" : "givenName", "firstName" : "givenName",
"lastName" : "sn", "lastName" : "sn",
}, },
Expand All @@ -110,7 +110,7 @@
"mapping" : { # maps internal record names to LDAP "mapping" : { # maps internal record names to LDAP
"recordName": "cn", "recordName": "cn",
"fullName" : "cn", "fullName" : "cn",
"emailAddresses" : "mail", "emailAddresses" : ["mail"],
"firstName" : "givenName", "firstName" : "givenName",
"lastName" : "sn", "lastName" : "sn",
}, },
Expand All @@ -125,7 +125,7 @@
"mapping" : { # maps internal record names to LDAP "mapping" : { # maps internal record names to LDAP
"recordName": "cn", "recordName": "cn",
"fullName" : "cn", "fullName" : "cn",
"emailAddresses" : "mail", "emailAddresses" : ["mail"],
"firstName" : "givenName", "firstName" : "givenName",
"lastName" : "sn", "lastName" : "sn",
}, },
Expand All @@ -140,7 +140,7 @@
"mapping" : { # maps internal record names to LDAP "mapping" : { # maps internal record names to LDAP
"recordName": "cn", "recordName": "cn",
"fullName" : "cn", "fullName" : "cn",
"emailAddresses" : "mail", "emailAddresses" : ["mail"],
"firstName" : "givenName", "firstName" : "givenName",
"lastName" : "sn", "lastName" : "sn",
}, },
Expand Down

0 comments on commit fcffe3b

Please sign in to comment.