1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import string
21 import copy
22 import types
23 import re
24 import pprint
25
26
27 import ldap, ldap.schema
28
29 from easyLDAP_bind import *
30 import easyLDAP_defaults
31
32 import easyLDAP_exceptions
33 from easyLDAP_exceptions import *
34
35 easyLDAP_ADDATTR = 0
36 easyLDAP_REPLACEATTR = 1
37
38 SCHEMA_CLASS_MAPPING = ldap.cidict.cidict()
39 SCHEMA_ATTRS = SCHEMA_CLASS_MAPPING.keys()
40
41 _easyLDAP_schema_cache = {}
42
43
44
45
46
47
48
49
50
51
52
53
54
55
57
58
84
85 - def __init__(self, bind_dn=None, bind_pw=None, config_defaults=EASY_LDAP, update_schema_cache=False, ldapsession=None):
86
87 self._method_aliases()
88
89
90 self.CONFIG=config_defaults
91 self.LDAPuri=self.CONFIG['URI'].lower()
92 self.LDAPserver=string.split (self.LDAPuri,'//')[1]
93 if not bind_dn:
94 self.BindDN = self.CONFIG['BindDN']
95 if not bind_pw:
96 self.BindPW = self.CONFIG['BindPW']
97 self.RootDSE=self.CONFIG['RootDSE'].lower()
98 self.BaseDN=self.CONFIG['BaseDN'].lower()
99 if self.CONFIG['AdminRDN']:
100 self.AdminDN=self.CONFIG['AdminRDN']+','+self.CONFIG['BaseDN'].lower()
101 else:
102 self.AdminDN=''
103 self.PeopleBaseDN = self.GroupsBaseDN = self.HostsBaseDN = self.MailAliasesBaseDN = self.AutomountBaseDN = self.CONFIG['BaseDN'].lower()
104 if self.CONFIG['PeopleRDN']:
105 self.PeopleBaseDN = self.CONFIG['PeopleRDN']+','+self.PeopleBaseDN
106 if self.CONFIG['GroupsRDN']:
107 self.GroupsBaseDN = self.CONFIG['GroupsRDN']+','+self.GroupsBaseDN
108 if self.CONFIG['HostsRDN']:
109 self.HostsBaseDN = self.CONFIG['HostsRDN']+','+self.HostsBaseDN
110 if self.CONFIG['MailAliasesRDN']:
111 self.MailAliasesBaseDN = self.CONFIG['MailAliasesRDN']+','+self.MailAliasesBaseDN
112 if self.CONFIG['AutomountRDN']:
113 self.AutomountBaseDN = self.CONFIG['AutomountRDN']+','+self.AutomountBaseDN
114
115 self.LDAPServerCharsetEncoding=self.CONFIG['ServerCharsetEncoding']
116 self.posix_availableUidNumbers=self.CONFIG['posix_availableUidNumbers']
117 self.posix_availableGidNumbers=self.CONFIG['posix_availableGidNumbers']
118 self.templateLDAPSyntaxValues = {
119 'NO SPECIFIED SYNTAX': { 'default': 'Empty', 'regexp': '.*', },
120 'Audio': { 'default': 'NOSOUND', 'regexp': '.*', },
121 'Binary': { 'default': 'Empty_Binary', 'regexp': '.*', },
122 'Bit String': { 'default': '00000000', 'regexp': '[0-1]+', },
123 'Boolean': { 'default': 'False', 'regexp': 'TRUE|FALSE', },
124 'Certificate': { 'default': 'Empty_Certificate', 'regexp': '.*', },
125 'Certificate List': { 'default': 'Empty_CertificateList', 'regexp': '.*', },
126 'Certificate Pair': { 'default': 'Empty_CertificatePair', 'regexp': '.*', },
127 'Country String': { 'default': 'noCountry', 'regexp': '.*', },
128 'Directory String': { 'default': 'Empty', 'regexp': '.*', },
129 'Distinguished Name': { 'default': 'cn=DUMMY,%s' % self.BaseDN, 'regexp': '', },
130 'Facsimile Telephone Number': { 'default': '212-555-555', 'regexp': '^([0-9+]{2,3}|)( |-|)([0-9()]+|)( |-|/| / |)([0-9]+(-| |)[0-9]+)+$', },
131 'Generalized Time': { 'default': '0', 'regexp': '.*', },
132 'IA5 String': { 'default': 'Empty', 'regexp': '.*', },
133 'Integer': { 'default': '-1', 'regexp': '[0-9\-]', },
134 'JPEG': { 'default': 'NOJPEG', 'regexp': '.*', },
135 'Name And Optional UID': { 'default': 'Empty', 'regexp': '.*', },
136 'Numeric String': { 'default': '123456', 'regexp': '[0-9]+', },
137 'Octet String': { 'default': 'SECRET', 'regexp': '.*', },
138 'OID': { 'default': '1.2.3.4.5', 'regexp': '([0-9].[0-9.]+[0-9].|[a-zA-Z]+)', },
139 'OpenLDAP Experimental ACI': { 'default': 'Empty', 'regexp': '.*', },
140 'Other Mailbox': { 'default': 'someone@not.here.org', 'regexp': '.*', },
141 'Postal Address': { 'default': 'Empty_Place', 'regexp': '.*', },
142 'Printable String': { 'default': 'Empty', 'regexp': '.*', },
143 'RFC2307 Boot Parameter': { 'default': 'Empty', 'regexp': '.*', },
144 'RFC2307 NIS Netgroup Triple': { 'default': 'Empty', 'regexp': '.*', },
145 'Supported Algorithm': { 'default': 'Empty', 'regexp': '.*', },
146 'Telephone Number': { 'default': '212-555-555', 'regexp': '^([0-9+]{2,3}|)( |-|)([0-9()]+|)( |-|/| / |)([0-9]+(-| |)[0-9]+)+$', },
147 'Telex Number': { 'default': '212-555-555', 'regexp': '^([0-9+]{2,3}|)( |-|)([0-9()]+|)( |-|/| / |)([0-9]+(-| |)[0-9]+)+$', },
148 'UTC Time': { 'default': 'Mo Mr 22 22:22:22 UTC 2222', 'regexp': '.*', },
149 }
150
151 if ldapsession is None:
152 self.ldapsession=ldap.initialize(self.LDAPuri)
153 self.ldapsession.set_option(ldap.OPT_DEREF, ldap.DEREF_ALWAYS)
154
155 self.ldapsession.sizelimit = self.CONFIG['SizeLimit']
156 else:
157 self.ldapsession=ldapsession
158
159 if bind_dn:
160 self.BindDN = bind_dn
161 if bind_pw:
162 self.BindPW = bind_pw
163 if self.BindDN and self.BindPW:
164
165 self.bind_norefresh(self.BindDN, self.BindPW)
166
167 _schema_cache_key = self.LDAPuri+self.BaseDN
168 if _easyLDAP_schema_cache.has_key(_schema_cache_key) and not update_schema_cache:
169 self.attributeTypes = _easyLDAP_schema_cache[_schema_cache_key]['attributeTypes']
170 self.attributeTypesDict = _easyLDAP_schema_cache[_schema_cache_key]['attributeTypesDict']
171 self.oidDict = _easyLDAP_schema_cache[_schema_cache_key]['oidDict']
172 self.reverseAttributeTypesDict = _easyLDAP_schema_cache[_schema_cache_key]['reverseAttributeTypesDict']
173 self.objectClasses = _easyLDAP_schema_cache[_schema_cache_key]['objectClasses']
174 self.objectClassesDict = _easyLDAP_schema_cache[_schema_cache_key]['objectClassesDict']
175 self.matchingRules = _easyLDAP_schema_cache[_schema_cache_key]['matchingRules']
176 self.ldapSyntaxes = _easyLDAP_schema_cache[_schema_cache_key]['ldapSyntaxes']
177 self.ldapSyntaxesDict = _easyLDAP_schema_cache[_schema_cache_key]['ldapSyntaxesDict']
178
179 else:
180
181
182 self.objectClassesDict = {'top': {'STRUCTURAL': False,
183 'AUXILIARY': False,
184 'MAY': [],
185 'OID': '2.5.6.0',
186 'SUP': [],
187 'DESC': 'WARNING: the LDAP server\'s schema is not loaded',
188 'MUST': ['objectclass']
189 }
190 }
191
192 self.attributeTypesDict = {'objectclass': {'EQUALITY': 'objectIdentifierMatch',
193 'NAME': 'objectClass',
194 'ORDERING': '',
195 'COLLECTIVE': False,
196 'OID': '2.5.4.0',
197 'OBSOLETE': False,
198 'SYNTAX': '1.3.6.1.4.1.1466.115.121.1.38',
199 'SUBSTR': '',
200 'SUP': '',
201 'NO-USER-MODIFICATION': False,
202 'SINGLE-VALUE': False,
203 'DESC': 'WARNING: the LDAP server\'s schema is not loaded',
204 }
205 }
206 self.oidDict = {'2.5.4.0': ['objectclass'], }
207
208 self.ldapSyntaxesDict = {'NO SPECIFIED SYNTAX': { 'DEFAULT': 'Empty',
209 'DESC': 'NO SPECIFIED SYNTAX',
210 'REGEXP': '.*',
211 'X-NOT-HUMAN-READABLE': False, }, }
212
213 try:
214 schema = None
215
216 subschema_subentry_dn = self.ldapsession.search_subschemasubentry_s()
217 if subschema_subentry_dn is None:
218
219 subschema_subentry_entry = None
220 schema = None
221
222 else:
223
224 subschema_subentry_entry = self.ldapsession.read_subschemasubentry_s(subschema_subentry_dn, attrs=SCHEMA_ATTRS)
225 schema = ldap.schema.SubSchema(subschema_subentry_entry)
226
227 if schema is None:
228 raise easyLDAP_exceptions.LDAPSCHEMA_NOT_LOADED
229
230 schemas = schema.ldap_entry()
231
232 self.objectClasses=None
233 self.attributeTypes=None
234 self.matchingRules=None
235 self.ldapSyntaxes=None
236 if schemas.has_key('objectClasses'):
237 self.objectClasses=schemas['objectClasses']
238 if schemas.has_key('attributeTypes'):
239 self.attributeTypes=schemas['attributeTypes']
240 if schemas.has_key('matchingRules'):
241 self.matchingRules=schemas['matchingRules']
242 if schemas.has_key('ldapSyntaxes'):
243 self.ldapSyntaxes=schemas['ldapSyntaxes']
244 self.generate_attributetypes_dict()
245 self.generate_objectclass_dict()
246 self.generate_reverse_attributetypes_dict()
247 self.generate_ldapsyntaxes_dict()
248
249 _easyLDAP_schema_cache[_schema_cache_key] = {}
250 _easyLDAP_schema_cache[_schema_cache_key]['attributeTypes'] = copy.deepcopy(self.attributeTypes)
251 _easyLDAP_schema_cache[_schema_cache_key]['attributeTypesDict'] = copy.deepcopy(self.attributeTypesDict)
252 _easyLDAP_schema_cache[_schema_cache_key]['oidDict'] = copy.deepcopy(self.oidDict)
253 _easyLDAP_schema_cache[_schema_cache_key]['reverseAttributeTypesDict'] = copy.deepcopy(self.reverseAttributeTypesDict)
254 _easyLDAP_schema_cache[_schema_cache_key]['objectClasses'] = copy.deepcopy(self.objectClasses)
255 _easyLDAP_schema_cache[_schema_cache_key]['objectClassesDict'] = copy.deepcopy(self.objectClassesDict)
256 _easyLDAP_schema_cache[_schema_cache_key]['matchingRules'] = copy.deepcopy(self.matchingRules)
257 _easyLDAP_schema_cache[_schema_cache_key]['ldapSyntaxes'] = copy.deepcopy(self.ldapSyntaxes)
258 _easyLDAP_schema_cache[_schema_cache_key]['ldapSyntaxesDict'] = copy.deepcopy(self.ldapSyntaxesDict)
259
260 except ldap.SERVER_DOWN:
261 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
262
263
265 """Creates a deepcopy of the easyLDAP class."""
266 result = self.__class__()
267 memo[id(self)] = result
268
269 result.LDAPuri = self.LDAPuri
270 result.LDAPserver = self.LDAPserver
271 result.BindDN = self.BindDN
272 result.BindPW = self.BindPW
273 result.BaseDN = self.BaseDN
274 result.AdminDN = self.AdminDN
275 result.PeopleBaseDN = self.PeopleBaseDN
276 result.GroupBaseDN = self.GroupsBaseDN
277 result.HostsBaseDN = self.HostsBaseDN
278 result.MailAliasesBaseDN = self.MailAliasesBaseDN
279 result.AutomountBaseDN = self.AutomountBaseDN
280 result.LDAPServerCharsetEncoding = self.LDAPServerCharsetEncoding
281 result.posix_availableUidNumbers = self.posix_availableUidNumbers
282 result.posix_availableGidNumbers = self.posix_availableGidNumbers
283 if (self.BindDN != '') and self.has_dn(self.BindDN):
284 result.bind_norefresh(self.BindDN, self.BindPW)
285
286 result.EASY_LDAP = copy.deepcopy(self.CONFIG)
287 result.attributeTypes=copy.deepcopy(self.attributeTypes)
288 result.attributeTypesDict=copy.deepcopy(self.attributeTypesDict)
289 result.attributeTypesDict=copy.deepcopy(self.oidDict)
290 result.attributeTypesDict=copy.deepcopy(self.reverseAttributeTypesDict)
291 result.objectClasses=copy.deepcopy(self.objectClasses)
292 result.objectClassesDict=copy.deepcopy(self.objectClassesDict)
293 result.matchingRules=copy.deepcopy(self.matchingRules)
294 result.ldapSyntaxes=copy.deepcopy(self.ldapSyntaxes)
295 result.ldapSyntaxesDict=copy.deepcopy(self.ldapSyntaxesDict)
296
297 return result
298
299
301 self.ldapsession.unbind_s()
302
303
305 """
306 thisClass.generate_objectclass_dict()
307
308 is for class-internal use only. It is evoked once from
309 thisClass.__init__() to generate the python dictionary
310 thisClass.objectClassesDict.
311
312 You should not need to call this method.
313 """
314 self.objectClassesDict={}
315 for schema_def in self.objectClasses:
316 schema_key = 'OID'
317 elements = []
318 this_objectClassesDict = {'OID': '','DESC': '', 'SUP': [], 'MUST': [], 'MAY': [], 'AUXILIARY': False, 'STRUCTURAL': False }
319 objectClassNames = []
320 exprList = string.split(schema_def)
321 exprList.append ('mySTOP')
322
323 for word in exprList:
324 word = string.strip (word,"'")
325
326 if word in ['NAME','DESC','SUP','MUST','MAY','mySTOP']:
327 if schema_key in ['NAME']:
328 schema_key = word
329 continue
330 if schema_key in ['SUP', 'MUST', 'MAY']:
331 this_objectClassesDict[schema_key] = elements
332 elements = []
333 schema_key = word
334 continue
335 if schema_key in ['OID', 'DESC']:
336 this_objectClassesDict[schema_key] = string.join(elements)
337 elements = []
338 schema_key = word
339 continue
340
341 if word in ['STRUCTURAL', 'AUXILIARY']:
342 this_objectClassesDict[word]=True
343 continue
344
345 if word not in ['(',')','$']:
346 if schema_key == 'NAME':
347 objectClassNames.append (word.lower())
348 this_objectClassesDict[schema_key] = word
349 if schema_key in ['MUST', 'MAY', ]:
350 elements.append(word.lower())
351 if schema_key in ['SUP', ]:
352 elements.append(word.lower())
353 if schema_key in ['OID', 'DESC']:
354 elements.append (word)
355
356 for objectClassName in objectClassNames:
357 self.objectClassesDict[objectClassName]=this_objectClassesDict
358
359
361 """
362 thisClass.generate_attributetypes_dict ()
363
364 is for class-internal use only. It is evoked once from
365 thisClass.__init__() to generate the python dictionary
366 thisClass.attributeTypesDict.
367
368 You should not need to call this method.
369 """
370 self.attributeTypesDict={}
371 self.oidDict
372 for schema_def in self.attributeTypes:
373 schema_key = 'OID'
374 elements = []
375 this_attributeTypesDict = {'OID': '','DESC': '', 'SUP': '', 'SUBSTR': '', 'SYNTAX': '', 'EQUALITY': '', 'ORDERING': '',
376 'OBSOLETE': False, 'COLLECTIVE': False, 'SINGLE-VALUE': False, 'NO-USER-MODIFICATION': False}
377 attributeTypesNames = []
378 exprList = string.split(schema_def)
379 exprList.append ('mySTOP')
380
381 for word in exprList:
382 word = string.strip (word,"'")
383 if word in ['NAME', 'DESC','SUP','SUBSTR','SYNTAX','EQUALITY', 'ORDERING'
384 'USAGE', 'mySTOP']:
385 if schema_key in ['NAME']:
386 schema_key = word
387 continue
388 else:
389 this_attributeTypesDict[schema_key] = string.join(elements)
390 elements = []
391 schema_key = word
392 continue
393
394 if word in ['SINGLE-VALUE','OBSOLETE','NO-USER-MODIFICATION','COLLECTIVE']:
395 this_attributeTypesDict[word]=True
396 continue
397
398 if word not in ['(',')','$']:
399 if schema_key == 'NAME':
400 attributeTypesNames.append (word.lower())
401 this_attributeTypesDict[schema_key] = word
402 elif schema_key == 'SUP':
403 elements.append (word.lower())
404 else:
405 elements.append (word)
406
407 for attributeTypesName in attributeTypesNames:
408 self.attributeTypesDict[attributeTypesName]=this_attributeTypesDict
409
410 if not self.oidDict.has_key(schema_key):
411 self.oidDict[schema_key] = []
412 self.oidDict[schema_key].append(attributeTypesName)
413
414
416
417 self.reverseAttributeTypesDict = { 'OID': {}, 'NAME': {}, }
418 for objectClassName, objectClass in self.objectClassesDict.items():
419
420
421 attributeTypeList = objectClass['MUST']+objectClass['MAY']
422 for attrtype in [ at.lower() for at in attributeTypeList ]:
423 if not self.reverseAttributeTypesDict['NAME'].has_key(attrtype):
424 self.reverseAttributeTypesDict['NAME'][attrtype] = [attrtype]
425 else:
426 self.reverseAttributeTypesDict['NAME'][attrtype].append(objectClassName)
427
428 try:
429 oid = self.map_attrtypes2oids(attrtype)[0]
430 if not self.reverseAttributeTypesDict['OID'].has_key(oid):
431 self.reverseAttributeTypesDict['OID'][oid] = [objectClassName]
432 else:
433 self.reverseAttributeTypesDict['OID'][oid].append(objectClassName)
434 except:
435 pass
436
437
439 """
440 thisClass.generate_ldapsyntaxes__dict ()
441
442 is for class-internal use only. It is evoked once from
443 thisClass.__init__() to generate the python dictionary
444 thisClass.ldapSyntaxesDict.
445
446 You should not need to call this method.
447 """
448 if not self.ldapSyntaxes:
449 return
450 for schema_def in self.ldapSyntaxes:
451 schema_key = 'OID'
452 elements = []
453 this_ldapSyntaxesDict = {'DESC': '', 'X-NOT-HUMAN-READABLE': False}
454 ldapSyntaxesOIDs = []
455 exprList = string.split(schema_def)
456 exprList.append ('mySTOP')
457
458 for word in exprList:
459 word = string.strip (word,"'")
460 if word in ['DESC', 'X-NOT-HUMAN-READABLE', 'mySTOP']:
461 if schema_key in ['OID', 'X-NOT-HUMAN-READABLE']:
462 schema_key = word
463 continue
464 if schema_key == 'DESC':
465 this_ldapSyntaxesDict[schema_key] = string.join(elements)
466 elements = []
467 schema_key = word
468 continue
469
470 if word not in ['(',')','$']:
471 if schema_key == 'OID':
472 ldapSyntaxesOIDs.append (word)
473 if schema_key == 'DESC':
474 elements.append (word)
475 if (schema_key == 'X-NOT-HUMAN-READABLE') and (word == 'TRUE'):
476 this_ldapSyntaxesDict[schema_key]=True
477
478 for ldapSyntaxOID in ldapSyntaxesOIDs:
479 ldapSyntaxName = this_ldapSyntaxesDict['DESC']
480 if self.templateLDAPSyntaxValues.has_key(ldapSyntaxName):
481 this_ldapSyntaxesDict['DEFAULT'] = self.templateLDAPSyntaxValues[ldapSyntaxName]['default']
482 this_ldapSyntaxesDict['REGEXP'] = self.templateLDAPSyntaxValues[ldapSyntaxName]['regexp']
483 else:
484 this_ldapSyntaxesDict['DEFAULT'] = 'Empty'
485 this_ldapSyntaxesDict['REGEXP'] = '.*'
486 self.ldapSyntaxesDict[ldapSyntaxOID]=this_ldapSyntaxesDict
487
488
490
491 is_string_type = False
492 from easyLDAP_utils import _attrtype, _attropt, to_list_of_strings
493 if type(attrdesc_list) is not types.ListType:
494 is_string_type = True
495 attrdesc_list = to_list_of_strings(attrdesc_list)
496
497 rewrite_attrdesc_list = []
498 try:
499 for attrdesc in attrdesc_list:
500
501 attrtype = _attrtype(attrdesc)
502 oid = self.map_attrtypes2oids(attrtype)[0]
503 if oid in self.CONFIG['preferredAttributeAliases'].keys():
504 attrtype = self.CONFIG['preferredAttributeAliases'][oid]
505 elif attrtype.lower() == self.attributeTypesDict[attrtype.lower()]['NAME'].lower():
506 attrtype = self.attributeTypesDict[attrtype.lower()]['NAME']
507 else:
508 attrtype = attrtype.lower()
509 attropt = _attropt(attrdesc)
510
511 if not attropt:
512 rewrite_attrdesc_list.append(attrtype)
513 else:
514 rewrite_attrdesc_list.append('%s;%s' % (attrtype, attropt))
515
516 except KeyError:
517 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
518
519 if is_string_type:
520 return rewrite_attrdesc_list[0]
521 else:
522 return rewrite_attrdesc_list
523
524
526
527 is_string_type = False
528 from easyLDAP_utils import _attrtype, _attropt, to_list_of_strings
529 if type (objectclasses_list) is not types.ListType:
530 is_string_type = True
531 objectclasses_list = to_list_of_strings(objectclasses_list)
532
533 rewrite_objclasses_list = []
534 for objclass in objectclasses_list:
535
536 rewrite_objclasses_list.append(self.objectClassesDict[objclass.lower()]['NAME'])
537
538 if is_string_type:
539 return rewrite_objclasses_list[0]
540 else:
541 return rewrite_objclasses_list
542
543
545
546
547 result_pyldapobject = []
548 for ldap_single_object in pyldapobject:
549 ldap_single_object = list(ldap_single_object)
550
551 for (from_attrdesc, to_attrdesc) in zip(ldap_single_object[1].keys(), self._rewrite_attrtype_names(ldap_single_object[1].keys())):
552 if from_attrdesc != to_attrdesc:
553 ldap_single_object[1][to_attrdesc] = ldap_single_object[1][from_attrdesc]
554 del ldap_single_object[1][from_attrdesc]
555
556 ldap_single_object[1]['objectClass'] = self._rewrite_objectclass_names(ldap_single_object[1]['objectClass'])
557
558 result_pyldapobject.append(ldap_single_object)
559 return result_pyldapobject
560
561
562 - def adminbind(self,admin_bind_pw, refresh_cache=True):
563 """
564 thisClass.adminbind('myADMINPW')
565
566 binds to the LDAP server with administrative access. The LDAP server's
567 admin DN is stored in thisClass.AdminDN, the administrative password
568 is given through the argument 'myADMINPW'.
569 """
570 success = False
571 try:
572 self.ldapsession.simple_bind_s(self.AdminDN,admin_bind_pw)
573 self.LDAPSERVER_DOWN = False
574 self.BindDN = self.AdminDN
575 self.BindPW = admin_bind_pw
576 success = True
577 except ldap.SERVER_DOWN:
578 self.LDAPSERVER_DOWN=True
579 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
580 except ldap.INVALID_CREDENTIALS:
581 raise_easyldap_exception(err_code=7)
582
583 if refresh_cache:
584 self.refresh_cache()
585
586 return success
587
588
590 """
591 thisClass.bind_norefresh('myDN', 'myPW')
592
593 as the easyLDAP class does not load any objects into
594 the easyLDAP cache, this method is just an alias for
595 this_class.bind()
596 """
597 return self.adminbind(admin_bind_pw=admin_bind_pw, refresh_cache=False)
598
599
600 - def bind(self, bind_dn, bind_pw, refresh_cache=True):
622
623
625 """
626 thisClass.bind_norefresh('myDN', 'myPW')
627
628 as the easyLDAP class does not load any objects into
629 the easyLDAP cache, this method is just an alias for
630 this_class.bind()
631 """
632 return self.bind(bind_dn, bind_pw, refresh_cache=False)
633
634
635 - def uid_bind (self, bind_uid, bind_pw, refresh_cache=True):
636 """
637 thisClass.uid_bind('myUID', 'myPW')
638
639 binds to the LDAP server. This method tries to find the UID's
640 corresponding DN in the LDAP tree starting at thisClass.BaseDN.
641
642 Binding by UID will fail if the given UID 'myUID' is not unique
643 to the specified LDAP tree.
644 """
645 my_bind_dn = self.map_uid2dn (bind_uid)
646 return self.bind(bind_dn=my_bind_dn, bind_pw=bind_pw, refresh_cache=refresh_cache)
647
648
650 """
651 thisClass.uid_bind_norefresh('myUID', 'myPW')
652
653 as the easyLDAP class does not load any objects into
654 the easyLDAP cache, this method is just an alias for
655 this_class.bind()
656 """
657 return self.uid_bind(bind_uid, bind_pw, refresh_cache=False)
658
659
660 - def cn_bind(self, bind_cn, bind_pw, refresh_cache=True):
661 """
662 thisClass.cnbind('myCN', 'myPW')
663
664 binds to the LDAP server. This method tries to find the cn's
665 corresponding DN in the LDAP tree starting at thisClass.BaseDN.
666
667 Binding by CN (Common Name) will fail if the given cn 'myCN' is
668 not unique to the specified LDAP tree.
669 """
670 my_bind_dn = self.map_cn2dn (bind_cn)
671 return self.bind(my_bind_dn, bind_pw, refresh_cache=refresh_cache)
672
673
675 """
676 thisClass.uid_bind_norefresh('myDN', 'myPW')
677
678 as the easyLDAP class does not load any objects into
679 the easyLDAP cache, this method is just an alias for
680 this_class.bind()
681 """
682 return self.cn_bind(bind_cn, bind_pw, refresh_cache=False)
683
684
686 """
687 thisClass.anonbind()
688
689 tries an anonymous bind to the LDAP server.
690 """
691 success = False
692 try:
693 self.ldapsession.simple_bind_s('','')
694 self.BindDN = ''
695 self.BindPW = ''
696 success = True
697
698 except ldap.SERVER_DOWN:
699 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
700
701 if refresh_cache:
702 self.refresh_cache()
703
704 return success
705
706
708 """
709 thisClass.anonymous_norefresh()
710
711 tries an anonymous bind to the LDAP server.
712 """
713 return self.anonymous_bind(refresh_cache=False)
714
715
717 """
718 thisClass.is_ldapobject('myLDAP_DATA')
719
720 returns True, if the given data structure conforms to the
721 python-ldap data format and only contains data of a single DN.
722 """
723 from easyLDAP_utils import is_pyldapobject
724 return is_pyldapobject(ldap_data_dict)
725
726
728 """
729 thisClass.is_ldaptree('myLDAP_DATA')
730
731 returns True, if the given data structure conforms to the
732 python-ldap data format and the hierarchical structure is
733 tree-like.
734 """
735 from easyLDAP_utils import is_pyldaptree
736 return is_pyldaptree(ldap_data_dict)
737
738
740 """
741 thisClass.is_singlevalueattr('myATTRIBUTE')
742
743 tests if the SINGLE-VALUE flag is set for the LDAP attribute
744 'myATTRIBUTE'.
745 """
746 from easyLDAP_utils import _attrtype
747 return self.attributeTypesDict[_attrtype(this_attr).lower()]['SINGLE-VALUE']
748
749
751 """
752 thisClass.is_obsoleteattr('myATTRIBUTE')
753
754 tests if the OBSOLETE flag is set for the LDAP attribute
755 'myATTRIBUTE'.
756 """
757 from easyLDAP_utils import _attrtype
758 return self.attributeTypesDict[_attrtype(this_attr).lower()]['OBSOLETE']
759
760
762 """
763 thisClass.is_nousermodattr('myATTRIBUTE')
764
765 tests if the NO-USER-MODIFICATION flag is set for the LDAP
766 attribute 'myATTRIBUTE'.
767 """
768 from easyLDAP_utils import _attrtype
769 return self.attributeTypesDict[_attrtype(this_attr).lower()]['NO-USER-MODIFICATION']
770
771
773 """
774 thisClass.is_collectiveattr('myATTRIBUTE')
775
776 tests if the COLLECTIVE flag is set for the LDAP attribute
777 'myATTRIBUTE'.
778 """
779 from easyLDAP_utils import _attrtype
780 return self.attributeTypesDict[_attrtype(this_attr).lower()]['COLLECTIVE']
781
782
784 """
785 thisClass.get_objectclasses()
786
787 returns a list of all objectClasses that are known to the
788 server's LDAP schema.
789 """
790 if capitalize:
791 return [ self.objectClassesDict[obc]['NAME'] for obc in self.objectClassesDict.keys() ]
792 else:
793 return self.objectClassesDict.keys()
794
795
797 """
798 thisClass.get_attributetypes()
799
800 returns a list of all attirbuteTypes that are known the
801 server's LDAP schema.
802 """
803 if capitalize:
804 return [ at['NAME'] for at in self.attributeTypesDict ]
805 else:
806 return self.attributeTypesDict.keys()
807
808
810 """
811 check_objectclass_dependencies ('myOBJECT_CLASS'|['myOBJECT_CLASS1',
812 'myOBJECT_CLASS2'])
813
814 checks if and what objectClasses are needed before adding them
815 to an LDAP directory. The dependencies are derived from the
816 server's LDAP schema.
817
818 The method returns a list of ObjectClasses, including those
819 that were given to the method and those that are needed
820 to complete the set.
821 """
822 from easyLDAP_utils import to_list_of_strings
823
824 these_objectClasses = [ obc.lower() for obc in to_list_of_strings(objectclass_list) ]
825
826
827 checkedObjectClasses = these_objectClasses
828 for this_objectClass in these_objectClasses:
829
830 if self.is_valid_objectclass(this_objectClass):
831
832
833 superiorObjectClasses = self._rewrite_objectclass_names(self.objectClassesDict[this_objectClass.lower()]['SUP'])
834 for superiorObjectClass in superiorObjectClasses:
835 if superiorObjectClass.lower() not in [ objc.lower() for objc in checkedObjectClasses ]:
836 checkedObjectClasses.append(superiorObjectClass)
837
838
839 return checkedObjectClasses
840
841
843 """
844 thisClass.map_objectclass2attr ('myOBJECT_CLASS')
845
846 returns all attributes that are mentioned in the server's
847 LDAP schema for objectClass 'myOBJECT_CLASS'.
848 """
849 return self.objectClassesDict[objectclass.lower()]['MUST']+self.objectClassesDict[objectclass.lower()]['MAY']
850
851
853 """
854 thisClass.map_attrtype2objectclass ('myATTRTYPE')
855
856 returns a lists of objectClasses that the given attribute
857 'myATTRTYPE' occurs in. This list is derived from the
858 server's LDAP schema.
859 """
860 from easyLDAP_utils import _attrtype
861 resultObjectClasses = []
862
863
864 oid = self.map_attrtypes2oids(_attrtype(attrtype))[0]
865 if oid in self.reverseAttributeTypesDict['OID'].keys():
866 resultObjectClasses = self.reverseAttributeTypesDict['OID'][oid]
867
868
869 if len (resultObjectClasses) == 0:
870 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
871
872 return resultObjectClasses
873
874
876 """
877 thisClass.is_valid_objectclass('myOBJECTCLASS')
878
879 tests if the given objectClass 'myOBJECTCLASS' is a valid
880 objectClass according to the server's LDAP schema.
881 """
882 return (objectclass.lower() in [ oc for oc in self.objectClassesDict.keys() ])
883
885 """
886 thisClass.is_valid_attrtype('myATTRTYPE')
887
888 tests if the given attribute type 'myATTRTYPE' is a valid
889 attribute type according to the server's LDAP schema.
890 """
891 return (attrtype.lower() in [ at for at in self.attributeTypesDict.keys() ])
892
893
895 """
896 thisClass.has_valid_attrtype('myATTRDESC')
897
898 tests if the given attribute 'myATTRDESC' has a valid attributeType
899 according to the server's LDAP schema.
900 """
901 from easyLDAP_utils import _attrtype
902 if self.map_attrtype2objectclass(_attrtype(attrdesc)) > 0:
903 return True
904 return False
905
906
908 """
909 thisClass.has_oid_set('myOID'[, mySINGLELDAPOBJECT])
910
911 checks if the given OID 'myOID' is set in the cached
912 easyLDAP object. If so, the method's result is True.
913
914 Another LDAP object than the one currently cached
915 can be analyzed by passing 'mySINGLELDAPOBJECT'. The
916 lengths of the passed LDAP object has to be 1.
917 """
918 from easyLDAP_utils import is_pyldapobject
919 if is_pyldapobject(pyldapobject):
920 if oid in self.get_used_attrtype_oids(pyldapobject):
921 return True
922
923 return False
924
925
927 """
928 thisClass.get_used_attrtype_oids()
929
930 returns a list of those attribute OIDs, that are currently
931 used in the cached easyLDAP object. This list is taken from
932 the server's LDAP schema. If - by some reason - the easyLDAP
933 object cache is, an empty list is returned.
934
935 Another LDAP object than the one currently cached
936 can be analyzed by passing 'mySINGLELDAPOBJECT'. The
937 lengths of the passed LDAP object has to be 1.
938 """
939 from easyLDAP_utils import _attrtype, _unique
940 oidList=[]
941 for key in [ at.lower() for at in pyldapobject[0][1].keys() ]:
942 oidList.append (self.attributeTypesDict[_attrtype(key)]['OID'])
943 return _unique(oidList)
944
945
947 """
948 thisClass.map_attrtypes2oids('myATTRIBUTELIST')
949
950 maps the given attributes in 'myATTRIBUTELIST'
951 to a list of their unequivocal OIDs. If the mapping
952 fails, an empty list is returned.
953 """
954 from easyLDAP_utils import _attrtype, to_list_of_strings
955 OIDList = []
956 if type(attribute_types_list) is not types.ListType:
957 attribute_types_list = to_list_of_strings(attribute_types_list)
958 attribute_types_list = [ at.lower() for at in attribute_types_list ]
959
960 for myAttr in attribute_types_list:
961 if self.is_valid_attrtype(_attrtype(myAttr)):
962 OIDList.append(self.attributeTypesDict[_attrtype(myAttr)]['OID'])
963 else:
964
965 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
966
967 return OIDList
968
969
971 """
972 thisClass.map_oid2attrtypes('myOID')
973
974 maps the given OID 'myOID' to a list of their
975 possible ATTRIBUTEs according to the LDAP server's
976 LDAP schema. If the mapping fails, an empty list
977 is returned.
978 """
979 ATTRList = []
980 if type(oid) is types.StringType:
981 for attrtype, dict in self.attributeTypesDict.items():
982 if oid == dict['OID']:
983 ATTRList.append(attrtype)
984
985 return ATTRList
986
987
989 """
990 thisClass.get_used_attrtypes([mySINGLELDAPOBJECT])
991
992 returns a list of attribute types that are used in the current easyLDAP
993 object. If - by some reason - the cache is empty, an empty list
994 is returned.
995
996 Another LDAP object than the one currently cached
997 can be analyzed by passing 'mySINGLELDAPOBJECT'. The
998 lengths of the passed LDAP object has to be 1.
999 """
1000 from easyLDAP_utils import _attrtype, _unique, is_pyldapobject
1001 if is_pyldapobject(pyldapobject, strict=False):
1002 if capitalize:
1003 return _unique(self._rewrite_attrtype_names(pyldapobject[0][1].keys()))
1004 else:
1005 return _unique([ _attrtype(key).lower() for key in pyldapobject[0][1].keys() ])
1006 else:
1007 raise easyLDAP_exceptions.NOT_A_PYTHON_LDAPOBJECT
1008
1009
1037
1038
1040 """
1041 thisClass.get_attrtypealiases('myATTRTYPE')
1042
1043 returns a list of attribute types that are treated as aliases in
1044 the LDAP server's schema.
1045 """
1046 from easyLDAP_utils import _attrtype
1047 if capitalize:
1048 return [ self.attributeTypesDict[attrtype_alias]['NAME'] for attrtype_alias in self.map_oid2attrtypes(self.map_attrtypes2oids(_attrtype(attrtype))[0]) ]
1049 else:
1050 return [ attrtype_alias for attrtype_alias in self.map_oid2attrtypes(self.map_attrtypes2oids(_attrtype(attrtype))[0]) ]
1051
1052
1054 """
1055 thisClass.map_attrtype2ldapsyntax('myATTRTYPE')
1056
1057 returns the LDAPSyntax for the given attribute 'myATTRTYPE'. Using
1058 the dictionary thisClass.templateLDAPSyntaxValues will help you
1059 to generate a default value for new attribute values:
1060
1061 print thisClass.templateLDAPSyntaxValues[
1062 thisClass.map_attrtype2ldapsyntax['myATTRTYPE']
1063 ]
1064 """
1065 from easyLDAP_utils import _attrtype
1066 if not self.ldapSyntaxesDict: return None
1067 try:
1068 self.attributeTypesDict[_attrtype(this_attrtype).lower()]
1069 attrSyntaxOID = self.attributeTypesDict[_attrtype(this_attrtype).lower()]['SYNTAX']
1070 if attrSyntaxOID == '':
1071 return self.ldapSyntaxesDict['NO SPECIFIED SYNTAX']
1072 else:
1073 attrSyntaxOID = string.split(attrSyntaxOID, '{')[0]
1074 return self.ldapSyntaxesDict[attrSyntaxOID]
1075 except KeyError:
1076 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
1077
1078
1080 """
1081 thisClass.map_attrtype2ldapsyntax('myATTRTYPE')
1082
1083 returns the LDAPSyntax for the given attribute 'myATTRTYPE'. Using
1084 the dictionary thisClass.templateLDAPSyntaxValues will help you
1085 to generate a default value for new attribute values:
1086
1087 print thisClass.templateLDAPSyntaxValues[
1088 thisClass.map_attrtype2ldapsyntax['myATTRTYPE']
1089 ]
1090 """
1091 from easyLDAP_utils import _attrtype
1092 if not self.ldapSyntaxesDict: return None
1093 try:
1094 self.attributeTypesDict[_attrtype(this_attrtype).lower()]
1095 attrSyntaxOID = self.attributeTypesDict[_attrtype(this_attrtype).lower()]['SYNTAX']
1096 if attrSyntaxOID == '':
1097 return 'NO SPECIFIED SYNTAX'
1098 else:
1099 attrSyntaxOID = string.split(attrSyntaxOID, '{')[0]
1100 return self.ldapSyntaxesDict[attrSyntaxOID]['DESC']
1101 except KeyError:
1102 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
1103
1104
1106 """
1107 thisClass.map_attrtype2ldapsyntaxoid('myATTRTYPE')
1108
1109 returns the LDAPSyntax's OID for the given attribute type
1110 'myATTRTYPE'.
1111 """
1112 from easyLDAP_utils import _attrtype
1113 if self.has_valid_attrtype(this_attrtype):
1114 attrSyntaxOID = self.attributeTypesDict[_attrtype(this_attrtype).lower()]['SYNTAX']
1115 if attrSyntaxOID == '':
1116 return 'NO SPECIFIED SYNTAX'
1117 else:
1118 return attrSyntaxOID.split('{')[0]
1119 else:
1120 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
1121
1123 """
1124 thisClass.map_attrtype2ldapsyntaxoid('myATTRTYPE')
1125
1126 returns the LDAPSyntax's OID for the given attribute type
1127 'myATTRTYPE'.
1128 """
1129 from easyLDAP_utils import _attrtype
1130 if self.has_valid_attrtype(this_attrtype):
1131 attrSyntaxOID = self.attributeTypesDict[_attrtype(this_attrtype).lower()]['SYNTAX']
1132 if '{' in attrSyntaxOID:
1133 return attrSyntaxOID.split('{')[1].rstrip('}')
1134 return 0
1135 else:
1136 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
1137
1138
1140 """
1141 attrtype_needs_objectclass('myATTRIBUTE')
1142
1143 returns True if the easyLDAP object in cache needs an additional
1144 objectClass before adding the LDAP attribute 'myATTRIBUTE'. If
1145 the objectClass dependencies are already all solved, it returns False.
1146
1147 The pseudo-boolean funtcion returns None, if there is no such
1148 attribute in the server's LDAP schema.
1149 """
1150 neededObjectClasses = []
1151 setObjectClasses = []
1152 setObjectClasses = self.get_used_objectclasses()
1153 if 'ABSTRACT' in setObjectClasses:
1154 return False
1155 neededObjectClasses = self.map_attrtype2objectclasses(attr)
1156 if len (neededObjectClasses) > 0:
1157 for neededObjectClass in neededObjectClasses:
1158
1159 if neededObjectClass in setObjectClasses:
1160
1161 return False
1162 return True
1163 else:
1164
1165 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
1166
1167
1168 - def search(self, filter='(objectClass=*)', scope=ldap.SCOPE_SUBTREE, base='',retrieve_data=False):
1169 """
1170 thisClass.search(filter='MyFILTER', scope=myLDAPSCOPE, base='myLDAPSEARCHBASEDN')
1171
1172 performs a raw ldap.search request and returns the DNs of objects the search filter applies to.
1173 """
1174 from easyLDAP_utils import ldapDictionaryDecode
1175
1176 dn_list = []
1177 if not base:
1178 base = self.CONFIG['BaseDN']
1179 try:
1180 search = ldapDictionaryDecode(self.ldapsession.search_s(base, scope, filter), config_defaults=self.CONFIG)
1181 if search and not retrieve_data:
1182 dn_list = [ obj[0] for obj in search ]
1183 return dn_list
1184
1185 return search
1186
1187 except ldap.SERVER_DOWN:
1188 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1189
1190
1192 """
1193 thisClass.map_uidNumber2uid ('myUIDNUMBER')
1194
1195 transforms the given uidNumber 'myUIDNUMBER' to the corresponding uid.
1196 The search is started at base DN thisClass.BaseDN.
1197 """
1198 from easyLDAP_utils import ldapDictionaryDecode
1199
1200 try:
1201 if type(uid_number) is types.ListType:
1202 uid_number = str(uid_number[0])
1203 else:
1204 uid_number = str(uid_number)
1205 uidnumbersearch = ldapDictionaryDecode(self.ldapsession.search_s(self.BaseDN, ldap.SCOPE_SUBTREE,'(&(objectClass=posixAccount)(uidNumber='+uid_number+'))'), config_defaults=self.CONFIG)
1206
1207 if len(uidnumbersearch) > 1:
1208
1209 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_UID
1210
1211 elif len(uidnumbersearch) == 0:
1212
1213 raise easyLDAP_exceptions.NO_SUCH_POSIXACCOUNT
1214
1215 else:
1216 uid = uidnumbersearch[0][1]['uid'][0]
1217
1218 return uid
1219
1220 except ldap.SERVER_DOWN:
1221 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1222
1223
1225 """
1226 thisClass.map_gid2gidNumber ('myGID')
1227
1228 transforms the given gid 'myGID' to the corresponding gidNumber.
1229 The search is started at base DN thisClass.BaseDN.
1230 """
1231 from easyLDAP_utils import ldapDictionaryDecode
1232
1233 try:
1234 if type(this_gid) is types.ListType:
1235 gid = str(this_gid[0])
1236 else:
1237 gid = str(this_gid)
1238 gidsearch = ldapDictionaryDecode(self.ldapsession.search_s(self.BaseDN, ldap.SCOPE_SUBTREE,'(&(objectClass=posixGroup)(cn='+gid+'))'), config_defaults=self.CONFIG)
1239
1240 if len(gidsearch) > 1:
1241
1242 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_GID
1243
1244 elif len(gidsearch) == 0:
1245
1246 raise easyLDAP_exceptions.NO_SUCH_POSIXGROUP
1247
1248 else:
1249 if gidsearch[0][1].has_key('gidNumber'):
1250 gidNumber = int(gidsearch[0][1]['gidNumber'][0])
1251 return gidNumber
1252 else:
1253
1254 self.raise_easyldap_exception(err_code=27)
1255 except ldap.SERVER_DOWN:
1256 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1257
1258
1260 """
1261 thisClass.map_gidNumber2gid ('myGIDNUMBER')
1262
1263 transforms the given gidNumber 'myGIDNUMBER' to the corresponding gid.
1264 The search is started at base DN thisClass.BaseDN.
1265 """
1266 from easyLDAP_utils import ldapDictionaryDecode
1267
1268 try:
1269 if type(gid_number) is types.ListType:
1270 gid_number = str(gid_number[0])
1271 else:
1272 gid_number = str(gid_number)
1273 gidnumbersearch = ldapDictionaryDecode(self.ldapsession.search_s(self.BaseDN, ldap.SCOPE_SUBTREE,'(&(objectClass=posixGroup)(gidNumber='+gidnumber+'))'), config_defaults=self.CONFIG)
1274
1275 if len(gidnumbersearch) > 1:
1276
1277 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_GID
1278
1279 elif len(gidnumbersearch) == 0:
1280
1281 raise easyLDAP_exceptions.NO_SUCH_POSIXGROUP
1282
1283 else:
1284 cn = gidnumbersearch[0][1]['cn'][0]
1285 return cn
1286
1287 except ldap.SERVER_DOWN:
1288 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1289
1290
1291 - def map_uid2dn(self, uid, searchbase=None, scope=ldap.SCOPE_SUBTREE):
1292 """
1293 thisClass.map_uid2dn ('myUID')
1294
1295 transforms the given uid 'myUID' - if unique - to the corresponding
1296 DN in the LDAP tree. The search is started at base DN thisClass.BaseDN.
1297 """
1298 from easyLDAP_utils import ldapDictionaryDecode
1299
1300 if searchbase is None:
1301 searchbase = self.BaseDN
1302
1303 res = ldapDictionaryDecode(self.ldapsession.search_s(searchbase, scope, 'uid='+uid,None), config_defaults=self.CONFIG)
1304
1305 if len(res) < 1:
1306 return None
1307
1308 elif len(res) == 1:
1309 return ( res[0][0] )
1310
1311 elif len(res) > 1:
1312 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_UID
1313
1314
1315 - def map_gid2dn(self, gid, searchbase=None, scope=ldap.SCOPE_SUBTREE):
1316 """
1317 thisClass.map_gid2dn ('myGID')
1318
1319 transforms the given gid 'myGID' - if unique - to the corresponding
1320 DN in the LDAP tree. The search is started at base DN thisClass.BaseDN.
1321 """
1322 from easyLDAP_utils import ldapDictionaryDecode
1323
1324 if searchbase == '':
1325 searchbase = self.BaseDN
1326 res=ldapDictionaryDecode(self.ldapsession.search_s(searchbase, scope, 'cn='+gid,None), config_defaults=self.CONFIG)
1327
1328 if len(res) < 1:
1329 return None
1330
1331 elif len(res) == 1:
1332 return ( res[0][0] )
1333
1334 elif len(res) > 1:
1335 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_UID
1336
1337
1338 - def map_cn2dn(self, cn, searchbase=None, scope=ldap.SCOPE_SUBTREE):
1339 """
1340 thisClass.map_cn2dn ('myCN')
1341
1342 transforms the given common name 'myCN' - if unique - to the
1343 corresponding DN in the LDAP tree. The search is started at
1344 base DN thisClass.BaseDN.
1345 """
1346 from easyLDAP_utils import ldapDictionaryDecode
1347
1348 if searchbase is None:
1349 searchbase = self.BaseDN
1350 res=ldapDictionaryDecode(self.ldapsession.search_s(searchbase, scope, 'cn='+cn, None), config_defaults=self.CONFIG)
1351
1352 if len(res) < 1:
1353 return None
1354
1355 elif len(res) == 1:
1356 return ( res[0][0] )
1357
1358 elif len(res) > 1:
1359 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_CN
1360
1361
1362 - def map_ou2dn(self, ou, searchbase=None, scope=ldap.SCOPE_SUBTREE):
1363 """
1364 thisClass.map_ou2dn ('myOU', 'mySUBTREE')
1365
1366 transforms the given organizationalUnit 'myOU' - if unique - to the
1367 corresponding DN in the LDAP tree. The search is started at
1368 base DN thisClass.BaseDN.
1369 """
1370 from easyLDAP_utils import ldapDictionaryDecode
1371
1372 if searchbase is None:
1373 searchbase = self.BaseDN
1374 res = ldapDictionaryDecode(self.ldapsession.search_s(searchbase, scope, '(&(objectClass=organizationalUnit)(ou='+ou+'))',None), config_defaults=self.CONFIG)
1375
1376 if len(res) < 1:
1377 return None
1378
1379 elif len(res) == 1:
1380 return ( res[0][0] )
1381
1382 elif len(res) > 1:
1383 raise easyLDAP_exceptions.MULTIPLE_DNs_FOR_OU
1384
1385
1387 """
1388 thisClass.map_dn2ufn ('myDN'):
1389
1390 tries to map a given \'myDN\' to a user-friendly DN. This
1391 method is taken directly from python-ldap.
1392 """
1393 if searchbase is None:
1394 searchbase = self.BaseDN
1395
1396 return ''
1397
1398
1400 """
1401 thisClass.map_uid2posixgroups ('myUID'[,'mySUBTREE'])
1402
1403 find all ldap groups that the given uid 'myUID' is a posix member of.
1404 As a result the method returns a list of posixGroup DNs.
1405 The search is started at base DN thisClass.BaseDN if not otherswise
1406 specified in 'mySUBTREE'.
1407 """
1408 from easyLDAP_utils import ldapDictionaryDecode
1409
1410 if searchbase is None:
1411 searchbase = self.BaseDN
1412 res = ldapDictionaryDecode(self.ldapsession.search_s(searchbase, scope, 'memberUid='+this_uid,None), config_defaults=self.CONFIG)
1413
1414 if len(res) < 1:
1415 return None
1416
1417 elif len(res) >= 1:
1418 return ( [obj[0] for obj in res] )
1419
1420
1421 - def map_uid2uniquemembergroups(self,uid,searchbase=None, user_searchbase=None, group_searchbase=None, scope=ldap.SCOPE_SUBTREE):
1422 """
1423 thisClass.map_uid2uniquemembergroups ('myUID'[,'mySUBTREE'])
1424
1425 find all groups that the given uid 'myUID' is a unique member of.
1426 As a result the method returns a list of posixGroup DNs.
1427 The search is started at base DN thisClass.BaseDN if not otherswise
1428 specified in 'mySUBTREE'.
1429 """
1430 from easyLDAP_utils import ldapDictionaryDecode
1431
1432 if searchbase is None:
1433 if user_searchbase is None:
1434 user_searchbase = self.BaseDN
1435 if group_searchbase is None:
1436 group_searchbase = self.BaseDN
1437 else:
1438 user_searchbase = group_searchbase = searchbase
1439
1440 userDn = self.map_uid2dn(uid, searchbase=user_searchbase)
1441 if userDn is not None:
1442
1443
1444
1445
1446
1447 searchres=ldapDictionaryDecode(self.ldapsession.search_s(this_subtree, ldap.SCOPE_SUBTREE, '(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames))',None), config_defaults=self.CONFIG)
1448
1449 if len(searchres) < 1:
1450 return None
1451
1452 elif len(searchres) >= 1:
1453 res = copy.deepcopy(searchres)
1454 for obj in searchres:
1455
1456 uid_in_group = False
1457
1458
1459 unique_members = []
1460 if obj[1].has_key('member'):
1461 unique_members = unique_members + obj[1]['member']
1462 if obj[1].has_key('uniqueMember'):
1463 unique_members = unique_members + obj[1]['uniqueMember']
1464
1465 for unique_member in unique_members:
1466 if re.match ('^uid=%s,.*' % uid,unique_member):
1467 uid_in_group = True
1468
1469 if not uid_in_group:
1470 res.remove(obj)
1471
1472 return [obj[0] for obj in res]
1473 else:
1474 return None
1475
1476
1477 - def has_dn(self, dn, searchbase=None, scope=ldap.SCOPE_SUBTREE):
1478 """
1479 thisClass.has_dn ('myDN')
1480
1481 checks, if the given distinguished name \'myDN\' exists in
1482 the server\'s LDAP directory. The searches starts with the
1483 thisClass.BaseDN.
1484 """
1485 from easyLDAP_utils import ldapDictionaryDecode
1486
1487 try:
1488 searchtest = ldapDictionaryDecode(self.ldapsession.search_s(dn, scope, 'objectClass=*'), config_defaults=self.CONFIG)
1489 return True
1490 except ldap.NO_SUCH_OBJECT:
1491 return False
1492 except ldap.INVALID_DN_SYNTAX:
1493 raise easyLDAP_exceptions.INVALID_DN_SYNTAX
1494
1495
1497 """
1498 thisClass.get_basedn ()
1499
1500 returns the absolute DN of the currently
1501 cached easyLDAP object/tree/subtree
1502 from the LDAP server's directory tree.
1503 """
1504 return self.BaseDN
1505
1506
1508 """
1509 thisClass.get_people_basedn ()
1510
1511 """
1512 return self.PeopleBaseDN
1513
1514
1516 """
1517 thisClass.get_groups_basedn ()
1518
1519 """
1520 return self.GroupsBaseDN
1521
1522
1524 """
1525 thisClass.get_hosts_basedn ()
1526
1527 """
1528 return self.HostsBaseDN
1529
1530
1532 """
1533 thisClass.get_admin_dn ()
1534
1535 """
1536 return self.AdminDN
1537
1538
1561
1562
1564 """
1565 thisClass.get_parent_rdn ('myDN')
1566
1567 returns the parent relative DN of 'myDN'
1568 from the LDAP server's directory tree.
1569 """
1570 parent_dn = get_parent_dn(dn)
1571 return split_dn(parent_dn)[0]
1572
1573
1575 """
1576 thisClass.has_parent_dn ('myDN')
1577
1578 tests the existence of the referred object with a
1579 live search request to the LDAP server.
1580 """
1581 from easyLDAP_utils import ldapDictionaryDecode
1582
1583 parent_dn = self.get_parent_dn (dn)
1584 try:
1585 ldap_search = ldapDictionaryDecode(self.ldapsession.search_s(parent_dn, ldap.SCOPE_ONELEVEL, 'objectClass=*'), config_defaults=self.CONFIG)
1586 return True
1587 except ldap.NO_SUCH_OBJECT:
1588 return False
1589
1590
1592 """
1593 thisClass.get_samelevel_dns ('myDN')
1594
1595 returns a list with distinguished names that exist on the same level
1596 as the given DN 'myDN'.
1597
1598 If the DN 'myDN' is alone on its level, it will be the only item
1599 in the list.
1600
1601 If the returned list is empty, an error occurred.
1602 """
1603 from easyLDAP_utils import ldapDictionaryDecode
1604
1605 dnList = []
1606
1607 if use_cache:
1608 pass
1609
1610 else:
1611 try:
1612 if self.has_parent_dn(dn):
1613 dn_search = ldapDictionaryDecode(self.ldapsession.search_s(self.get_parent_dn(dn),ldap.SCOPE_ONELEVEL,'objectClass=*'), config_defaults=self.CONFIG)
1614 for object in dn_search:
1615 dnList.append(object[0].lower())
1616 dnList.remove(dn.lower())
1617 except ldap.SERVER_DOWN:
1618 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1619
1620 return dnList
1621
1622
1624 """
1625 thisClass.get_subleveldns ('myDN')
1626
1627 returns a list with distinguished names that exist exactly below
1628 the given DN 'myDN'.
1629
1630 If the easyLDAP object has no objects on its sublevel, the result will
1631 be an empty list. If an LDAP error occurs, the list will also be empty!
1632 """
1633 from easyLDAP_utils import ldapDictionaryDecode
1634
1635 dnList = []
1636
1637 if use_cache:
1638 pass
1639
1640 else:
1641 try:
1642 dn_search = ldapDictionaryDecode(self.ldapsession.search_s(dn,ldap.SCOPE_ONELEVEL,'objectClass=*'), config_defaults=self.CONFIG)
1643 for object in dn_search:
1644 dnList.append(object[0].lower())
1645 except ldap.SERVER_DOWN:
1646 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1647
1648 return dnList
1649
1650
1652 """
1653 thisClass.get_sublevelrdns ('myDN')
1654
1655 returns a list with reduced distinguished names that exist exactly below
1656 the given DN 'myDN'.
1657
1658 If the easyLDAP object has no objects on its sublevel, the result will
1659 be an empty list. If an LDAP error occurs, the list will also be empty!
1660 """
1661 from easyLDAP_utils import ldapDictionaryDecode
1662
1663 dnList = []
1664
1665 if use_cache:
1666 pass
1667
1668 else:
1669 try:
1670 dn_search = ldapDictionaryDecode(self.ldapsession.search_s(dn,ldap.SCOPE_ONELEVEL,'objectClass=*'), config_defaults=self.CONFIG)
1671 for object in dn_search:
1672 dnList.append(string.split(object[0].lower(),',')[0])
1673 except ldap.SERVER_DOWN:
1674 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1675
1676 return dnList
1677
1678
1680 """
1681 thisClass.get_subtree_dns (this_dn)
1682
1683 returns a tree of all distinguished names that exists below
1684 the given DN 'myDN'.
1685
1686 If the easyLDAP object has no objects on its sublevel,
1687 the result will be an empty list. If an LDAP error occurs,
1688 the list will also be empty!
1689 """
1690 from easyLDAP_utils import ldapDictionaryDecode
1691
1692 dnList = []
1693
1694 if use_cache:
1695 pass
1696
1697 else:
1698 try:
1699 dn_search = ldapDictionaryDecode(self.ldapsession.search_s(dn,ldap.SCOPE_SUBTREE,'objectClass=*'), config_defaults=self.CONFIG)
1700 for object in dn_search:
1701 dnList.append(object[0].lower())
1702 dnList.remove(this_dn.lower())
1703 except ldap.SERVER_DOWN:
1704 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1705
1706 return dnList
1707
1708
1712
1713
1717
1718
1720 """
1721 thisClass.get_samba3_algorithmicRidBase('myDOMAIN')
1722
1723 searches the LDAP tree starting at thisClass.BaseDN for
1724 the algorithmic RID base of Samba domain 'myDOMAIN'.
1725 """
1726 from easyLDAP_utils import ldapDictionaryDecode
1727
1728
1729 if self.has_samba3_schema():
1730
1731
1732 try:
1733 domainLDAPSearch = ldapDictionaryDecode (self.ldapsession.search_s(self.BaseDN,ldap.SCOPE_SUBTREE,'objectClass=sambaDomain'), config_defaults=self.CONFIG)
1734 for domain in domainLDAPSearch:
1735 if (len(domain[1]['sambaDomainName']) == 1) and (domain[1]['sambaDomainName'][0].upper() == this_domain.upper()):
1736 return int(domain[1]['sambaAlgorithmicRidBase'][0])
1737
1738
1739 return None
1740
1741 except ldap.SERVER_DOWN:
1742
1743
1744 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1745
1746
1747 else:
1748 raise easyLDAP_exceptions.SAMBA3_ONLY
1749
1750
1751 - def get_samba3_domainSID(self, domain):
1752 """
1753 thisClass.get_samba3_domainSID('myDOMAIN')
1754
1755 searches the LDAP tree starting at thisClass.BaseDN for
1756 the Samba PDC's sambaDomainName entry. When the method
1757 can find it, then it will extract the domain's SID.
1758 """
1759 from easyLDAP_utils import ldapDictionaryDecode
1760
1761
1762 if self.has_samba3_schema():
1763
1764
1765 try:
1766 domainLDAPSearch = ldapDictionaryDecode(self.ldapsession.search_s(self.BaseDN,ldap.SCOPE_SUBTREE,'objectClass=sambaDomain'), config_defaults=self.CONFIG)
1767 for domain in domainLDAPSearch:
1768 if (len(domain[1]['sambaDomainName']) == 1) and (domain[1]['sambaDomainName'][0].upper() == this_domain.upper()):
1769 return domain[1]['sambaSID'][0]
1770
1771
1772 return None
1773
1774 except ldap.SERVER_DOWN:
1775
1776
1777 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1778
1779
1780 else:
1781 raise easyLDAP_exceptions.SAMBA3_ONLY
1782
1783
1784 - def find_newUidNumber(self, min_uidNumber=None, max_uidNumber=None, searchbase=None, cached_searchresult=None):
1785 """
1786 self.find_newUidNumber (minUID,maxUID,myPEOPLEBASEDN)
1787
1788 live searches the connected LDAP server for the lowest
1789 vacant uidNumber between minUID and maxUID.
1790
1791 If myPEOPLEBASEDN is not specified, the easyLDAP
1792 thisClass.PeoplebaseDN is presumed.
1793
1794 The method only checks vacant uidNumber in the connected
1795 LDAP tree. Other sources for posixUserIDs (/etc/passwd,
1796 NIS, etc.) are not taken into consideration!
1797
1798 If an error occurs or no vacant uidNumber can be found,
1799 the method returns '-1'.
1800 """
1801 from easyLDAP_utils import ldapDictionaryDecode
1802
1803 if searchbase is None:
1804 searchbase = self.PeopleBaseDN
1805
1806 my_min = min_uidNumber or self.posix_availableUidNumbers['min']
1807 my_max = max_uidNumber or self.posix_availableUidNumbers['max']
1808
1809 if 0 < int(my_min) < int(my_max):
1810 try:
1811 if cached_searchresult is None:
1812 searchresult = ldapDictionaryDecode(self.ldapsession.search_s(searchbase,ldap.SCOPE_SUBTREE,'uidNumber=*'), config_defaults=self.CONFIG)
1813 else:
1814 searchresult = cached_searchresult
1815
1816 uidList = []
1817 for obj in searchresult:
1818 try:
1819 uidList.append(int(obj[1]['uidNumber'][0]))
1820 except ValueError:
1821 continue
1822 searchUID = int(my_min)
1823 while (searchUID in uidList) and (searchUID <= my_max):
1824 searchUID += 1
1825
1826 if searchUID <= my_max:
1827 return searchUID
1828 else:
1829
1830 raise easyLDAP_exception.NO_VACANT_UIDNUMBER
1831
1832 except ldap.SERVER_DOWN:
1833
1834 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1835
1836 else:
1837
1838 raise easyLDAP_exceptions.UIDNUMBER_RANGE_FAULTY
1839
1840
1841 - def find_newGidNumber(self, min_gidNumber=None, max_gidNumber=None, searchbase=None, cached_searchresult=None):
1842 """
1843 self.find_newGidNumber(minGID,maxGID,myGROUPSBASEDN)
1844
1845 searches the connected LDAP server for the lowest
1846 vacant gidNumber between minGID and maxGID.
1847
1848 If myGROUPSBASEDN is not specified, the easyLDAP
1849 thisClass.GroupBaseDN is presumed.
1850
1851 The method only checks vacant gidNumber in the connected
1852 LDAP tree. Other sources for posixGroupIDs (/etc/groups,
1853 NIS, etc.) are not taken into consideration!
1854
1855 If an error occurs or no vacant gidNumber can be found,
1856 the method returns '-1'.
1857 """
1858 from easyLDAP_utils import ldapDictionaryDecode
1859
1860 if searchbase is None:
1861 searchbase = self.GroupsBaseDN
1862
1863 my_min = min_gidNumber or self.posix_availableGidNumbers['min']
1864 my_max = max_gidNumber or self.posix_availableGidNumbers['max']
1865
1866 if 0 < int(my_min) < int(my_max):
1867 try:
1868 if cached_searchresult is None:
1869 searchresult = ldapDictionaryDecode(self.ldapsession.search_s(searchbase,ldap.SCOPE_SUBTREE,'&(objectClass=posixGroup)(gidNumber=*)'), config_defaults=self.CONFIG)
1870 else:
1871 searchresult = cached_searchresult
1872
1873 gidList = []
1874 for obj in searchresult:
1875 try:
1876 gidList.append(int(obj[1]['gidNumber'][0]))
1877 except ValueError:
1878 continue
1879
1880 searchGID = int(my_min)
1881 while (searchGID in gidList) and (searchGID <= my_max):
1882 searchGID += 1
1883
1884 if searchGID <= my_max:
1885 return searchGID
1886 else:
1887
1888 raise easyLDAP_exception.NO_VACANT_GIDNUMBER
1889
1890 except ldap.SERVER_DOWN:
1891
1892 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1893
1894 else:
1895
1896 raise easyLDAP_exceptions.GIDNUMBER_RANGE_FAULTY
1897
1898
1900 """
1901 thisClass.show_objectclass ('myOBJECT_CLASS'):
1902
1903 displays an objectClass's schema in a user-friendly manner...
1904 """
1905 flagDict = {'SINGLE-VALUE': 'sv', 'OBSOLETE': 'obs', 'NO-USER-MODIFICATION': 'num', 'COLLECTIVE': 'col'}
1906
1907 if self.objectClassesDict.has_key(this_objectclass):
1908 print
1909 print 'objectClass:', this_objectclass
1910 print '------------'
1911 for key in ['OID','DESC','SUP','MUST','MAY','STRUCTURAL', 'AUXILIARY']:
1912
1913
1914
1915 if type(self.objectClassesDict[this_objectclass][key]) is types.ListType:
1916 sortedAttributes = self.objectClassesDict[this_objectclass][key]
1917
1918
1919 for listindex in range (0, len(sortedAttributes)):
1920
1921 try:
1922 attr = self.objectClassesDict[this_objectclass][key][listindex]
1923 oid = self.map_attrtypes2oids(attr)
1924 syntax = self.map_attrtype2ldapsyntax(attr)
1925
1926
1927 except easyLDAP_exceptions.NO_SUCH_ATTRIBUTE:
1928 oid = ['NONE']
1929 syntax = ['NONE']
1930
1931
1932 try:
1933 flags = ''
1934 for flagKey in flagDict.keys():
1935 if self.attributeTypesDict[attr][flagKey]:
1936 flags = flags + '+' + flagDict[flagKey] + ','
1937 else:
1938 flags = flags + '-' + flagDict[flagKey] + ','
1939 flags = string.rstrip(flags,',')
1940 except KeyError:
1941 flags = 'NONE'
1942
1943 print '%s: %s (OID: %s, Syntax: %s, Flags: %s)' % (key, attr, oid[0], syntax, flags)
1944
1945 else:
1946
1947 print '%s: %s' % (key, self.objectClassesDict[this_objectclass][key])
1948 print
1949
1950 return True
1951
1952 else:
1953
1954 raise easyLDAP_exceptions.NO_SUCH_OBJECTCLASS
1955
1956
1958 """
1959 thisClass.get_cache_reference()
1960
1961 commits a search operation on the LDAP server with
1962 starting with thisClass.ObjectCacheBaseDN as the base DN.
1963 The result of this operation can be compared to the
1964 current content of the easyLDAP cache to figure out
1965 what changes have been made to the object in cache
1966 by easyLDAP methods.
1967
1968 If an error occurs, an empty list will be returned.
1969 """
1970 from easyLDAP_utils import ldapDictionaryDecode
1971
1972
1973 cache_reference = [(dn,{})]
1974 try:
1975 cache_reference = ldapDictionaryDecode(self.ldapsession.search_s(dn,scope,'objectClass=*'), config_defaults=self.CONFIG)
1976 return cache_reference
1977 except ldap.NO_SUCH_OBJECT:
1978
1979 return cache_reference
1980 except ldap.SERVER_DOWN:
1981 raise easyLDAP_exceptions.SERVER_UNAVAILABLE
1982
1983
1985 """
1986 dummy method, will be used in classes easyLDAP_object, easyLDAP_tree, etc.
1987 """
1988 return True
1989
1990 if __name__=='__main__':
1991 pass
1992