[CalendarServer-changes] [12391] twext/trunk/twext/who/ldap
source_changes at macosforge.org
source_changes at macosforge.org
Wed Mar 12 11:17:40 PDT 2014
Revision: 12391
http://trac.calendarserver.org//changeset/12391
Author: wsanchez at apple.com
Date: 2014-01-17 19:10:38 -0800 (Fri, 17 Jan 2014)
Log Message:
-----------
We no longer describe a record type to LDAP as a set of values for a specific attribute (eg. objectType).
Instead, we describe it as a relative distinguished name (presently unused), and a sequence of (attribute, value) pairs to match against.
Modified Paths:
--------------
twext/trunk/twext/who/ldap/_constants.py
twext/trunk/twext/who/ldap/_service.py
twext/trunk/twext/who/ldap/_util.py
twext/trunk/twext/who/ldap/test/test_service.py
twext/trunk/twext/who/ldap/test/test_util.py
Modified: twext/trunk/twext/who/ldap/_constants.py
===================================================================
--- twext/trunk/twext/who/ldap/_constants.py 2014-01-17 23:34:52 UTC (rev 12390)
+++ twext/trunk/twext/who/ldap/_constants.py 2014-01-18 03:10:38 UTC (rev 12391)
@@ -125,6 +125,7 @@
"""
LDAP match flags.
"""
+ none = ValueConstant(u"")
NOT = ValueConstant(u"!")
Modified: twext/trunk/twext/who/ldap/_service.py
===================================================================
--- twext/trunk/twext/who/ldap/_service.py 2014-01-17 23:34:52 UTC (rev 12390)
+++ twext/trunk/twext/who/ldap/_service.py 2014-01-18 03:10:38 UTC (rev 12391)
@@ -50,25 +50,6 @@
-# Maps field name -> LDAP attribute names
-DEFAULT_FIELDNAME_ATTRIBUTE_MAP = MappingProxyType({
- BaseFieldName.guid: (LDAPAttribute.generatedUUID.value,),
- BaseFieldName.recordType: (LDAPAttribute.objectClass.value,),
- BaseFieldName.shortNames: (LDAPAttribute.uid.value,),
- BaseFieldName.fullNames: (LDAPAttribute.cn.value,),
- BaseFieldName.emailAddresses: (LDAPAttribute.mail.value,),
- BaseFieldName.password: (LDAPAttribute.userPassword.value,),
-})
-
-
-# Maps record type -> LDAP object class names
-DEFAULT_RECORDTYPE_OBJECTCLASS_MAP = MappingProxyType({
- BaseRecordType.user: (LDAPObjectClass.inetOrgPerson.value,),
- BaseRecordType.group: (LDAPObjectClass.groupOfNames.value,),
-})
-
-
-
#
# Exceptions
#
@@ -124,6 +105,77 @@
#
+# LDAP schema descriptions
+#
+
+class RecordTypeSchema(object):
+ """
+ Describes the LDAP schema for a record type.
+ """
+ def __init__(self, relativeDN, attributes):
+ """
+ @param relativeDN: The relative distinguished name for the record type.
+ This is prepended to the service's base distinguished name when
+ searching for records of this type.
+ @type relativeDN: L{unicode}
+
+ @param attributes: Attribute/value pairs that are expected for records
+ of this type.
+ @type attributes: iterable of sequences containing two L{unicode}s
+ """
+ self.relativeDN = relativeDN
+ self.attributes = tuple(tuple(pair) for pair in attributes)
+
+
+
+# We use strings (constant.value) instead of constants for the values in
+# these mappings because it's meant to be configurable by application users,
+# and user input forms such as config files aren't going to be able to use
+# the constants.
+
+# Maps field name -> LDAP attribute names
+DEFAULT_FIELDNAME_ATTRIBUTE_MAP = MappingProxyType({
+ BaseFieldName.guid: (LDAPAttribute.generatedUUID.value,),
+ BaseFieldName.shortNames: (LDAPAttribute.uid.value,),
+ BaseFieldName.fullNames: (LDAPAttribute.cn.value,),
+ BaseFieldName.emailAddresses: (LDAPAttribute.mail.value,),
+ BaseFieldName.password: (LDAPAttribute.userPassword.value,),
+})
+
+# Information about record types
+DEFAULT_RECORDTYPE_SCHEMAS = MappingProxyType({
+
+ BaseRecordType.user: RecordTypeSchema(
+ # ou=person
+ relativeDN=u"ou={0}".format(LDAPObjectClass.person.value),
+
+ # (objectClass=inetOrgPerson)
+ attributes=(
+ (
+ LDAPAttribute.objectClass.value,
+ LDAPObjectClass.inetOrgPerson.value,
+ ),
+ ),
+ ),
+
+ BaseRecordType.group: RecordTypeSchema(
+ # ou=groupOfNames
+ relativeDN=u"ou={0}".format(LDAPObjectClass.groupOfNames.value),
+
+ # (objectClass=groupOfNames)
+ attributes=(
+ (
+ LDAPAttribute.objectClass.value,
+ LDAPObjectClass.groupOfNames.value,
+ ),
+ ),
+ ),
+
+})
+
+
+
+#
# Directory Service
#
@@ -148,8 +200,8 @@
tlsCACertificateFile=None,
tlsCACertificateDirectory=None,
useTLS=False,
- fieldNameToAttributeMap=DEFAULT_FIELDNAME_ATTRIBUTE_MAP,
- recordTypeToObjectClassMap=DEFAULT_RECORDTYPE_OBJECTCLASS_MAP,
+ fieldNameToAttributesMap=DEFAULT_FIELDNAME_ATTRIBUTE_MAP,
+ recordTypeSchemas=DEFAULT_RECORDTYPE_SCHEMAS,
uidField=BaseFieldName.uid,
_debug=False,
):
@@ -176,15 +228,14 @@
@param useTLS: Enable the use of TLS.
@type useTLS: L{bool}
- @param fieldNameToAttributeMap: A mapping of field names to LDAP
+ @param fieldNameToAttributesMap: A mapping of field names to LDAP
attribute names.
- @type fieldNameToAttributeMap: mapping with L{NamedConstant} keys and
+ @type fieldNameToAttributesMap: mapping with L{NamedConstant} keys and
sequence of L{unicode} values
- @param recordTypeToObjectClassMap: A mapping of record types to LDAP
- object classes.
- @type recordTypeToObjectClassMap: mapping with L{NamedConstant} keys
- and sequence of L{unicode} values
+ @param recordTypeSchemas: Schema information for record types.
+ @type recordTypeSchemas: mapping from L{NamedConstant} to
+ L{RecordTypeSchema}
"""
self.url = url
@@ -209,30 +260,14 @@
else:
self._debug = None
- def reverseDict(sourceName, source):
- new = {}
+ if self.fieldName.recordType in fieldNameToAttributesMap:
+ raise TypeError("Record type field may not be mapped")
- for key, values in source.iteritems():
- for value in values:
- if value in new:
- raise LDAPConfigurationError(
- u"{0} map has duplicate values: {1}"
- .format(sourceName, value)
- )
- new[value] = key
-
- return new
-
- self._fieldNameToAttributeMap = fieldNameToAttributeMap
+ self._fieldNameToAttributesMap = fieldNameToAttributesMap
self._attributeToFieldNameMap = reverseDict(
- "Field name", fieldNameToAttributeMap
+ "Field name", fieldNameToAttributesMap
)
-
- self._recordTypeToObjectClassMap = recordTypeToObjectClassMap
- self._objectClassToRecordTypeMap = reverseDict(
- "Record type", recordTypeToObjectClassMap
- )
-
+ self._recordTypeSchemas = recordTypeSchemas
self._uidField = uidField
@@ -312,69 +347,68 @@
self.log.debug("Performing LDAP query: {query}", query=queryString)
reply = connection.search_s(
- self._baseDN, ldap.SCOPE_SUBTREE, queryString # attrs
+ self._baseDN, ldap.SCOPE_SUBTREE, queryString # FIXME: attrs
)
records = []
- # Note: self._uidField is the name of the field in
- # self._fieldNameToAttributeMap that tells us which LDAP attribute
+ # self._uidField is the name of the field in
+ # self._fieldNameToAttributesMap that tells us which LDAP attribute
# we are using to determine the UID of the record.
- uidField = self.fieldName.uid
- uidAttribute = self._fieldNameToAttributeMap[self._uidField][0]
+ uidAttribute = self._fieldNameToAttributesMap[self._uidField][0]
- recordTypeField = self.fieldName.recordType
- recordTypeAttributes = (
- self._fieldNameToAttributeMap[self.fieldName.recordType]
- )
+ # recordTypeAttributes = set(chain(*[
+ # info[u"attributes"].iterkeys()
+ # for info in self._recordTypeInfo.itervalues()
+ # ]))
for dn, recordData in reply:
- # Attributes used to determine the record type are required, since
- # record type is very much required.
+ # Fetch the UID
- for recordTypeAttribute in recordTypeAttributes:
- if recordTypeAttribute not in recordData:
- self.log.debug(
- "Ignoring LDAP record data without record type "
- "attribute {attribute!r}: "
- "{recordData!r}",
- attribute=recordTypeAttribute, recordData=recordData,
- )
- continue
-
- # Make a dict of fields -> values from the incoming dict of
- # attributes -> values.
-
- fields = dict([
- (self._attributeToFieldNameMap[k], v)
- for k, v in recordData.iteritems()
- if k in self._attributeToFieldNameMap
- ])
-
- # Make sure the UID is populated
-
try:
- fields[uidField] = recordData[uidAttribute]
+ uid = recordData[uidAttribute]
except KeyError:
self.log.debug(
- "Ignoring LDAP record data with no UID attribute "
- "{source._uidField!r}: {recordData!r}",
+ "Ignoring LDAP record data; no UID attribute "
+ "({source._uidField}): {recordData!r}",
recordData=recordData
)
continue
+ # Determine the record type
- # Coerce data to the correct type
+ recordType = recordTypeForRecordData(
+ self._recordTypeSchemas, recordData
+ )
- for fieldName, value in fields.iteritems():
+ if recordType is None:
+ self.log.debug(
+ "Ignoring LDAP record data; unable to determine record "
+ "type: {recordData!r}",
+ recordData=recordData,
+ )
+ continue
+
+ # Populate a fields dictionary
+
+ fields = {}
+
+ for attribute, value in recordData.iteritems():
+ fieldName = self._attributeToFieldNameMap.get(attribute, None)
+ if fieldName is None:
+ self.log.debug(
+ "Unmapped LDAP attribute {attribute!r} in record "
+ "data: {recordData!r}",
+ attribute=attribute, recordData=recordData,
+ )
+
valueType = self.fieldName.valueType(fieldName)
- if fieldName is recordTypeField:
- value = self._objectClassToRecordTypeMap[value]
- elif valueType in (unicode, UUID):
- value = valueType(value)
+ if valueType in (unicode, UUID):
+ fields[fieldName] = valueType(value)
+
else:
raise LDAPConfigurationError(
"Unknown value type {0} for field {1}".format(
@@ -382,8 +416,11 @@
)
)
- fields[fieldName] = value
+ # Set record type and uid fields
+ fields[self.fieldName.recordType] = recordType
+ fields[self.fieldName.uid] = uid
+
# Make a record object from fields.
record = DirectoryRecord(self, fields)
@@ -398,7 +435,7 @@
if isinstance(expression, MatchExpression):
queryString = ldapQueryStringFromMatchExpression(
expression,
- self._fieldNameToAttributeMap, self._recordTypeToObjectClassMap
+ self._fieldNameToAttributesMap, self._recordTypeSchemas
)
return self._recordsFromQueryString(queryString)
@@ -413,7 +450,7 @@
queryString = ldapQueryStringFromCompoundExpression(
expression,
- self._fieldNameToAttributeMap, self._recordTypeToObjectClassMap
+ self._fieldNameToAttributesMap, self._recordTypeSchemas
)
return self._recordsFromQueryString(queryString)
@@ -423,3 +460,42 @@
"""
LDAP directory record.
"""
+
+
+
+def reverseDict(sourceName, source):
+ new = {}
+
+ for key, values in source.iteritems():
+ for value in values:
+ if value in new:
+ raise LDAPConfigurationError(
+ u"{0} map has duplicate values: {1}"
+ .format(sourceName, value)
+ )
+ new[value] = key
+
+ return new
+
+
+def recordTypeForRecordData(recordTypeSchemas, recordData):
+ """
+ Given info about record types, determine the record type for a blob of
+ LDAP record data.
+
+ @param recordTypeSchemas: Schema information for record types.
+ @type recordTypeSchemas: mapping from L{NamedConstant} to
+ L{RecordTypeSchema}
+
+ @param recordData: LDAP record data.
+ @type recordData: mapping
+ """
+
+ for recordType, schema in recordTypeSchemas.iteritems():
+ for attribute, value in schema.attributes:
+ if recordData.get(attribute, None) != value:
+ break
+ else:
+ return recordType
+
+ return None
Modified: twext/trunk/twext/who/ldap/_util.py
===================================================================
--- twext/trunk/twext/who/ldap/_util.py 2014-01-17 23:34:52 UTC (rev 12390)
+++ twext/trunk/twext/who/ldap/_util.py 2014-01-18 03:10:38 UTC (rev 12391)
@@ -33,7 +33,7 @@
@type operand: L{unicode}
@param queryStrings: LDAP query strings.
- @type queryStrings: iterable of L{unicode}
+ @type queryStrings: sequence of L{unicode}
"""
if len(queryStrings) == 1:
return queryStrings[0]
@@ -51,7 +51,7 @@
def ldapQueryStringFromMatchExpression(
- expression, fieldNameToAttributeMap, recordTypeToObjectClassMap
+ expression, fieldNameToAttributesMap, recordTypeSchemas
):
"""
Generates an LDAP query string from a match expression.
@@ -59,15 +59,14 @@
@param expression: A match expression.
@type expression: L{MatchExpression}
- @param fieldNameToAttributeMap: A mapping from field names to native LDAP
+ @param fieldNameToAttributesMap: A mapping from field names to native LDAP
attribute names.
- @type fieldNameToAttributeMap: L{dict} with L{FieldName} keys and sequence
+ @type fieldNameToAttributesMap: L{dict} with L{FieldName} keys and sequence
of L{unicode} values.
- @param recordTypeToObjectClassMap: A mapping from L{RecordType}s to native
- LDAP object class names.
- @type recordTypeToObjectClassMap: L{dict} with L{RecordType} keys and
- sequence of L{unicode} values.
+ @param recordTypeSchemas: Schema information for record types.
+ @type recordTypeSchemas: mapping from L{NamedConstant} to
+ L{RecordTypeSchema}
@return: An LDAP query string.
@rtype: L{unicode}
@@ -89,7 +88,7 @@
notOp = LDAPMatchFlags.NOT.value
operand = LDAPOperand.AND.value
else:
- notOp = u""
+ notOp = LDAPMatchFlags.none.value
operand = LDAPOperand.OR.value
# FIXME: It doesn't look like LDAP queries can be case sensitive.
@@ -100,53 +99,63 @@
# raise NotImplementedError("Need to handle case sensitive")
fieldName = expression.fieldName
- try:
- attributes = fieldNameToAttributeMap[fieldName]
- except KeyError:
- raise QueryNotSupportedError(
- "Unmapped field name: {0}".format(expression.fieldName)
- )
if fieldName is FieldName.recordType:
+ if matchType is not LDAPMatchType.equals:
+ raise QueryNotSupportedError(
+ "Match type for record type must be equals, not {0!r}"
+ .format(expression.matchType)
+ )
+
try:
- values = recordTypeToObjectClassMap[expression.fieldValue]
+ schema = recordTypeSchemas[expression.fieldValue]
except KeyError:
raise QueryNotSupportedError(
"Unmapped record type: {0}".format(expression.fieldValue)
)
- else:
- values = (unicode(expression.fieldValue),)
- # Escape special LDAP query characters
- values = [value.translate(LDAP_QUOTING_TABLE) for value in values]
- del value # Symbol used below; ensure non-reuse of data
+ if notOp:
+ valueOperand = LDAPOperand.OR.value
+ else:
+ valueOperand = LDAPOperand.AND.value
- # Compose an query using each of the LDAP attributes cooresponding to the
- # target field name.
+ queryStrings = [
+ matchType.queryString.format(
+ notOp=notOp, attribute=attribute, value=value,
+ )
+ for attribute, value in schema.attributes
+ ]
- if notOp:
- valueOperand = LDAPOperand.OR.value
+ return ldapQueryStringFromQueryStrings(valueOperand, queryStrings)
+
else:
- valueOperand = LDAPOperand.AND.value
+ try:
+ attributes = fieldNameToAttributesMap[fieldName]
+ except KeyError:
+ raise QueryNotSupportedError(
+ "Unmapped field name: {0}".format(expression.fieldName)
+ )
- queryStrings = [
- ldapQueryStringFromQueryStrings(
- valueOperand,
- [
- matchType.queryString.format(
- notOp=notOp, attribute=attribute, value=value
- )
- for value in values
- ]
- )
- for attribute in attributes
- ]
+ # Covert to unicode and escape special LDAP query characters
+ value = unicode(expression.fieldValue).translate(LDAP_QUOTING_TABLE)
- return ldapQueryStringFromQueryStrings(operand, queryStrings)
+ # Compose an query using each of the LDAP attributes cooresponding to
+ # the target field name.
+ queryStrings = [
+ matchType.queryString.format(
+ notOp=notOp, attribute=attribute, value=value
+ )
+ for attribute in attributes
+ ]
+ return ldapQueryStringFromQueryStrings(operand, queryStrings)
+
+ raise AssertionError("We shouldn't be here.")
+
+
def ldapQueryStringFromCompoundExpression(
- expression, fieldNameToAttributeMap, recordTypeToObjectClassMap
+ expression, fieldNameToAttributesMap, recordTypeSchemas
):
"""
Generates an LDAP query string from a compound expression.
@@ -154,15 +163,14 @@
@param expression: A compound expression.
@type expression: L{MatchExpression}
- @param fieldNameToAttributeMap: A mapping from field names to native LDAP
+ @param fieldNameToAttributesMap: A mapping from field names to native LDAP
attribute names.
- @type fieldNameToAttributeMap: L{dict} with L{FieldName} keys and sequence
+ @type fieldNameToAttributesMap: L{dict} with L{FieldName} keys and sequence
of L{unicode} values.
- @param recordTypeToObjectClassMap: A mapping from L{RecordType}s to native
- LDAP object class names.
- @type recordTypeToObjectClassMap: L{dict} with L{RecordType} keys and
- sequence of L{unicode} values.
+ @param recordTypeSchemas: Schema information for record types.
+ @type recordTypeSchemas: mapping from L{NamedConstant} to
+ L{RecordTypeSchema}
@return: An LDAP query string.
@rtype: L{unicode}
@@ -179,7 +187,7 @@
queryStrings = [
ldapQueryStringFromExpression(
subExpression,
- fieldNameToAttributeMap, recordTypeToObjectClassMap
+ fieldNameToAttributesMap, recordTypeSchemas
)
for subExpression in expression.expressions
]
@@ -188,7 +196,7 @@
def ldapQueryStringFromExpression(
- expression, fieldNameToAttributeMap, recordTypeToObjectClassMap
+ expression, fieldNameToAttributesMap, recordTypeSchemas
):
"""
Converts an expression into an LDAP query string.
@@ -196,15 +204,14 @@
@param expression: An expression.
@type expression: L{MatchExpression} or L{CompoundExpression}
- @param fieldNameToAttributeMap: A mapping from field names to native LDAP
+ @param fieldNameToAttributesMap: A mapping from field names to native LDAP
attribute names.
- @type fieldNameToAttributeMap: L{dict} with L{FieldName} keys and sequence
+ @type fieldNameToAttributesMap: L{dict} with L{FieldName} keys and sequence
of L{unicode} values.
- @param recordTypeToObjectClassMap: A mapping from L{RecordType}s to native
- LDAP object class names.
- @type recordTypeToObjectClassMap: L{dict} with L{RecordType} keys and
- sequence of L{unicode} values.
+ @param recordTypeSchemas: Schema information for record types.
+ @type recordTypeSchemas: mapping from L{NamedConstant} to
+ L{RecordTypeSchema}
@return: An LDAP query string.
@rtype: L{unicode}
@@ -215,12 +222,12 @@
if isinstance(expression, MatchExpression):
return ldapQueryStringFromMatchExpression(
- expression, fieldNameToAttributeMap, recordTypeToObjectClassMap
+ expression, fieldNameToAttributesMap, recordTypeSchemas
)
if isinstance(expression, CompoundExpression):
return ldapQueryStringFromCompoundExpression(
- expression, fieldNameToAttributeMap, recordTypeToObjectClassMap
+ expression, fieldNameToAttributesMap, recordTypeSchemas
)
raise QueryNotSupportedError(
Modified: twext/trunk/twext/who/ldap/test/test_service.py
===================================================================
--- twext/trunk/twext/who/ldap/test/test_service.py 2014-01-17 23:34:52 UTC (rev 12390)
+++ twext/trunk/twext/who/ldap/test/test_service.py 2014-01-18 03:10:38 UTC (rev 12391)
@@ -33,7 +33,7 @@
from ...idirectory import QueryNotSupportedError, FieldName as BaseFieldName
from .._service import (
- DEFAULT_FIELDNAME_ATTRIBUTE_MAP, DEFAULT_RECORDTYPE_OBJECTCLASS_MAP,
+ DEFAULT_FIELDNAME_ATTRIBUTE_MAP, DEFAULT_RECORDTYPE_SCHEMAS,
LDAPBindAuthError,
DirectoryService, DirectoryRecord,
)
@@ -85,7 +85,7 @@
return DirectoryService(
url=self.url,
baseDN=self.baseDN,
- fieldNameToAttributeMap=TEST_FIELDNAME_MAP,
+ fieldNameToAttributesMap=TEST_FIELDNAME_MAP,
**kwargs
)
@@ -238,16 +238,22 @@
return unicode(obj)
def tuplify(record, fieldName):
+ fieldValue = record.fields[fieldName]
+
if fieldName is BaseFieldName.recordType:
- values = DEFAULT_RECORDTYPE_OBJECTCLASS_MAP[
- record.fields[fieldName]
- ]
+ schema = DEFAULT_RECORDTYPE_SCHEMAS[fieldValue]
+
+ return schema.attributes
+
else:
- values = (toUnicode(record.fields[fieldName]),)
+ value = toUnicode(fieldValue)
- for name in TEST_FIELDNAME_MAP.get(fieldName, fieldName.name):
- for value in values:
- yield (name, value)
+ return (
+ (name, value)
+ for name in TEST_FIELDNAME_MAP.get(
+ fieldName, (u"__" + fieldName.name,)
+ )
+ )
for records in service.index[service.fieldName.uid].itervalues():
for record in records:
Modified: twext/trunk/twext/who/ldap/test/test_util.py
===================================================================
--- twext/trunk/twext/who/ldap/test/test_util.py 2014-01-17 23:34:52 UTC (rev 12390)
+++ twext/trunk/twext/who/ldap/test/test_util.py 2014-01-18 03:10:38 UTC (rev 12391)
@@ -25,7 +25,7 @@
CompoundExpression, Operand, MatchExpression, MatchType, MatchFlags
)
from .._constants import LDAPOperand
-from .._service import DirectoryService
+from .._service import DirectoryService, RecordTypeSchema
from .._util import (
ldapQueryStringFromQueryStrings,
ldapQueryStringFromMatchExpression,
@@ -59,7 +59,7 @@
])
- def recordTypeMap(self, service):
+ def recordTypeSchemas(self, service):
"""
Create a mapping from record types to LDAP object class names.
The object class names returned here are not real LDAP object class
@@ -67,7 +67,15 @@
connecting to LDAP.
"""
return dict([
- (c, (c.name,))
+ (
+ c,
+ RecordTypeSchema(
+ relativeDN=NotImplemented, # Don't expect this to be used
+ attributes=(
+ (u"recordTypeAttribute", c.name),
+ )
+ )
+ )
for c in service.recordType.iterconstants()
])
@@ -127,7 +135,7 @@
)
queryString = ldapQueryStringFromMatchExpression(
expression,
- self.fieldNameMap(service), self.recordTypeMap(service),
+ self.fieldNameMap(service), self.recordTypeSchemas(service),
)
expected = u"({attribute}{expected})".format(
attribute=u"shortNames", expected=expected
@@ -147,7 +155,7 @@
)
queryString = ldapQueryStringFromMatchExpression(
expression,
- self.fieldNameMap(service), self.recordTypeMap(service),
+ self.fieldNameMap(service), self.recordTypeSchemas(service),
)
expected = u"(!{attribute}=xyzzy)".format(
attribute=u"shortNames",
@@ -168,7 +176,7 @@
)
queryString = ldapQueryStringFromMatchExpression(
expression,
- self.fieldNameMap(service), self.recordTypeMap(service),
+ self.fieldNameMap(service), self.recordTypeSchemas(service),
)
expected = u"???????({attribute}=xyzzy)".format(
attribute=u"shortNames",
@@ -193,7 +201,7 @@
)
queryString = ldapQueryStringFromMatchExpression(
expression,
- self.fieldNameMap(service), self.recordTypeMap(service),
+ self.fieldNameMap(service), self.recordTypeSchemas(service),
)
expected = u"({attribute}={expected})".format(
attribute=u"fullNames",
@@ -219,7 +227,7 @@
QueryNotSupportedError,
ldapQueryStringFromMatchExpression,
expression,
- self.fieldNameMap(service), self.recordTypeMap(service),
+ self.fieldNameMap(service), self.recordTypeSchemas(service),
)
@@ -238,7 +246,7 @@
QueryNotSupportedError,
ldapQueryStringFromMatchExpression,
expression,
- self.fieldNameMap(service), self.recordTypeMap(service),
+ self.fieldNameMap(service), self.recordTypeSchemas(service),
)
@@ -257,7 +265,8 @@
}
queryString = ldapQueryStringFromMatchExpression(
- expression, fieldNameToAttributeMap, self.recordTypeMap(service)
+ expression,
+ fieldNameToAttributeMap, self.recordTypeSchemas(service)
)
self.assertEquals(queryString, expected)
@@ -305,17 +314,37 @@
fieldNameToAttributeMap = self.fieldNameMap(service)
- recordTypeToObjectClassMap = {
- service.recordType.user: (u"person", u"account"),
+ recordTypeAttr = fieldNameToAttributeMap[recordTypeField][0]
+ type1 = u"person"
+ type2 = u"coolPerson"
+
+ statusAttr = u"accountStatus"
+ status1 = u"active"
+
+ recordTypeSchemas = {
+ service.recordType.user: RecordTypeSchema(
+ relativeDN=NotImplemented, # Don't expect this to be used.
+ attributes=(
+ (recordTypeAttr, type1),
+ (recordTypeAttr, type2),
+ (statusAttr, status1),
+ )
+ )
}
queryString = ldapQueryStringFromMatchExpression(
- expression, fieldNameToAttributeMap, recordTypeToObjectClassMap
+ expression, fieldNameToAttributeMap, recordTypeSchemas
)
self.assertEquals(
queryString,
- expected.format(attr=fieldNameToAttributeMap[recordTypeField][0])
+ expected.format(
+ recordType=recordTypeAttr,
+ type1=type1,
+ type2=type2,
+ accountStatus=statusAttr,
+ status1=status1,
+ )
)
@@ -326,7 +355,11 @@
"""
# We want a match for both values.
- expected = u"(&({attr}=person)({attr}=account))"
+ expected = (
+ u"(&({recordType}={type1})"
+ u"({recordType}={type2})"
+ u"({accountStatus}={status1}))"
+ )
return self._test_queryStringFromMatchExpression_multiRecordType(
MatchFlags.none, expected
@@ -339,7 +372,11 @@
"""
# We want a NOT match for either value.
- expected = u"(|(!{attr}=person)(!{attr}=account))"
+ expected = (
+ u"(|(!{recordType}={type1})"
+ u"(!{recordType}={type2})"
+ u"(!{accountStatus}={status1}))"
+ )
return self._test_queryStringFromMatchExpression_multiRecordType(
MatchFlags.NOT, expected
@@ -370,12 +407,13 @@
)
queryString = queryFunction(
compoundExpression,
- self.fieldNameMap(service), self.recordTypeMap(service),
+ self.fieldNameMap(service), self.recordTypeSchemas(service),
)
expected = u"{match}".format(
match=ldapQueryStringFromMatchExpression(
matchExpression,
- self.fieldNameMap(service), self.recordTypeMap(service),
+ self.fieldNameMap(service),
+ self.recordTypeSchemas(service),
)
)
self.assertEquals(queryString, expected)
@@ -404,17 +442,19 @@
)
queryString = queryFunction(
compoundExpression,
- self.fieldNameMap(service), self.recordTypeMap(service),
+ self.fieldNameMap(service), self.recordTypeSchemas(service),
)
expected = u"({op}{match1}{match2})".format(
op=token,
match1=ldapQueryStringFromMatchExpression(
matchExpression1,
- self.fieldNameMap(service), self.recordTypeMap(service),
+ self.fieldNameMap(service),
+ self.recordTypeSchemas(service),
),
match2=ldapQueryStringFromMatchExpression(
matchExpression2,
- self.fieldNameMap(service), self.recordTypeMap(service),
+ self.fieldNameMap(service),
+ self.recordTypeSchemas(service),
),
)
self.assertEquals(queryString, expected)
@@ -431,11 +471,11 @@
)
queryString = ldapQueryStringFromExpression(
matchExpression,
- self.fieldNameMap(service), self.recordTypeMap(service),
+ self.fieldNameMap(service), self.recordTypeSchemas(service),
)
expected = ldapQueryStringFromMatchExpression(
matchExpression,
- self.fieldNameMap(service), self.recordTypeMap(service),
+ self.fieldNameMap(service), self.recordTypeSchemas(service),
)
self.assertEquals(queryString, expected)
@@ -461,5 +501,6 @@
self.assertRaises(
QueryNotSupportedError,
ldapQueryStringFromExpression,
- object(), self.fieldNameMap(service), self.recordTypeMap(service)
+ object(),
+ self.fieldNameMap(service), self.recordTypeSchemas(service)
)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140312/fd0d5298/attachment.html>
More information about the calendarserver-changes
mailing list