[CalendarServer-changes] [12087] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Mar 12 11:19:24 PDT 2014


Revision: 12087
          http://trac.calendarserver.org//changeset/12087
Author:   sagen at apple.com
Date:     2013-12-13 13:51:30 -0800 (Fri, 13 Dec 2013)
Log Message:
-----------
LDAP support for structured locations

Modified Paths:
--------------
    CalendarServer/trunk/conf/caldavd-test.plist
    CalendarServer/trunk/twistedcaldav/directory/ldapdirectory.py
    CalendarServer/trunk/twistedcaldav/directory/test/test_ldapdirectory.py

Modified: CalendarServer/trunk/conf/caldavd-test.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-test.plist	2013-12-13 18:21:26 UTC (rev 12086)
+++ CalendarServer/trunk/conf/caldavd-test.plist	2013-12-13 21:51:30 UTC (rev 12087)
@@ -284,29 +284,20 @@
                     <string>mail</string>
                     <string>mailAlias</string>
                 </array>
-                <key>firstName</key>
-                <string></string>
-                <key>lastName</key>
-                <string></string>
             </dict>
           </dict>
           <key>locations</key>
           <dict>
             <key>rdn</key>
             <string>ou=locations</string>
+            <key>associatedAddressAttr</key>
+            <string></string>
             <key>mapping</key>
             <dict>
                 <key>recordName</key>
                 <string>cn</string>
                 <key>fullName</key>
                 <string>cn</string>
-                <key>emailAddresses</key>
-                <array>
-                </array>
-                <key>firstName</key>
-                <string></string>
-                <key>lastName</key>
-                <string></string>
             </dict>
           </dict>
           <key>resources</key>
@@ -319,15 +310,24 @@
                 <string>cn</string>
                 <key>fullName</key>
                 <string>cn</string>
-                <key>emailAddresses</key>
-                <array>
-                </array>
-                <key>firstName</key>
-                <string></string>
-                <key>lastName</key>
-                <string></string>
             </dict>
           </dict>
+          <key>addresses</key>
+          <dict>
+            <key>rdn</key>
+            <string>ou=buildings</string>
+            <key>geoAttr</key>
+            <string></string>
+            <key>streetAddressAttr</key>
+            <string></string>
+            <key>mapping</key>
+            <dict>
+                <key>recordName</key>
+                <string>cn</string>
+                <key>fullName</key>
+                <string>cn</string>
+            </dict>
+          </dict>
         </dict>
         <key>groupSchema</key>
         <dict>

Modified: CalendarServer/trunk/twistedcaldav/directory/ldapdirectory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/ldapdirectory.py	2013-12-13 18:21:26 UTC (rev 12086)
+++ CalendarServer/trunk/twistedcaldav/directory/ldapdirectory.py	2013-12-13 21:51:30 UTC (rev 12087)
@@ -113,8 +113,6 @@
                 "guidAttr": "entryUUID",
                 "users": {
                     "rdn": "ou=People",
-                    "attr": "uid", # used only to synthesize email address
-                    "emailSuffix": None, # used only to synthesize email address
                     "filter": None, # additional filter for this type
                     "loginEnabledAttr" : "", # attribute controlling login
                     "loginEnabledValue" : "yes", # "True" value of above attribute
@@ -130,8 +128,6 @@
                 },
                 "groups": {
                     "rdn": "ou=Group",
-                    "attr": "cn", # used only to synthesize email address
-                    "emailSuffix": None, # used only to synthesize email address
                     "filter": None, # additional filter for this type
                     "mapping" : { # maps internal record names to LDAP
                         "recordName": "cn",
@@ -143,23 +139,18 @@
                 },
                 "locations": {
                     "rdn": "ou=Places",
-                    "attr": "cn", # used only to synthesize email address
-                    "emailSuffix": None, # used only to synthesize email address
                     "filter": None, # additional filter for this type
                     "calendarEnabledAttr" : "", # attribute controlling enabledForCalendaring
                     "calendarEnabledValue" : "yes", # "True" value of above attribute
+                    "associatedAddressAttr" : "",
                     "mapping" : { # maps internal record names to LDAP
                         "recordName": "cn",
                         "fullName" : "cn",
                         "emailAddresses" : ["mail"], # multiple LDAP fields supported
-                        "firstName" : "givenName",
-                        "lastName" : "sn",
                     },
                 },
                 "resources": {
                     "rdn": "ou=Resources",
-                    "attr": "cn", # used only to synthesize email address
-                    "emailSuffix": None, # used only to synthesize email address
                     "filter": None, # additional filter for this type
                     "calendarEnabledAttr" : "", # attribute controlling enabledForCalendaring
                     "calendarEnabledValue" : "yes", # "True" value of above attribute
@@ -167,10 +158,18 @@
                         "recordName": "cn",
                         "fullName" : "cn",
                         "emailAddresses" : ["mail"], # multiple LDAP fields supported
-                        "firstName" : "givenName",
-                        "lastName" : "sn",
                     },
                 },
+                "addresses": {
+                    "rdn": "ou=Buildings",
+                    "filter": None, # additional filter for this type
+                    "streetAddressAttr" : "",
+                    "geoAttr" : "",
+                    "mapping" : { # maps internal record names to LDAP
+                        "recordName": "cn",
+                        "fullName" : "cn",
+                    },
+                },
             },
             "groupSchema": {
                 "membersAttr": "member", # how members are specified
@@ -238,8 +237,10 @@
         for recordType in self.recordTypes():
             if self.rdnSchema[recordType]["attr"]:
                 attrSet.add(self.rdnSchema[recordType]["attr"])
-            if self.rdnSchema[recordType].get("calendarEnabledAttr", False):
-                attrSet.add(self.rdnSchema[recordType]["calendarEnabledAttr"])
+            for n in ("calendarEnabledAttr", "associatedAddressAttr",
+                "streetAddressAttr", "geoAttr"):
+                if self.rdnSchema[recordType].get(n, False):
+                    attrSet.add(self.rdnSchema[recordType][n])
             for attrList in self.rdnSchema[recordType]["mapping"].values():
                 if attrList:
                     # Since emailAddresses can map to multiple LDAP fields,
@@ -304,7 +305,7 @@
 
         # Build filter
         filterstr = "(!(objectClass=organizationalUnit))"
-        typeFilter = self.rdnSchema[recordType]["filter"]
+        typeFilter = self.rdnSchema[recordType].get("filter", "")
         if typeFilter:
             filterstr = "(&%s%s)" % (filterstr, typeFilter)
 
@@ -778,6 +779,7 @@
         enabledForAddressBooks = None
         uid = None
         enabledForLogin = True
+        extras = {}
 
         shortNames = tuple(self._getMultipleLdapAttributes(attrs, self.rdnSchema[recordType]["mapping"]["recordName"]))
         if not shortNames:
@@ -794,17 +796,17 @@
 
         # Find or build email
         # (The emailAddresses mapping is a list of ldap fields)
-        emailAddressesMappedTo = self.rdnSchema[recordType]["mapping"]["emailAddresses"]
+        emailAddressesMappedTo = self.rdnSchema[recordType]["mapping"].get("emailAddresses", "")
         # Supporting either string or list for emailAddresses:
         if isinstance(emailAddressesMappedTo, str):
-            emailAddresses = set(self._getMultipleLdapAttributes(attrs, self.rdnSchema[recordType]["mapping"]["emailAddresses"]))
+            emailAddresses = set(self._getMultipleLdapAttributes(attrs, self.rdnSchema[recordType]["mapping"].get("emailAddresses", "")))
         else:
             emailAddresses = set(self._getMultipleLdapAttributes(attrs, *self.rdnSchema[recordType]["mapping"]["emailAddresses"]))
-        emailSuffix = self.rdnSchema[recordType]["emailSuffix"]
+        emailSuffix = self.rdnSchema[recordType].get("emailSuffix", None)
 
         if len(emailAddresses) == 0 and emailSuffix:
             emailPrefix = self._getUniqueLdapAttribute(attrs,
-                self.rdnSchema[recordType]["attr"])
+                self.rdnSchema[recordType].get("attr", "cn"))
             emailAddresses.add(emailPrefix + emailSuffix)
 
         proxyGUIDs = ()
@@ -890,6 +892,25 @@
                     autoAcceptGroup = self._getUniqueLdapAttribute(attrs,
                         self.resourceSchema["autoAcceptGroupAttr"])
 
+            if recordType == self.recordType_locations:
+                if self.rdnSchema[recordType]["associatedAddressAttr"]:
+                    associatedAddress = self._getUniqueLdapAttribute(attrs,
+                        self.rdnSchema[recordType]["associatedAddressAttr"])
+                    if associatedAddress:
+                        extras["associatedAddress"] = associatedAddress
+
+        elif recordType == self.recordType_addresses:
+            if self.rdnSchema[recordType].get("geoAttr", ""):
+                geo = self._getUniqueLdapAttribute(attrs,
+                    self.rdnSchema[recordType]["geoAttr"])
+                if geo:
+                    extras["geo"] = geo
+            if self.rdnSchema[recordType].get("streetAddressAttr", ""):
+                street = self._getUniqueLdapAttribute(attrs,
+                    self.rdnSchema[recordType]["streetAddressAttr"])
+                if street:
+                    extras["streetAddress"] = street
+
         serverID = None
         if self.poddingSchema["serverIdAttr"]:
             serverID = self._getUniqueLdapAttribute(attrs,
@@ -911,6 +932,7 @@
             extProxies=proxyGUIDs,
             extReadOnlyProxies=readOnlyProxyGUIDs,
             attrs=attrs,
+            **extras
         )
 
         if self.augmentService is not None:
@@ -981,7 +1003,7 @@
 
             # Build filter
             filterstr = "(!(objectClass=organizationalUnit))"
-            typeFilter = self.rdnSchema[recordType]["filter"]
+            typeFilter = self.rdnSchema[recordType].get("filter", "")
             if typeFilter:
                 filterstr = "(&%s%s)" % (filterstr, typeFilter)
 
@@ -1003,17 +1025,17 @@
             elif indexType == self.INDEX_TYPE_CUA:
                 # indexKey is of the form "mailto:test at example.net"
                 email = indexKey[7:] # strip "mailto:"
-                emailSuffix = self.rdnSchema[recordType]["emailSuffix"]
+                emailSuffix = self.rdnSchema[recordType].get("emailSuffix", None)
                 if emailSuffix is not None and email.partition("@")[2] == emailSuffix:
                     filterstr = "(&%s(|(&(!(mail=*))(%s=%s))(mail=%s)))" % (
                         filterstr,
-                        self.rdnSchema[recordType]["attr"],
+                        self.rdnSchema[recordType].get("attr", "cn"),
                         email.partition("@")[0],
                         ldapEsc(email)
                     )
                 else:
                     # emailAddresses can map to multiple LDAP fields
-                    ldapFields = self.rdnSchema[recordType]["mapping"]["emailAddresses"]
+                    ldapFields = self.rdnSchema[recordType]["mapping"].get("emailAddresses", "")
                     if isinstance(ldapFields, str):
                         if ldapFields:
                             subfilter = "(%s=%s)" % (ldapFields, ldapEsc(email))
@@ -1108,7 +1130,7 @@
             typeCounts[recordType] = 0
             base = self.typeDNs[recordType]
             scope = ldap.SCOPE_SUBTREE
-            extraFilter = self.rdnSchema[recordType]["filter"]
+            extraFilter = self.rdnSchema[recordType].get("filter", "")
             filterstr = buildFilterFromTokens(recordType, self.rdnSchema[recordType]["mapping"],
                 tokens, extra=extraFilter)
 
@@ -1509,7 +1531,7 @@
         guid, shortNames, authIDs, fullName,
         firstName, lastName, emailAddresses,
         uid, dn, memberGUIDs, extProxies, extReadOnlyProxies,
-        attrs
+        attrs, **kwargs
     ):
         super(LdapDirectoryRecord, self).__init__(
             service=service,
@@ -1524,6 +1546,7 @@
             extProxies=extProxies,
             extReadOnlyProxies=extReadOnlyProxies,
             uid=uid,
+            **kwargs
         )
 
         # Save attributes of dn and attrs in case you might need them later

Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_ldapdirectory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_ldapdirectory.py	2013-12-13 18:21:26 UTC (rev 12086)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_ldapdirectory.py	2013-12-13 21:51:30 UTC (rev 12087)
@@ -541,8 +541,6 @@
                             "recordName": "cn",
                             "fullName" : "cn",
                             "emailAddresses" : ["mail", "emailAliases"],
-                            "firstName" : "givenName",
-                            "lastName" : "sn",
                         },
                     },
                     "locations": {
@@ -552,12 +550,11 @@
                         "filter": "(objectClass=apple-resource)", # additional filter for this type
                         "calendarEnabledAttr" : "", # attribute controlling calendaring
                         "calendarEnabledValue" : "yes", # "True" value of above attribute
+                        "associatedAddressAttr" : "assocAddr",
                         "mapping": { # maps internal record names to LDAP
                             "recordName": "cn",
                             "fullName" : "cn",
                             "emailAddresses" : "", # old style, single string
-                            "firstName" : "givenName",
-                            "lastName" : "sn",
                         },
                     },
                     "resources": {
@@ -571,10 +568,17 @@
                             "recordName": "cn",
                             "fullName" : "cn",
                             "emailAddresses" : [], # new style, array
-                            "firstName" : "givenName",
-                            "lastName" : "sn",
                         },
                     },
+                    "addresses": {
+                        "rdn": "cn=Buildings",
+                        "geoAttr" : "coordinates",
+                        "streetAddressAttr" : "postal",
+                        "mapping": { # maps internal record names to LDAP
+                            "recordName": "cn",
+                            "fullName" : "cn",
+                        },
+                    },
                 },
                 "groupSchema": {
                     "membersAttr": "uniqueMember", # how members are specified
@@ -1514,6 +1518,39 @@
                 self.service.recordType_users)
             self.assertEquals(record.guid, guid.upper())
 
+            # Location with associated Address
+
+            dn = "cn=odtestlocation,cn=locations,dc=example,dc=com"
+            guid = "D3094652-344B-4633-8DB8-09639FA00FB6"
+            attrs = {
+                "apple-generateduid": [guid],
+                "cn": ["odtestlocation"],
+                "assocAddr" : ["6C6CD280-E6E3-11DF-9492-0800200C9A66"],
+            }
+            record = self.service._ldapResultToRecord(dn, attrs,
+                self.service.recordType_locations)
+            self.assertEquals(record.extras, {
+                "associatedAddress": "6C6CD280-E6E3-11DF-9492-0800200C9A66"
+            })
+           
+            # Address with street and geo
+
+            dn = "cn=odtestaddress,cn=buildings,dc=example,dc=com"
+            guid = "6C6CD280-E6E3-11DF-9492-0800200C9A66"
+            attrs = {
+                "apple-generateduid": [guid],
+                "cn": ["odtestaddress"],
+                "coordinates" : ["geo:1,2"],
+                "postal" : ["1 Infinite Loop, Cupertino, CA"],
+            }
+            record = self.service._ldapResultToRecord(dn, attrs,
+                self.service.recordType_addresses)
+            self.assertEquals(record.extras, {
+                "geo": "geo:1,2",
+                "streetAddress" : "1 Infinite Loop, Cupertino, CA",
+            })
+           
+
         def test_listRecords(self):
             """
             listRecords makes an LDAP query (with fake results in this test)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140312/e76771fe/attachment.html>


More information about the calendarserver-changes mailing list