[CalendarServer-changes] [13079] CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/ directory/test
source_changes at macosforge.org
source_changes at macosforge.org
Mon Mar 31 18:41:25 PDT 2014
Revision: 13079
http://trac.calendarserver.org//changeset/13079
Author: wsanchez at apple.com
Date: 2014-03-31 18:41:25 -0700 (Mon, 31 Mar 2014)
Log Message:
-----------
obsolete
Removed Paths:
-------------
CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/test/test_ldapdirectory.py
CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/test/test_livedirectory.py
Deleted: CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/test/test_ldapdirectory.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/test/test_ldapdirectory.py 2014-04-01 01:41:02 UTC (rev 13078)
+++ CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/test/test_ldapdirectory.py 2014-04-01 01:41:25 UTC (rev 13079)
@@ -1,1856 +0,0 @@
-##
-# Copyright (c) 2011-2014 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.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-##
-from __future__ import print_function
-
-try:
- from twistedcaldav.directory.ldapdirectory import (
- buildFilter, buildFilterFromTokens, LdapDirectoryService,
- MissingGuidException, MissingRecordNameException,
- normalizeDNstr, dnContainedIn
- )
- from twistedcaldav.directory.util import splitIntoBatches
- from twistedcaldav.test.util import proxiesFile
- from twistedcaldav.directory.calendaruserproxyloader import (
- XMLCalendarUserProxyLoader
- )
- from twistedcaldav.directory import calendaruserproxy
- from twistedcaldav.directory.directory import (
- GroupMembershipCache, GroupMembershipCacheUpdater
- )
- from twisted.internet.defer import inlineCallbacks
- from string import maketrans
- import ldap
-except ImportError:
- print("Skipping because ldap module not installed")
-else:
- from twistedcaldav.test.util import TestCase
-
- class BuildFilterTestCase(TestCase):
-
- def test_buildFilter(self):
- mapping = {
- "recordName": "uid",
- "fullName": "cn",
- "emailAddresses": "mail",
- "firstName": "givenName",
- "lastName": "sn",
- "guid": "generateduid",
- "memberIDAttr": "generateduid",
- }
-
- entries = [
- {
- "fields": [
- ("fullName", "mor", True, u"starts-with"),
- ("emailAddresses", "mor", True, u"starts-with"),
- ("firstName", "mor", True, u"starts-with"),
- ("lastName", "mor", True, u"starts-with")
- ],
- "operand": "or",
- "recordType": "users",
- "expected": "(&(uid=*)(generateduid=*)(|(cn=mor*)(mail=mor*)(givenName=mor*)(sn=mor*)))",
- "optimize": False,
- },
- {
- "fields": [
- ("fullName", "mor(", True, u"starts-with"),
- ("emailAddresses", "mor)", True, u"contains"),
- ("firstName", "mor*", True, u"exact"),
- ("lastName", "mor\\", True, u"starts-with")
- ],
- "operand": "or",
- "recordType": "users",
- "expected": "(&(uid=*)(generateduid=*)(|(cn=mor\\28*)(mail=*mor\\29*)(givenName=mor\\2a)(sn=mor\\5c*)))",
- "optimize": False,
- },
- {
- "fields": [
- ("fullName", "mor", True, u"starts-with"),
- ],
- "operand": "or",
- "recordType": "users",
- "expected": "(&(uid=*)(generateduid=*)(cn=mor*))",
- "optimize": False,
- },
- {
- "fields": [
- ("fullName", "mor", True, u"contains"),
- ("emailAddresses", "mor", True, u"equals"),
- ("invalid", "mor", True, u"starts-with"),
- ],
- "operand": "and",
- "recordType": "users",
- "expected": "(&(uid=*)(generateduid=*)(&(cn=*mor*)(mail=mor)))",
- "optimize": False,
- },
- {
- "fields": [
- ("invalid", "mor", True, u"contains"),
- ("invalid", "mor", True, u"starts-with"),
- ],
- "operand": "and",
- "recordType": "users",
- "expected": None,
- "optimize": False,
- },
- {
- "fields": [],
- "operand": "and",
- "recordType": "users",
- "expected": None,
- "optimize": False,
- },
- {
- "fields": [
- ("fullName", "mor", True, u"starts-with"),
- ("fullName", "sag", True, u"starts-with"),
- ("emailAddresses", "mor", True, u"starts-with"),
- ("emailAddresses", "sag", True, u"starts-with"),
- ("firstName", "mor", True, u"starts-with"),
- ("firstName", "sag", True, u"starts-with"),
- ("lastName", "mor", True, u"starts-with"),
- ("lastName", "sag", True, u"starts-with"),
- ],
- "operand": "or",
- "recordType": "users",
- "expected": "(&(uid=*)(generateduid=*)(|(&(givenName=mor*)(sn=sag*))(&(givenName=sag*)(sn=mor*))))",
- "optimize": True,
- },
- {
- "fields": [
- ("fullName", "mor", True, u"starts-with"),
- ("fullName", "sag", True, u"starts-with"),
- ("emailAddresses", "mor", True, u"starts-with"),
- ("emailAddresses", "sag", True, u"starts-with"),
- ("firstName", "mor", True, u"starts-with"),
- ("firstName", "sag", True, u"starts-with"),
- ("lastName", "mor", True, u"starts-with"),
- ("lastName", "sag", True, u"starts-with"),
- ],
- "operand": "or",
- "recordType": "groups",
- "expected": None,
- "optimize": True,
- },
- {
- "fields": [
- ("fullName", "mor", True, u"starts-with"),
- ("fullName", "sag", True, u"starts-with"),
- ("emailAddresses", "mor", True, u"starts-with"),
- ("emailAddresses", "sag", True, u"starts-with"),
- ("firstName", "mor", True, u"starts-with"),
- ("firstName", "sag", True, u"starts-with"),
- ("lastName", "mor", True, u"starts-with"),
- ("lastName", "sag", True, u"starts-with"),
- ],
- "operand": "or",
- "recordType": "groups",
- "expected": None,
- "optimize": True,
- },
- {
- "fields": [
- ("guid", "xyzzy", True, u"equals"),
- ("guid", "plugh", True, u"equals"),
- ],
- "operand": "or",
- "recordType": "groups",
- "expected": "(&(uid=*)(generateduid=*)(|(generateduid=xyzzy)(generateduid=plugh)))",
- "optimize": True,
- },
- {
- "fields": [
- ("fullName", "mor", True, u"contains"),
- ("fullName", "sag", True, u"contains"),
- ],
- "operand": "or",
- "recordType": "locations",
- "expected": "(&(uid=*)(generateduid=*)(|(cn=*mor*)(cn=*sag*)))",
- "optimize": True,
- },
- {
- "fields": [
- ("fullName", "mor", True, u"contains"),
- ("fullName", "sag", True, u"contains"),
- ],
- "operand": "or",
- "recordType": "resources",
- "expected": "(&(uid=*)(generateduid=*)(|(cn=*mor*)(cn=*sag*)))",
- "optimize": True,
- },
- ]
- for entry in entries:
- self.assertEquals(
- buildFilter(entry["recordType"], mapping, entry["fields"],
- operand=entry["operand"], optimizeMultiName=entry["optimize"]),
- entry["expected"]
- )
-
-
- class BuildFilterFromTokensTestCase(TestCase):
-
- def test_buildFilterFromTokens(self):
-
- entries = [
- {
- "tokens": ["foo"],
- "mapping": {
- "fullName": "cn",
- "emailAddresses": "mail",
- },
- "expected": "(&(a=b)(|(cn=*foo*)(mail=foo*)))",
- "extra": "(a=b)",
- },
- {
- "tokens": ["foo", "foo", "oo", "fo", "bar"],
- "mapping": {
- "fullName": "cn",
- "emailAddresses": "mail",
- },
- "expected": "(&(a=b)(|(cn=*bar*)(mail=bar*))(|(cn=*foo*)(mail=foo*)))",
- "extra": "(a=b)",
- },
- {
- "tokens": ["fo", "foo", "foooo", "ooo", "fooo"],
- "mapping": {
- "fullName": "cn",
- "emailAddresses": "mail",
- },
- "expected": "(&(a=b)(|(cn=*foooo*)(mail=foooo*)))",
- "extra": "(a=b)",
- },
- {
- "tokens": ["foo"],
- "mapping": {
- "fullName": "cn",
- "emailAddresses": ["mail", "mailAliases"],
- },
- "expected": "(&(a=b)(|(cn=*foo*)(mail=foo*)(mailAliases=foo*)))",
- "extra": "(a=b)",
- },
- {
- "tokens": [],
- "mapping": {
- "fullName": "cn",
- "emailAddresses": "mail",
- },
- "expected": None,
- "extra": None,
- },
- {
- "tokens": ["foo", "bar"],
- "mapping": {},
- "expected": None,
- "extra": None,
- },
- {
- "tokens": ["foo", "bar"],
- "mapping": {
- "emailAddresses": "mail",
- },
- "expected": "(&(mail=bar*)(mail=foo*))",
- "extra": None,
- },
- {
- "tokens": ["foo", "bar"],
- "mapping": {
- "fullName": "cn",
- "emailAddresses": "mail",
- },
- "expected": "(&(|(cn=*bar*)(mail=bar*))(|(cn=*foo*)(mail=foo*)))",
- "extra": None,
- },
- {
- "tokens": ["foo", "bar"],
- "mapping": {
- "fullName": "cn",
- "emailAddresses": ["mail", "mailAliases"],
- },
- "expected": "(&(|(cn=*bar*)(mail=bar*)(mailAliases=bar*))(|(cn=*foo*)(mail=foo*)(mailAliases=foo*)))",
- "extra": None,
- },
- {
- "tokens": ["foo", "bar", "baz("],
- "mapping": {
- "fullName": "cn",
- "emailAddresses": "mail",
- },
- "expected": "(&(|(cn=*bar*)(mail=bar*))(|(cn=*baz\\28*)(mail=baz\\28*))(|(cn=*foo*)(mail=foo*)))",
- "extra": None,
- },
- ]
- for entry in entries:
- self.assertEquals(
- buildFilterFromTokens(None, entry["mapping"], entry["tokens"], extra=entry["extra"]),
- entry["expected"]
- )
-
-
- class StubList(object):
- def __init__(self, wrapper):
- self.ldap = wrapper
-
- def startSearch(self, base, scope, filterstr, attrList=None,
- timeout=-1, sizelimit=0):
- self.base = base
- self.scope = scope
- self.filterstr = filterstr
- self.attrList = attrList
- self.timeout = timeout
- self.sizelimit = sizelimit
-
- def processResults(self):
- self.allResults = self.ldap.search_s(self.base, self.scope,
- self.filterstr,
- attrlist=self.attrList)
-
-
- class StubAsync(object):
- def List(self, wrapper):
- return StubList(wrapper)
-
-
- class LdapDirectoryTestWrapper(object):
- """
- A test stub which replaces search_s( ) with a version that will return
- whatever you have previously called addTestResults( ) with.
- """
-
- def __init__(self, actual, records):
- self.actual = actual
- self.async = StubAsync()
-
- # Test data returned from search_s.
- # Note that some DNs have various extra whitespace added and mixed
- # up case since LDAP is pretty loose about these.
- self.records = records
-
-
- def search_s(self, base, scope, filterstr="(objectClass=*)",
- attrlist=None):
- """ A simple implementation of LDAP search filter processing """
-
- base = normalizeDNstr(base)
- results = []
- for dn, attrs in self.records:
- dn = normalizeDNstr(dn)
- if dn == base:
- results.append(("ignored", (dn, attrs)))
- elif dnContainedIn(ldap.dn.str2dn(dn), ldap.dn.str2dn(base)):
- if filterstr in ("(objectClass=*)", "(!(objectClass=organizationalUnit))"):
- results.append(("ignored", (dn, attrs)))
- else:
- trans = maketrans("&(|)", " |")
- fragments = filterstr.encode("utf-8").translate(trans).split("|")
- for fragment in fragments:
- if not fragment:
- continue
- fragment = fragment.strip()
- key, value = fragment.split("=")
- if value in attrs.get(key, []):
- results.append(("ignored", (dn, attrs)))
- break
- elif value == "*" and key in attrs:
- results.append(("ignored", (dn, attrs)))
- break
-
- return results
-
-
- class LdapDirectoryServiceTestCase(TestCase):
-
- nestedUsingDifferentAttributeUsingDN = (
- (
- (
- "cn=Recursive1_coasts, cn=gROUps,dc=example, dc=com",
- {
- 'cn': ['recursive1_coasts'],
- 'apple-generateduid': ['recursive1_coasts'],
- 'uniqueMember': [
- 'uid=wsanchez ,cn=users, dc=eXAMple,dc=com',
- ],
- 'nestedGroups': [
- 'cn=recursive2_coasts,cn=groups,dc=example,dc=com',
- ],
- }
- ),
- (
- "cn=recursive2_coasts,cn=groups,dc=example,dc=com",
- {
- 'cn': ['recursive2_coasts'],
- 'apple-generateduid': ['recursive2_coasts'],
- 'uniqueMember': [
- 'uid=cdaboo,cn=users,dc=example,dc=com',
- ],
- 'nestedGroups': [
- 'cn=recursive1_coasts,cn=groups,dc=example,dc=com',
- ],
- }
- ),
- (
- 'cn=both_coasts,cn=groups,dc=example,dc=com',
- {
- 'cn': ['both_coasts'],
- 'apple-generateduid': ['both_coasts'],
- 'nestedGroups': [
- 'cn=right_coast,cn=groups,dc=example,dc=com',
- 'cn=left_coast,cn=groups,dc=example,dc=com',
- ],
- }
- ),
- (
- 'cn=right_coast,cn=groups,dc=example,dc=com',
- {
- 'cn': ['right_coast'],
- 'apple-generateduid': ['right_coast'],
- 'uniqueMember': [
- 'uid=cdaboo,cn=users,dc=example,dc=com',
- ],
- }
- ),
- (
- 'cn=left_coast,cn=groups,dc=example,dc=com',
- {
- 'cn': ['left_coast'],
- 'apple-generateduid': ['left_coast'],
- 'uniqueMember': [
- 'uid=wsanchez, cn=users,dc=example,dc=com',
- 'uid=lecroy,cn=users,dc=example,dc=com',
- 'uid=dreid,cn=users,dc=example,dc=com',
- ],
- }
- ),
- (
- "uid=odtestamanda,cn=users,dc=example,dc=com",
- {
- 'uid': ['odtestamanda'],
- # purposely throw in an un-normalized GUID
- 'apple-generateduid': ['9dc04a70-e6dd-11df-9492-0800200c9a66'],
- 'sn': ['Test'],
- 'mail': ['odtestamanda at example.com', 'alternate at example.com'],
- 'givenName': ['Amanda'],
- 'cn': ['Amanda Test']
- }
- ),
- (
- "uid=odtestbetty,cn=users,dc=example,dc=com",
- {
- 'uid': ['odtestbetty'],
- 'apple-generateduid': ['93A8F5C5-49D8-4641-840F-CD1903B0394C'],
- 'sn': ['Test'],
- 'mail': ['odtestbetty at example.com'],
- 'givenName': ['Betty'],
- 'cn': ['Betty Test']
- }
- ),
- (
- "uid=odtestcarlene,cn=users,dc=example,dc=com",
- {
- 'uid': ['odtestcarlene'],
- # Note: no guid here, to test this record is skipped
- 'sn': ['Test'],
- 'mail': ['odtestcarlene at example.com'],
- 'givenName': ['Carlene'],
- 'cn': ['Carlene Test']
- }
- ),
- (
- "uid=cdaboo,cn=users,dc=example,dc=com",
- {
- 'uid': ['cdaboo'],
- 'apple-generateduid': ['5A985493-EE2C-4665-94CF-4DFEA3A89500'],
- 'sn': ['Daboo'],
- 'mail': ['daboo at example.com'],
- 'givenName': ['Cyrus'],
- 'cn': ['Cyrus Daboo']
- }
- ),
- (
- "uid=wsanchez , cn=users , dc=example,dc=com",
- {
- 'uid': ['wsanchez'],
- 'apple-generateduid': ['6423F94A-6B76-4A3A-815B-D52CFD77935D'],
- 'sn': ['Sanchez'],
- 'mail': ['wsanchez at example.com'],
- 'givenName': ['Wilfredo'],
- 'cn': ['Wilfredo Sanchez']
- }
- ),
- (
- "uid=testresource , cn=resources , dc=example,dc=com",
- {
- 'uid': ['testresource'],
- 'apple-generateduid': ['D91B21B9-B856-495A-8E36-0E5AD54EFB3A'],
- 'sn': ['Resource'],
- 'givenName': ['Test'],
- 'cn': ['Test Resource'],
- # purposely throw in an un-normalized GUID
- 'read-write-proxy': ['6423f94a-6b76-4a3a-815b-d52cfd77935d'],
- 'read-only-proxy': ['5A985493-EE2C-4665-94CF-4DFEA3A89500'],
- }
- ),
- (
- "uid=testresource2 , cn=resources , dc=example,dc=com",
- {
- 'uid': ['testresource2'],
- 'apple-generateduid': ['753E5A60-AFFD-45E4-BF2C-31DAB459353F'],
- 'sn': ['Resource2'],
- 'givenName': ['Test'],
- 'cn': ['Test Resource2'],
- 'read-write-proxy': ['6423F94A-6B76-4A3A-815B-D52CFD77935D'],
- }
- ),
- ),
- {
- "augmentService": None,
- "groupMembershipCache": None,
- "cacheTimeout": 1, # Minutes
- "negativeCaching": False,
- "warningThresholdSeconds": 3,
- "batchSize": 500,
- "queryLocationsImplicitly": True,
- "restrictEnabledRecords": True,
- "restrictToGroup": "both_coasts",
- "recordTypes": ("users", "groups", "locations", "resources"),
- "uri": "ldap://localhost/",
- "tls": False,
- "tlsCACertFile": None,
- "tlsCACertDir": None,
- "tlsRequireCert": None, # never, allow, try, demand, hard
- "credentials": {
- "dn": None,
- "password": None,
- },
- "authMethod": "LDAP",
- "rdnSchema": {
- "base": "dc=example,dc=com",
- "guidAttr": "apple-generateduid",
- "users": {
- "rdn": "cn=Users",
- "attr": "uid", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "", # additional filter for this type
- "loginEnabledAttr": "", # attribute controlling login
- "loginEnabledValue": "yes", # "True" value of above attribute
- "calendarEnabledAttr": "enable-calendar", # attribute controlling calendaring
- "calendarEnabledValue": "yes", # "True" value of above attribute
- "mapping": { # maps internal record names to LDAP
- "recordName": "uid",
- "fullName": "cn",
- "emailAddresses": ["mail", "emailAliases"],
- "firstName": "givenName",
- "lastName": "sn",
- },
- },
- "groups": {
- "rdn": "cn=Groups",
- "attr": "cn", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "", # additional filter for this type
- "mapping": { # maps internal record names to LDAP
- "recordName": "cn",
- "fullName": "cn",
- "emailAddresses": ["mail", "emailAliases"],
- },
- },
- "locations": {
- "rdn": "cn=Places",
- "attr": "cn", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "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
- },
- },
- "resources": {
- "rdn": "cn=Resources",
- "attr": "cn", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "(objectClass=apple-resource)", # additional filter for this type
- "calendarEnabledAttr": "", # attribute controlling calendaring
- "calendarEnabledValue": "yes", # "True" value of above attribute
- "mapping": { # maps internal record names to LDAP
- "recordName": "cn",
- "fullName": "cn",
- "emailAddresses": [], # new style, array
- },
- },
- "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
- "nestedGroupsAttr": "nestedGroups", # how nested groups are specified
- "memberIdAttr": "", # which attribute the above refer to
- },
- "resourceSchema": {
- "resourceInfoAttr": "apple-resource-info", # contains location/resource info
- "autoScheduleAttr": None,
- "proxyAttr": "read-write-proxy",
- "readOnlyProxyAttr": "read-only-proxy",
- "autoAcceptGroupAttr": None,
- },
- "poddingSchema": {
- "serverIdAttr": "server-id", # maps to augments server-id
- },
- }
- )
- nestedUsingSameAttributeUsingDN = (
- (
- (
- "cn=Recursive1_coasts, cn=gROUps,dc=example, dc=com",
- {
- 'cn': ['recursive1_coasts'],
- 'apple-generateduid': ['recursive1_coasts'],
- 'uniqueMember': [
- 'uid=wsanchez ,cn=users, dc=eXAMple,dc=com',
- 'cn=recursive2_coasts,cn=groups,dc=example,dc=com',
- ],
- }
- ),
- (
- "cn=recursive2_coasts,cn=groups,dc=example,dc=com",
- {
- 'cn': ['recursive2_coasts'],
- 'apple-generateduid': ['recursive2_coasts'],
- 'uniqueMember': [
- 'uid=cdaboo,cn=users,dc=example,dc=com',
- 'cn=recursive1_coasts,cn=groups,dc=example,dc=com',
- ],
- }
- ),
- (
- 'cn=both_coasts,cn=groups,dc=example,dc=com',
- {
- 'cn': ['both_coasts'],
- 'apple-generateduid': ['both_coasts'],
- 'uniqueMember': [
- 'cn=right_coast,cn=groups,dc=example,dc=com',
- 'cn=left_coast,cn=groups,dc=example,dc=com',
- ],
- }
- ),
- (
- 'cn=right_coast,cn=groups,dc=example,dc=com',
- {
- 'cn': ['right_coast'],
- 'apple-generateduid': ['right_coast'],
- 'uniqueMember': [
- 'uid=cdaboo,cn=users,dc=example,dc=com',
- ],
- }
- ),
- (
- 'cn=left_coast,cn=groups,dc=example,dc=com',
- {
- 'cn': ['left_coast'],
- 'apple-generateduid': ['left_coast'],
- 'uniqueMember': [
- 'uid=wsanchez, cn=users,dc=example,dc=com',
- 'uid=lecroy,cn=users,dc=example,dc=com',
- 'uid=dreid,cn=users,dc=example,dc=com',
- ],
- }
- ),
- (
- "uid=odtestamanda,cn=users,dc=example,dc=com",
- {
- 'uid': ['odtestamanda'],
- 'apple-generateduid': ['9DC04A70-E6DD-11DF-9492-0800200C9A66'],
- 'sn': ['Test'],
- 'mail': ['odtestamanda at example.com', 'alternate at example.com'],
- 'givenName': ['Amanda'],
- 'cn': ['Amanda Test']
- }
- ),
- (
- "uid=odtestbetty,cn=users,dc=example,dc=com",
- {
- 'uid': ['odtestbetty'],
- 'apple-generateduid': ['93A8F5C5-49D8-4641-840F-CD1903B0394C'],
- 'sn': ['Test'],
- 'mail': ['odtestbetty at example.com'],
- 'givenName': ['Betty'],
- 'cn': ['Betty Test']
- }
- ),
- (
- "uid=odtestcarlene,cn=users,dc=example,dc=com",
- {
- 'uid': ['odtestcarlene'],
- # Note: no guid here, to test this record is skipped
- 'sn': ['Test'],
- 'mail': ['odtestcarlene at example.com'],
- 'givenName': ['Carlene'],
- 'cn': ['Carlene Test']
- }
- ),
- (
- "uid=cdaboo,cn=users,dc=example,dc=com",
- {
- 'uid': ['cdaboo'],
- 'apple-generateduid': ['5A985493-EE2C-4665-94CF-4DFEA3A89500'],
- 'sn': ['Daboo'],
- 'mail': ['daboo at example.com'],
- 'givenName': ['Cyrus'],
- 'cn': ['Cyrus Daboo']
- }
- ),
- (
- "uid=wsanchez , cn=users , dc=example,dc=com",
- {
- 'uid': ['wsanchez'],
- 'apple-generateduid': ['6423F94A-6B76-4A3A-815B-D52CFD77935D'],
- 'sn': ['Sanchez'],
- 'mail': ['wsanchez at example.com'],
- 'givenName': ['Wilfredo'],
- 'cn': ['Wilfredo Sanchez']
- }
- ),
- ),
- {
- "augmentService": None,
- "groupMembershipCache": None,
- "cacheTimeout": 1, # Minutes
- "negativeCaching": False,
- "warningThresholdSeconds": 3,
- "batchSize": 500,
- "queryLocationsImplicitly": True,
- "restrictEnabledRecords": True,
- "restrictToGroup": "both_coasts",
- "recordTypes": ("users", "groups", "locations", "resources"),
- "uri": "ldap://localhost/",
- "tls": False,
- "tlsCACertFile": None,
- "tlsCACertDir": None,
- "tlsRequireCert": None, # never, allow, try, demand, hard
- "credentials": {
- "dn": None,
- "password": None,
- },
- "authMethod": "LDAP",
- "rdnSchema": {
- "base": "dc=example,dc=com",
- "guidAttr": "apple-generateduid",
- "users": {
- "rdn": "cn=Users",
- "attr": "uid", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "", # additional filter for this type
- "loginEnabledAttr": "", # attribute controlling login
- "loginEnabledValue": "yes", # "True" value of above attribute
- "calendarEnabledAttr": "enable-calendar", # attribute controlling calendaring
- "calendarEnabledValue": "yes", # "True" value of above attribute
- "mapping": { # maps internal record names to LDAP
- "recordName": "uid",
- "fullName": "cn",
- "emailAddresses": ["mail", "emailAliases"],
- "firstName": "givenName",
- "lastName": "sn",
- },
- },
- "groups": {
- "rdn": "cn=Groups",
- "attr": "cn", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "", # additional filter for this type
- "mapping": { # maps internal record names to LDAP
- "recordName": "cn",
- "fullName": "cn",
- "emailAddresses": ["mail", "emailAliases"],
- "firstName": "givenName",
- "lastName": "sn",
- },
- },
- "locations": {
- "rdn": "cn=Places",
- "attr": "cn", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "(objectClass=apple-resource)", # additional filter for this type
- "calendarEnabledAttr": "", # attribute controlling calendaring
- "calendarEnabledValue": "yes", # "True" value of above attribute
- "mapping": { # maps internal record names to LDAP
- "recordName": "cn",
- "fullName": "cn",
- "emailAddresses": "", # old style, single string
- "firstName": "givenName",
- "lastName": "sn",
- },
- },
- "resources": {
- "rdn": "cn=Resources",
- "attr": "cn", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "(objectClass=apple-resource)", # additional filter for this type
- "calendarEnabledAttr": "", # attribute controlling calendaring
- "calendarEnabledValue": "yes", # "True" value of above attribute
- "mapping": { # maps internal record names to LDAP
- "recordName": "cn",
- "fullName": "cn",
- "emailAddresses": [], # new style, array
- "firstName": "givenName",
- "lastName": "sn",
- },
- },
- },
- "groupSchema": {
- "membersAttr": "uniqueMember", # how members are specified
- "nestedGroupsAttr": "", # how nested groups are specified
- "memberIdAttr": "", # which attribute the above refer to
- },
- "resourceSchema": {
- "resourceInfoAttr": "apple-resource-info", # contains location/resource info
- "autoScheduleAttr": None,
- "proxyAttr": None,
- "readOnlyProxyAttr": None,
- "autoAcceptGroupAttr": None,
- },
- "poddingSchema": {
- "serverIdAttr": "server-id", # maps to augments server-id
- },
- }
- )
- nestedUsingDifferentAttributeUsingGUID = (
- (
- (
- "cn=Recursive1_coasts, cn=gROUps,dc=example, dc=com",
- {
- 'cn': ['recursive1_coasts'],
- 'apple-generateduid': ['recursive1_coasts'],
- 'uniqueMember': [
- '6423F94A-6B76-4A3A-815B-D52CFD77935D',
- ],
- 'nestedGroups': [
- 'recursive2_coasts',
- ],
- }
- ),
- (
- "cn=recursive2_coasts,cn=groups,dc=example,dc=com",
- {
- 'cn': ['recursive2_coasts'],
- 'apple-generateduid': ['recursive2_coasts'],
- 'uniqueMember': [
- '5A985493-EE2C-4665-94CF-4DFEA3A89500',
- ],
- 'nestedGroups': [
- 'recursive1_coasts',
- ],
- }
- ),
- (
- 'cn=both_coasts,cn=groups,dc=example,dc=com',
- {
- 'cn': ['both_coasts'],
- 'apple-generateduid': ['both_coasts'],
- 'nestedGroups': [
- 'right_coast',
- 'left_coast',
- ],
- }
- ),
- (
- 'cn=right_coast,cn=groups,dc=example,dc=com',
- {
- 'cn': ['right_coast'],
- 'apple-generateduid': ['right_coast'],
- 'uniqueMember': [
- '5A985493-EE2C-4665-94CF-4DFEA3A89500',
- ],
- }
- ),
- (
- 'cn=left_coast,cn=groups,dc=example,dc=com',
- {
- 'cn': ['left_coast'],
- 'apple-generateduid': ['left_coast'],
- 'uniqueMember': [
- '6423F94A-6B76-4A3A-815B-D52CFD77935D',
- ],
- }
- ),
- (
- "uid=odtestamanda,cn=users,dc=example,dc=com",
- {
- 'uid': ['odtestamanda'],
- 'apple-generateduid': ['9DC04A70-E6DD-11DF-9492-0800200C9A66'],
- 'sn': ['Test'],
- 'mail': ['odtestamanda at example.com', 'alternate at example.com'],
- 'givenName': ['Amanda'],
- 'cn': ['Amanda Test']
- }
- ),
- (
- "uid=odtestbetty,cn=users,dc=example,dc=com",
- {
- 'uid': ['odtestbetty'],
- 'apple-generateduid': ['93A8F5C5-49D8-4641-840F-CD1903B0394C'],
- 'sn': ['Test'],
- 'mail': ['odtestbetty at example.com'],
- 'givenName': ['Betty'],
- 'cn': ['Betty Test']
- }
- ),
- (
- "uid=odtestcarlene,cn=users,dc=example,dc=com",
- {
- 'uid': ['odtestcarlene'],
- # Note: no guid here, to test this record is skipped
- 'sn': ['Test'],
- 'mail': ['odtestcarlene at example.com'],
- 'givenName': ['Carlene'],
- 'cn': ['Carlene Test']
- }
- ),
- (
- "uid=cdaboo,cn=users,dc=example,dc=com",
- {
- 'uid': ['cdaboo'],
- 'apple-generateduid': ['5A985493-EE2C-4665-94CF-4DFEA3A89500'],
- 'sn': ['Daboo'],
- 'mail': ['daboo at example.com'],
- 'givenName': ['Cyrus'],
- 'cn': ['Cyrus Daboo']
- }
- ),
- (
- "uid=wsanchez , cn=users , dc=example,dc=com",
- {
- 'uid': ['wsanchez'],
- 'apple-generateduid': ['6423F94A-6B76-4A3A-815B-D52CFD77935D'],
- 'sn': ['Sanchez'],
- 'mail': ['wsanchez at example.com'],
- 'givenName': ['Wilfredo'],
- 'cn': ['Wilfredo Sanchez']
- }
- ),
- ),
- {
- "augmentService": None,
- "groupMembershipCache": None,
- "cacheTimeout": 1, # Minutes
- "negativeCaching": False,
- "warningThresholdSeconds": 3,
- "batchSize": 500,
- "queryLocationsImplicitly": True,
- "restrictEnabledRecords": True,
- "restrictToGroup": "both_coasts",
- "recordTypes": ("users", "groups", "locations", "resources"),
- "uri": "ldap://localhost/",
- "tls": False,
- "tlsCACertFile": None,
- "tlsCACertDir": None,
- "tlsRequireCert": None, # never, allow, try, demand, hard
- "credentials": {
- "dn": None,
- "password": None,
- },
- "authMethod": "LDAP",
- "rdnSchema": {
- "base": "dc=example,dc=com",
- "guidAttr": "apple-generateduid",
- "users": {
- "rdn": "cn=Users",
- "attr": "uid", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "", # additional filter for this type
- "loginEnabledAttr": "", # attribute controlling login
- "loginEnabledValue": "yes", # "True" value of above attribute
- "calendarEnabledAttr": "enable-calendar", # attribute controlling calendaring
- "calendarEnabledValue": "yes", # "True" value of above attribute
- "mapping": { # maps internal record names to LDAP
- "recordName": "uid",
- "fullName": "cn",
- "emailAddresses": ["mail", "emailAliases"],
- "firstName": "givenName",
- "lastName": "sn",
- },
- },
- "groups": {
- "rdn": "cn=Groups",
- "attr": "cn", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "", # additional filter for this type
- "mapping": { # maps internal record names to LDAP
- "recordName": "cn",
- "fullName": "cn",
- "emailAddresses": ["mail", "emailAliases"],
- "firstName": "givenName",
- "lastName": "sn",
- },
- },
- "locations": {
- "rdn": "cn=Places",
- "attr": "cn", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "(objectClass=apple-resource)", # additional filter for this type
- "calendarEnabledAttr": "", # attribute controlling calendaring
- "calendarEnabledValue": "yes", # "True" value of above attribute
- "mapping": { # maps internal record names to LDAP
- "recordName": "cn",
- "fullName": "cn",
- "emailAddresses": "", # old style, single string
- "firstName": "givenName",
- "lastName": "sn",
- },
- },
- "resources": {
- "rdn": "cn=Resources",
- "attr": "cn", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "(objectClass=apple-resource)", # additional filter for this type
- "calendarEnabledAttr": "", # attribute controlling calendaring
- "calendarEnabledValue": "yes", # "True" value of above attribute
- "mapping": { # maps internal record names to LDAP
- "recordName": "cn",
- "fullName": "cn",
- "emailAddresses": [], # new style, array
- "firstName": "givenName",
- "lastName": "sn",
- },
- },
- },
- "groupSchema": {
- "membersAttr": "uniqueMember", # how members are specified
- "nestedGroupsAttr": "nestedGroups", # how nested groups are specified
- "memberIdAttr": "apple-generateduid", # which attribute the above refer to
- },
- "resourceSchema": {
- "resourceInfoAttr": "apple-resource-info", # contains location/resource info
- "autoScheduleAttr": None,
- "proxyAttr": None,
- "readOnlyProxyAttr": None,
- "autoAcceptGroupAttr": None,
- },
- "poddingSchema": {
- "serverIdAttr": "server-id", # maps to augments server-id
- },
- }
- )
- nestedUsingSameAttributeUsingGUID = (
- (
- (
- "cn=Recursive1_coasts, cn=gROUps,dc=example, dc=com",
- {
- 'cn': ['recursive1_coasts'],
- 'apple-generateduid': ['recursive1_coasts'],
- 'uniqueMember': [
- '6423F94A-6B76-4A3A-815B-D52CFD77935D',
- 'recursive2_coasts',
- ],
- }
- ),
- (
- "cn=recursive2_coasts,cn=groups,dc=example,dc=com",
- {
- 'cn': ['recursive2_coasts'],
- 'apple-generateduid': ['recursive2_coasts'],
- 'uniqueMember': [
- '5A985493-EE2C-4665-94CF-4DFEA3A89500',
- 'recursive1_coasts',
- ],
- }
- ),
- (
- 'cn=both_coasts,cn=groups,dc=example,dc=com',
- {
- 'cn': ['both_coasts'],
- 'apple-generateduid': ['both_coasts'],
- 'uniqueMember': [
- 'right_coast',
- 'left_coast',
- ],
- }
- ),
- (
- 'cn=right_coast,cn=groups,dc=example,dc=com',
- {
- 'cn': ['right_coast'],
- 'apple-generateduid': ['right_coast'],
- 'uniqueMember': [
- '5A985493-EE2C-4665-94CF-4DFEA3A89500',
- ],
- }
- ),
- (
- 'cn=left_coast,cn=groups,dc=example,dc=com',
- {
- 'cn': ['left_coast'],
- 'apple-generateduid': ['left_coast'],
- 'uniqueMember': [
- '6423F94A-6B76-4A3A-815B-D52CFD77935D',
- ],
- }
- ),
- (
- "uid=odtestamanda,cn=users,dc=example,dc=com",
- {
- 'uid': ['odtestamanda'],
- 'apple-generateduid': ['9DC04A70-E6DD-11DF-9492-0800200C9A66'],
- 'sn': ['Test'],
- 'mail': ['odtestamanda at example.com', 'alternate at example.com'],
- 'givenName': ['Amanda'],
- 'cn': ['Amanda Test']
- }
- ),
- (
- "uid=odtestbetty,cn=users,dc=example,dc=com",
- {
- 'uid': ['odtestbetty'],
- 'apple-generateduid': ['93A8F5C5-49D8-4641-840F-CD1903B0394C'],
- 'sn': ['Test'],
- 'mail': ['odtestbetty at example.com'],
- 'givenName': ['Betty'],
- 'cn': ['Betty Test']
- }
- ),
- (
- "uid=odtestcarlene,cn=users,dc=example,dc=com",
- {
- 'uid': ['odtestcarlene'],
- # Note: no guid here, to test this record is skipped
- 'sn': ['Test'],
- 'mail': ['odtestcarlene at example.com'],
- 'givenName': ['Carlene'],
- 'cn': ['Carlene Test']
- }
- ),
- (
- "uid=cdaboo,cn=users,dc=example,dc=com",
- {
- 'uid': ['cdaboo'],
- 'apple-generateduid': ['5A985493-EE2C-4665-94CF-4DFEA3A89500'],
- 'sn': ['Daboo'],
- 'mail': ['daboo at example.com'],
- 'givenName': ['Cyrus'],
- 'cn': ['Cyrus Daboo']
- }
- ),
- (
- "uid=wsanchez , cn=users , dc=example,dc=com",
- {
- 'uid': ['wsanchez'],
- 'apple-generateduid': ['6423F94A-6B76-4A3A-815B-D52CFD77935D'],
- 'sn': ['Sanchez'],
- 'mail': ['wsanchez at example.com'],
- 'givenName': ['Wilfredo'],
- 'cn': ['Wilfredo Sanchez']
- }
- ),
- ),
- {
- "augmentService": None,
- "groupMembershipCache": None,
- "cacheTimeout": 1, # Minutes
- "negativeCaching": False,
- "warningThresholdSeconds": 3,
- "batchSize": 500,
- "queryLocationsImplicitly": True,
- "restrictEnabledRecords": True,
- "restrictToGroup": "both_coasts",
- "recordTypes": ("users", "groups", "locations", "resources"),
- "uri": "ldap://localhost/",
- "tls": False,
- "tlsCACertFile": None,
- "tlsCACertDir": None,
- "tlsRequireCert": None, # never, allow, try, demand, hard
- "credentials": {
- "dn": None,
- "password": None,
- },
- "authMethod": "LDAP",
- "rdnSchema": {
- "base": "dc=example,dc=com",
- "guidAttr": "apple-generateduid",
- "users": {
- "rdn": "cn=Users",
- "attr": "uid", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "", # additional filter for this type
- "loginEnabledAttr": "", # attribute controlling login
- "loginEnabledValue": "yes", # "True" value of above attribute
- "calendarEnabledAttr": "enable-calendar", # attribute controlling calendaring
- "calendarEnabledValue": "yes", # "True" value of above attribute
- "mapping": { # maps internal record names to LDAP
- "recordName": "uid",
- "fullName": "cn",
- "emailAddresses": ["mail", "emailAliases"],
- "firstName": "givenName",
- "lastName": "sn",
- },
- },
- "groups": {
- "rdn": "cn=Groups",
- "attr": "cn", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "", # additional filter for this type
- "mapping": { # maps internal record names to LDAP
- "recordName": "cn",
- "fullName": "cn",
- "emailAddresses": ["mail", "emailAliases"],
- "firstName": "givenName",
- "lastName": "sn",
- },
- },
- "locations": {
- "rdn": "cn=Places",
- "attr": "cn", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "(objectClass=apple-resource)", # additional filter for this type
- "calendarEnabledAttr": "", # attribute controlling calendaring
- "calendarEnabledValue": "yes", # "True" value of above attribute
- "mapping": { # maps internal record names to LDAP
- "recordName": "cn",
- "fullName": "cn",
- "emailAddresses": "", # old style, single string
- "firstName": "givenName",
- "lastName": "sn",
- },
- },
- "resources": {
- "rdn": "cn=Resources",
- "attr": "cn", # used only to synthesize email address
- "emailSuffix": None, # used only to synthesize email address
- "filter": "(objectClass=apple-resource)", # additional filter for this type
- "calendarEnabledAttr": "", # attribute controlling calendaring
- "calendarEnabledValue": "yes", # "True" value of above attribute
- "mapping": { # maps internal record names to LDAP
- "recordName": "cn",
- "fullName": "cn",
- "emailAddresses": [], # new style, array
- "firstName": "givenName",
- "lastName": "sn",
- },
- },
- },
- "groupSchema": {
- "membersAttr": "uniqueMember", # how members are specified
- "nestedGroupsAttr": "", # how nested groups are specified
- "memberIdAttr": "apple-generateduid", # which attribute the above refer to
- },
- "resourceSchema": {
- "resourceInfoAttr": "apple-resource-info", # contains location/resource info
- "autoScheduleAttr": None,
- "proxyAttr": None,
- "readOnlyProxyAttr": None,
- "autoAcceptGroupAttr": None,
- },
- "poddingSchema": {
- "serverIdAttr": "server-id", # maps to augments server-id
- },
- }
- )
-
-
- def setupService(self, scenario):
- self.service = LdapDirectoryService(scenario[1])
- self.service.ldap = LdapDirectoryTestWrapper(self.service.ldap, scenario[0])
- self.patch(ldap, "async", StubAsync())
-
-
- def test_ldapWrapper(self):
- """
- Exercise the fake search_s implementation
- """
- self.setupService(self.nestedUsingDifferentAttributeUsingDN)
-
- # Get all groups
- self.assertEquals(
- len(self.service.ldap.search_s("cn=groups,dc=example,dc=com", 0, "(objectClass=*)", [])), 5)
-
- self.assertEquals(
- len(self.service.ldap.search_s("cn=recursive1_coasts,cn=groups,dc=example,dc=com", 2, "(objectClass=*)", [])), 1)
-
- self.assertEquals(
- len(self.service.ldap.search_s("cn=groups,dc=example,dc=com", 0, "(|(apple-generateduid=right_coast)(apple-generateduid=left_coast))", [])), 2)
-
-
- def test_ldapRecordCreation(self):
- """
- Exercise _ldapResultToRecord(), which converts a dictionary
- of LDAP attributes into an LdapDirectoryRecord
- """
- self.setupService(self.nestedUsingDifferentAttributeUsingDN)
-
- # User without enabled-for-calendaring specified
-
- dn = "uid=odtestamanda,cn=users,dc=example,dc=com"
- guid = '9DC04A70-E6DD-11DF-9492-0800200C9A66'
- attrs = {
- 'uid': ['odtestamanda'],
- 'apple-generateduid': [guid],
- 'sn': ['Test'],
- 'mail': ['odtestamanda at example.com', 'alternate at example.com'],
- 'givenName': ['Amanda'],
- 'cn': ['Amanda Test']
- }
-
- record = self.service._ldapResultToRecord(
- dn, attrs, self.service.recordType_users
- )
- self.assertEquals(record.guid, guid)
- self.assertEquals(
- record.emailAddresses,
- set(['alternate at example.com', 'odtestamanda at example.com'])
- )
- self.assertEquals(record.shortNames, ('odtestamanda',))
- self.assertEquals(record.fullName, 'Amanda Test')
- self.assertEquals(record.firstName, 'Amanda')
- self.assertEquals(record.lastName, 'Test')
- self.assertEquals(record.serverID, None)
- self.assertFalse(record.enabledForCalendaring)
-
- # User with enabled-for-calendaring specified
-
- dn = "uid=odtestamanda,cn=users,dc=example,dc=com"
- guid = '9DC04A70-E6DD-11DF-9492-0800200C9A66'
- attrs = {
- 'uid': ['odtestamanda'],
- 'apple-generateduid': [guid],
- 'enable-calendar': ["yes"],
- 'sn': ['Test'],
- 'mail': ['odtestamanda at example.com', 'alternate at example.com'],
- 'givenName': ['Amanda'],
- 'cn': ['Amanda Test']
- }
-
- record = self.service._ldapResultToRecord(
- dn, attrs, self.service.recordType_users
- )
- self.assertTrue(record.enabledForCalendaring)
-
- # User with "podding" info
-
- dn = "uid=odtestamanda,cn=users,dc=example,dc=com"
- guid = '9DC04A70-E6DD-11DF-9492-0800200C9A66'
- attrs = {
- 'uid': ['odtestamanda'],
- 'apple-generateduid': [guid],
- 'cn': ['Amanda Test'],
- 'server-id': ["test-server-id"],
- }
-
- record = self.service._ldapResultToRecord(
- dn, attrs, self.service.recordType_users
- )
- self.assertEquals(record.serverID, "test-server-id")
-
- # User missing guidAttr
-
- dn = "uid=odtestamanda,cn=users,dc=example,dc=com"
- attrs = {
- 'uid': ['odtestamanda'],
- 'cn': ['Amanda Test'],
- }
-
- self.assertRaises(
- MissingGuidException,
- self.service._ldapResultToRecord, dn, attrs,
- self.service.recordType_users
- )
-
- # User missing record name
-
- dn = "uid=odtestamanda,cn=users,dc=example,dc=com"
- attrs = {
- 'apple-generateduid': ['9ABDD881-B3A4-4065-9DA7-12095F40A898'],
- 'cn': ['Amanda Test'],
- }
-
- self.assertRaises(
- MissingRecordNameException,
- self.service._ldapResultToRecord, dn, attrs,
- self.service.recordType_users
- )
-
- # Group with direct user members and nested group
-
- dn = "cn=odtestgrouptop,cn=groups,dc=example,dc=com"
- guid = '6C6CD280-E6E3-11DF-9492-0800200C9A66'
- attrs = {
- 'apple-generateduid': [guid],
- 'uniqueMember': [
- 'uid=odtestamanda,cn=users,dc=example,dc=com',
- 'uid=odtestbetty,cn=users,dc=example,dc=com',
- 'cn=odtestgroupb,cn=groups,dc=example,dc=com',
- ],
- 'cn': ['odtestgrouptop']
- }
- record = self.service._ldapResultToRecord(
- dn, attrs, self.service.recordType_groups
- )
- self.assertEquals(record.guid, guid)
- self.assertEquals(
- record.memberGUIDs(),
- set(
- [
- 'cn=odtestgroupb,cn=groups,dc=example,dc=com',
- 'uid=odtestamanda,cn=users,dc=example,dc=com',
- 'uid=odtestbetty,cn=users,dc=example,dc=com',
- ]
- )
- )
-
- # Group with illegal DN value in members
-
- dn = "cn=odtestgrouptop,cn=groups,dc=example,dc=com"
- guid = '6C6CD280-E6E3-11DF-9492-0800200C9A66'
- attrs = {
- 'apple-generateduid': [guid],
- 'uniqueMember': [
- 'uid=odtestamanda,cn=users,dc=example,dc=com',
- 'uid=odtestbetty ,cn=users,dc=example,dc=com',
- 'cn=odtestgroupb+foo,cn=groups,dc=example,dc=com',
- ],
- 'cn': ['odtestgrouptop']
- }
- record = self.service._ldapResultToRecord(
- dn, attrs, self.service.recordType_groups
- )
- self.assertEquals(record.guid, guid)
- self.assertEquals(
- record.memberGUIDs(),
- set(
- [
- 'uid=odtestamanda,cn=users,dc=example,dc=com',
- 'uid=odtestbetty,cn=users,dc=example,dc=com',
- ]
- )
- )
-
- # Resource with delegates, autoSchedule = True, and autoAcceptGroup
-
- dn = "cn=odtestresource,cn=resources,dc=example,dc=com"
- guid = 'D3094652-344B-4633-8DB8-09639FA00FB6'
- attrs = {
- 'apple-generateduid': [guid],
- 'cn': ['odtestresource'],
- 'apple-resource-info': ["""<?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>CalendaringDelegate</key>
-<string>6C6CD280-E6E3-11DF-9492-0800200C9A66</string>
-<key>ReadOnlyCalendaringDelegate</key>
-<string>6AA1AE12-592F-4190-A069-547CD83C47C0</string>
-<key>AutoAcceptGroup</key>
-<string>77A8EB52-AA2A-42ED-8843-B2BEE863AC70</string>
-</dict>
-</dict>
-</plist>"""]
- }
- record = self.service._ldapResultToRecord(
- dn, attrs, self.service.recordType_resources
- )
- self.assertEquals(record.guid, guid)
- self.assertEquals(
- record.externalProxies(),
- set(['6C6CD280-E6E3-11DF-9492-0800200C9A66'])
- )
- self.assertEquals(
- record.externalReadOnlyProxies(),
- set(['6AA1AE12-592F-4190-A069-547CD83C47C0'])
- )
- self.assertTrue(record.autoSchedule)
- self.assertEquals(
- record.autoAcceptGroup, '77A8EB52-AA2A-42ED-8843-B2BEE863AC70'
- )
-
- # Resource with no delegates and autoSchedule = False
-
- dn = "cn=odtestresource,cn=resources,dc=example,dc=com"
- guid = 'D3094652-344B-4633-8DB8-09639FA00FB6'
- attrs = {
- 'apple-generateduid': [guid],
- 'cn': ['odtestresource'],
- 'apple-resource-info': ["""<?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>
-<false/>
-</dict>
-</dict>
-</plist>"""]
- }
- record = self.service._ldapResultToRecord(
- dn, attrs, self.service.recordType_resources
- )
- self.assertEquals(record.guid, guid)
- self.assertEquals(record.externalProxies(), set())
- self.assertEquals(record.externalReadOnlyProxies(), set())
- self.assertFalse(record.autoSchedule)
- self.assertEquals(record.autoAcceptGroup, "")
-
- # Now switch off the resourceInfoAttr and switch to individual
- # attributes...
- self.service.resourceSchema = {
- "resourceInfoAttr": "",
- "autoScheduleAttr": "auto-schedule",
- "autoScheduleEnabledValue": "yes",
- "proxyAttr": "proxy",
- "readOnlyProxyAttr": "read-only-proxy",
- "autoAcceptGroupAttr": "auto-accept-group",
- }
-
- # Resource with delegates and autoSchedule = True
-
- dn = "cn=odtestresource,cn=resources,dc=example,dc=com"
- guid = 'D3094652-344B-4633-8DB8-09639FA00FB6'
- attrs = {
- 'apple-generateduid': [guid],
- 'cn': ['odtestresource'],
- 'auto-schedule': ['yes'],
- 'proxy': ['6C6CD280-E6E3-11DF-9492-0800200C9A66'],
- 'read-only-proxy': ['6AA1AE12-592F-4190-A069-547CD83C47C0'],
- 'auto-accept-group': ['77A8EB52-AA2A-42ED-8843-B2BEE863AC70'],
- }
- record = self.service._ldapResultToRecord(
- dn, attrs, self.service.recordType_resources
- )
- self.assertEquals(record.guid, guid)
- self.assertEquals(
- record.externalProxies(),
- set(['6C6CD280-E6E3-11DF-9492-0800200C9A66'])
- )
- self.assertEquals(
- record.externalReadOnlyProxies(),
- set(['6AA1AE12-592F-4190-A069-547CD83C47C0'])
- )
- self.assertTrue(record.autoSchedule)
- self.assertEquals(
- record.autoAcceptGroup,
- '77A8EB52-AA2A-42ED-8843-B2BEE863AC70'
- )
-
- # Record with lowercase guid
- dn = "uid=odtestamanda,cn=users,dc=example,dc=com"
- guid = '9dc04a70-e6dd-11df-9492-0800200c9a66'
- attrs = {
- 'uid': ['odtestamanda'],
- 'apple-generateduid': [guid],
- 'sn': ['Test'],
- 'mail': ['odtestamanda at example.com', 'alternate at example.com'],
- 'givenName': ['Amanda'],
- 'cn': ['Amanda Test']
- }
- record = self.service._ldapResultToRecord(
- dn, attrs, 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)
- and turns the results into records
- """
- self.setupService(self.nestedUsingDifferentAttributeUsingDN)
-
- records = self.service.listRecords(self.service.recordType_users)
- self.assertEquals(len(records), 4)
- self.assertEquals(
- set([r.firstName for r in records]),
- set(["Amanda", "Betty", "Cyrus", "Wilfredo"]) # Carlene is skipped because no guid in LDAP
- )
-
- def test_restrictedPrincipalsUsingDN(self):
- """
- If restrictToGroup is in place, restrictedPrincipals should return only the principals
- within that group. In this case we're testing scenarios in which membership
- is specified by DN
- """
- for scenario in (
- self.nestedUsingSameAttributeUsingDN,
- self.nestedUsingDifferentAttributeUsingDN,
- ):
- self.setupService(scenario)
-
- self.assertEquals(
- set(
- [
- "cn=left_coast,cn=groups,dc=example,dc=com",
- "cn=right_coast,cn=groups,dc=example,dc=com",
- "uid=cdaboo,cn=users,dc=example,dc=com",
- "uid=dreid,cn=users,dc=example,dc=com",
- "uid=lecroy,cn=users,dc=example,dc=com",
- "uid=wsanchez,cn=users,dc=example,dc=com",
- ]
- ),
- self.service.restrictedPrincipals)
-
- dn = "uid=cdaboo,cn=users,dc=example,dc=com"
- attrs = {
- 'uid': ['cdaboo'],
- 'apple-generateduid': ['5A985493-EE2C-4665-94CF-4DFEA3A89500'],
- 'sn': ['Daboo'],
- 'mail': ['daboo at example.com'],
- 'givenName': ['Cyrus'],
- 'cn': ['Cyrus Daboo']
- }
- self.assertTrue(self.service.isAllowedByRestrictToGroup(dn, attrs))
-
- dn = "uid=unknown,cn=users,dc=example,dc=com"
- attrs = {
- 'uid': ['unknown'],
- 'apple-generateduid': ['5A985493-EE2C-4665-94CF-4DFEA3A89500'],
- 'sn': ['unknown'],
- 'mail': ['unknown at example.com'],
- 'givenName': ['unknown'],
- 'cn': ['unknown']
- }
- self.assertFalse(self.service.isAllowedByRestrictToGroup(dn, attrs))
-
-
- def test_restrictedPrincipalsUsingGUID(self):
- """
- If restrictToGroup is in place, restrictedPrincipals should return only the principals
- within that group. In this case we're testing scenarios in which membership
- is specified by an attribute, not DN
- """
- for scenario in (
- self.nestedUsingDifferentAttributeUsingGUID,
- self.nestedUsingSameAttributeUsingGUID,
- ):
- self.setupService(scenario)
-
- self.assertEquals(
- set(
- [
- "left_coast",
- "right_coast",
- "5A985493-EE2C-4665-94CF-4DFEA3A89500",
- "6423F94A-6B76-4A3A-815B-D52CFD77935D",
- ]
- ),
- self.service.restrictedPrincipals)
-
- dn = "uid=cdaboo,cn=users,dc=example,dc=com"
- attrs = {
- 'uid': ['cdaboo'],
- 'apple-generateduid': ['5A985493-EE2C-4665-94CF-4DFEA3A89500'],
- 'sn': ['Daboo'],
- 'mail': ['daboo at example.com'],
- 'givenName': ['Cyrus'],
- 'cn': ['Cyrus Daboo']
- }
- self.assertTrue(self.service.isAllowedByRestrictToGroup(dn, attrs))
-
- dn = "uid=unknown,cn=users,dc=example,dc=com"
- attrs = {
- 'uid': ['unknown'],
- 'apple-generateduid': ['unknown'],
- 'sn': ['unknown'],
- 'mail': ['unknown at example.com'],
- 'givenName': ['unknown'],
- 'cn': ['unknown']
- }
- self.assertFalse(self.service.isAllowedByRestrictToGroup(dn, attrs))
-
-
- @inlineCallbacks
- def test_groupMembershipAliases(self):
- """
- Exercise a directory environment where group membership does not refer
- to guids but instead uses LDAP DNs. This example uses the LDAP attribute
- "uniqueMember" to specify members of a group. The value of this attribute
- is each members' DN. Even though the proxy database deals strictly in
- guids, updateCache( ) is smart enough to map between guids and this
- attribute which is referred to in the code as record.cachedGroupsAlias().
- """
- self.setupService(self.nestedUsingDifferentAttributeUsingDN)
-
- # Set up proxydb and preload it from xml
- calendaruserproxy.ProxyDBService = calendaruserproxy.ProxySqliteDB("proxies.sqlite")
- yield XMLCalendarUserProxyLoader(proxiesFile.path).updateProxyDB()
-
- # Set up the GroupMembershipCache
- cache = GroupMembershipCache("ProxyDB", expireSeconds=60)
- self.service.groupMembershipCache = cache
- updater = GroupMembershipCacheUpdater(
- calendaruserproxy.ProxyDBService,
- self.service, 30, 15, 30, cache=cache, useExternalProxies=False
- )
-
- self.assertEquals((False, 8, 8), (yield updater.updateCache()))
-
- users = self.service.recordType_users
-
- for shortName, groups in [
- ("cdaboo", set(["both_coasts", "recursive1_coasts", "recursive2_coasts"])),
- ("wsanchez", set(["both_coasts", "left_coast", "recursive1_coasts", "recursive2_coasts"])),
- ]:
-
- record = self.service.recordWithShortName(users, shortName)
- self.assertEquals(groups, (yield record.cachedGroups()))
-
-
- def test_getExternalProxyAssignments(self):
- """
- Verify getExternalProxyAssignments can extract assignments from the
- directory, and that guids are normalized.
- """
- self.setupService(self.nestedUsingDifferentAttributeUsingDN)
- self.assertEquals(
- self.service.getExternalProxyAssignments(),
- [
- ('D91B21B9-B856-495A-8E36-0E5AD54EFB3A#calendar-proxy-read',
- ['5A985493-EE2C-4665-94CF-4DFEA3A89500']),
- ('D91B21B9-B856-495A-8E36-0E5AD54EFB3A#calendar-proxy-write',
- ['6423F94A-6B76-4A3A-815B-D52CFD77935D']),
- ('753E5A60-AFFD-45E4-BF2C-31DAB459353F#calendar-proxy-write',
- ['6423F94A-6B76-4A3A-815B-D52CFD77935D'])
- ]
- )
-
- def test_splitIntoBatches(self):
- self.setupService(self.nestedUsingDifferentAttributeUsingDN)
- # Data is perfect multiple of size
- results = list(splitIntoBatches(set(range(12)), 4))
- self.assertEquals(
- results,
- [set([0, 1, 2, 3]), set([4, 5, 6, 7]), set([8, 9, 10, 11])]
- )
-
- # Some left overs
- results = list(splitIntoBatches(set(range(12)), 5))
- self.assertEquals(
- results,
- [set([0, 1, 2, 3, 4]), set([8, 9, 5, 6, 7]), set([10, 11])]
- )
-
- # Empty
- results = list(splitIntoBatches(set([]), 5)) # empty data
- self.assertEquals(results, [set([])])
-
- def test_recordTypeForDN(self):
- # Ensure dn comparison is case insensitive and ignores extra
- # whitespace
- self.setupService(self.nestedUsingDifferentAttributeUsingDN)
-
- # Base DNs for each recordtype should already be lowercase
- for dn in self.service.typeDNs.itervalues():
- dnStr = ldap.dn.dn2str(dn)
- self.assertEquals(dnStr, dnStr.lower())
-
- # Match
- dnStr = "uid=foo,cn=USers ,dc=EXAMple,dc=com"
- self.assertEquals(self.service.recordTypeForDN(dnStr), "users")
- dnStr = "uid=foo,cn=PLaces,dc=EXAMple,dc=com"
- self.assertEquals(self.service.recordTypeForDN(dnStr), "locations")
- dnStr = "uid=foo,cn=Groups ,dc=EXAMple,dc=com"
- self.assertEquals(self.service.recordTypeForDN(dnStr), "groups")
- dnStr = "uid=foo,cn=Resources ,dc=EXAMple,dc=com"
- self.assertEquals(self.service.recordTypeForDN(dnStr), "resources")
-
- # No Match
- dnStr = "uid=foo,cn=US ers ,dc=EXAMple,dc=com"
- self.assertEquals(self.service.recordTypeForDN(dnStr), None)
-
- def test_normalizeDN(self):
- for input, expected in (
- ("uid=foo,cn=users,dc=example,dc=com",
- "uid=foo,cn=users,dc=example,dc=com"),
- ("uid=FoO,cn=uSeRs,dc=ExAmPlE,dc=CoM",
- "uid=foo,cn=users,dc=example,dc=com"),
- ("uid=FoO , cn=uS eRs , dc=ExA mPlE , dc=CoM",
- "uid=foo,cn=us ers,dc=exa mple,dc=com"),
- ("uid=FoO , cn=uS eRs , dc=ExA mPlE , dc=CoM",
- "uid=foo,cn=us ers,dc=exa mple,dc=com"),
- ):
- self.assertEquals(expected, normalizeDNstr(input))
-
- def test_queryDirectory(self):
- """
- Verify queryDirectory skips LDAP queries where there has been no
- LDAP attribute mapping provided for the given index type.
- """
- self.setupService(self.nestedUsingDifferentAttributeUsingDN)
-
- self.history = []
-
- def stubSearchMethod(base, scope, filterstr="(objectClass=*)",
- attrlist=None, timeoutSeconds=-1,
- resultLimit=0):
- self.history.append((base, scope, filterstr))
-
- recordTypes = [
- self.service.recordType_users,
- self.service.recordType_groups,
- self.service.recordType_locations,
- self.service.recordType_resources,
- ]
- self.service.queryDirectory(
- recordTypes,
- self.service.INDEX_TYPE_CUA,
- "mailto:test at example.com",
- queryMethod=stubSearchMethod
- )
- self.assertEquals(
- self.history,
- [('cn=users,dc=example,dc=com', 2, '(&(!(objectClass=organizationalUnit))(|(mail=test at example.com)(emailAliases=test at example.com)))'), ('cn=groups,dc=example,dc=com', 2, '(&(!(objectClass=organizationalUnit))(|(mail=test at example.com)(emailAliases=test at example.com)))')]
- )
Deleted: CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/test/test_livedirectory.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/test/test_livedirectory.py 2014-04-01 01:41:02 UTC (rev 13078)
+++ CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/test/test_livedirectory.py 2014-04-01 01:41:25 UTC (rev 13079)
@@ -1,209 +0,0 @@
-##
-# Copyright (c) 2011-2014 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.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-##
-from __future__ import print_function
-
-runLDAPTests = False
-runODTests = False
-
-try:
- import ldap
- import socket
-
- testServer = "localhost"
- base = ",".join(["dc=%s" % (p,) for p in socket.gethostname().split(".")])
- print("Using base: %s" % (base,))
-
- try:
- cxn = ldap.open(testServer)
- results = cxn.search_s(base, ldap.SCOPE_SUBTREE, "(uid=odtestamanda)",
- ["cn"])
- if len(results) == 1:
- runLDAPTests = True
- except ldap.LDAPError:
- pass # Don't run live tests
-
-except ImportError:
- print("Could not import ldap module (skipping LDAP tests)")
-
-try:
- from calendarserver.platform.darwin.od import opendirectory, dsattributes
-
- directory = opendirectory.odInit("/Search")
-
- results = list(opendirectory.queryRecordsWithAttribute_list(
- directory,
- dsattributes.kDS1AttrGeneratedUID,
- "9DC04A70-E6DD-11DF-9492-0800200C9A66",
- dsattributes.eDSExact,
- False,
- dsattributes.kDSStdRecordTypeUsers,
- None,
- count=0
- ))
- recordNames = [x[0] for x in results]
- if "odtestamanda" in recordNames:
- runODTests = True
- else:
- print("Test OD records not found (skipping OD tests)")
-
-except ImportError:
- print("Could not import OpenDirectory framework (skipping OD tests)")
-
-
-if runLDAPTests or runODTests:
-
- from twistedcaldav.test.util import TestCase
- from twistedcaldav.directory import augment
- from twistedcaldav.directory.test.test_xmlfile import augmentsFile
- from twisted.internet.defer import inlineCallbacks
-
- class LiveDirectoryTests(object):
-
- def test_ldapRecordWithShortName(self):
- record = self.svc.recordWithShortName("users", "odtestamanda")
- self.assertTrue(record is not None)
-
- def test_ldapRecordWithGUID(self):
- record = self.svc.recordWithGUID("9DC04A70-E6DD-11DF-9492-0800200C9A66")
- self.assertTrue(record is not None)
-
- @inlineCallbacks
- def test_ldapRecordsMatchingFields(self):
- fields = (
- ("firstName", "Amanda", True, "exact"),
- ("lastName", "Te", True, "starts-with"),
- )
- records = list(
- (yield self.svc.recordsMatchingFields(fields, operand="and"))
- )
- self.assertEquals(1, len(records))
- record = self.svc.recordWithGUID("9DC04A70-E6DD-11DF-9492-0800200C9A66")
- self.assertEquals(records, [record])
-
- @inlineCallbacks
- def test_restrictToGroup(self):
- self.svc.restrictEnabledRecords = True
- self.svc.restrictToGroup = "odtestgrouptop"
-
- # Faulting in specific records will return records outside of
- # the restrictToGroup, but they won't be enabledForCalendaring
- # and AddressBooks:
-
- # Amanda is a direct member of that group
- record = self.svc.recordWithShortName("users", "odtestamanda")
- self.assertTrue(record.enabledForCalendaring)
- self.assertTrue(record.enabledForAddressBooks)
-
- # Betty is a direct member of that group
- record = self.svc.recordWithShortName("users", "odtestbetty")
- self.assertTrue(record.enabledForCalendaring)
- self.assertTrue(record.enabledForAddressBooks)
-
- # Carlene is in a nested group
- record = self.svc.recordWithShortName("users", "odtestcarlene")
- self.assertTrue(record.enabledForCalendaring)
- self.assertTrue(record.enabledForAddressBooks)
-
- # Denise is not in the group
- record = self.svc.recordWithShortName("users", "odtestdenise")
- self.assertFalse(record.enabledForCalendaring)
- self.assertFalse(record.enabledForAddressBooks)
-
- # Searching for records using principal-property-search will not
- # yield records outside of the restrictToGroup:
-
- fields = (
- ("lastName", "Test", True, "exact"),
- )
- records = list(
- (yield self.svc.recordsMatchingFields(fields))
- )
- self.assertEquals(3, len(records))
-
- # These two are directly in the restrictToGroup:
- record = self.svc.recordWithShortName("users", "odtestamanda")
- self.assertTrue(record in records)
- record = self.svc.recordWithShortName("users", "odtestbetty")
- self.assertTrue(record in records)
- # Carlene is still picked up because she is in a nested group
- record = self.svc.recordWithShortName("users", "odtestcarlene")
- self.assertTrue(record in records)
-
- if runLDAPTests:
-
- from twistedcaldav.directory.ldapdirectory import LdapDirectoryService
- print("Running live LDAP tests against %s" % (testServer,))
-
- class LiveLDAPDirectoryServiceCase(LiveDirectoryTests, TestCase):
-
- def setUp(self):
- params = {
- "augmentService":
- augment.AugmentXMLDB(xmlFiles=(augmentsFile.path,)),
- "uri": "ldap://%s" % (testServer,),
- "rdnSchema": {
- "base": base,
- "guidAttr": "apple-generateduid",
- "users": {
- "rdn": "cn=users",
- "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
- "mapping" : { # maps internal record names to LDAP
- "recordName": "uid",
- "fullName" : "cn",
- "emailAddresses" : ["mail"], # multiple LDAP fields supported
- "firstName" : "givenName",
- "lastName" : "sn",
- },
- },
- "groups": {
- "rdn": "cn=groups",
- "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",
- "fullName" : "cn",
- "emailAddresses" : ["mail"], # multiple LDAP fields supported
- "firstName" : "givenName",
- "lastName" : "sn",
- },
- },
- },
- "groupSchema": {
- "membersAttr": "apple-group-memberguid", # how members are specified
- "nestedGroupsAttr" : "apple-group-nestedgroup", # how nested groups are specified
- "memberIdAttr": "apple-generateduid", # which attribute the above refers to
- },
- }
- self.svc = LdapDirectoryService(params)
-
- if runODTests:
-
- from twistedcaldav.directory.appleopendirectory import OpenDirectoryService
- print("Running live OD tests")
-
- class LiveODDirectoryServiceCase(LiveDirectoryTests, TestCase):
-
- def setUp(self):
- params = {
- "augmentService":
- augment.AugmentXMLDB(xmlFiles=(augmentsFile.path,)),
- }
- self.svc = OpenDirectoryService(params)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140331/2abddb3f/attachment-0001.html>
More information about the calendarserver-changes
mailing list