Package easyLDAP :: Module easyLDAP_class_object_base
[frames] | no frames]

Source Code for Module easyLDAP.easyLDAP_class_object_base

   1  # -*- coding: utf-8 -*- 
   2   
   3  #    easyLDAP - a python library that makes LDAP management easier than before... 
   4  #    Copyright (C) 2004-2010,2020  Mike Gabriel <m.gabriel@das-netzwerkteam.de> 
   5  # 
   6  #    This program is free software: you can redistribute it and/or modify 
   7  #    it under the terms of the GNU General Public License as published by 
   8  #    the Free Software Foundation, either version 3 of the License, or 
   9  #    (at your option) any later version. 
  10  # 
  11  #    This program is distributed in the hope that it will be useful, 
  12  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  14  #    GNU General Public License for more details. 
  15  # 
  16  #    You should have received a copy of the GNU General Public License 
  17  #    along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  18  # 
  19   
  20  # these modules appear in python-ldap 
  21  import ldap, ldap.schema 
  22   
  23  # these modules appear in python-crypto 
  24  from Crypto.Hash import MD4 
  25  from Crypto.Cipher import DES 
  26   
  27  import easyLDAP_defaults 
  28  from easyLDAP_exceptions import * 
  29   
  30  from easyLDAP_utils import * 
  31  from easyLDAP_utils import _attrtype, _attropt, _attrdesc, _unique 
  32  from easyLDAP_bind import * 
  33  from easyLDAP_class_base import * 
  34  from easyLDAP_class_cache import * 
  35   
36 -class easyLDAP_object(easyLDAP):
37 38 _ldap_cacheobject = None 39 _init_dn = '' 40
41 - def _method_aliases(self):
42 43 easyLDAP._method_aliases(self) 44 45 self.get_cache_basedn = self.get_object_dn 46 self.get_cachebasedn = self.get_object_dn 47 self.get_objectdn = self.get_object_dn 48 self.get_baserdn = self.get_object_rdn 49 self.load_cache = self.refresh_cache 50 self.add_objectclass = self.add_objectclasses 51 self.del_attrdesc_value = self.del_attrdesc_values 52 self.modify_object_dn = self.set_object_dn 53 self.get_usedobjectclasses = self.get_used_objectclasses 54 self.get_attrdesc = self.get_attrdesc_values 55 self.show = self.show_cache 56 self.flush = self.flush_cache 57 self.clear = self.clear_cache
58
59 - def __init__(self, dn_or_cacheobject, bind_dn=None, bind_pw=None, config_defaults=EASY_LDAP, update_schema_cache=False, use_cache_history=True, ldapsession=None):
60 61 easyLDAP.__init__(self, bind_dn=bind_dn, bind_pw=bind_pw, config_defaults=config_defaults, update_schema_cache=update_schema_cache, ldapsession=ldapsession) 62 63 self.use_cache_history = use_cache_history 64 if isinstance(dn_or_cacheobject, easyLDAP_cacheobject): 65 self._ldap_cacheobject = dn_or_cacheobject 66 dn = self._ldap_cacheobject.get_cacheobject_dn() 67 self._init_dn = dn 68 else: 69 dn = dn_or_cacheobject 70 self._init_dn = dn 71 self.refresh_cache() 72 73 self._method_aliases()
74
75 - def __deepcopy__(self, memo):
76 """Creates a deepcopy of the easyLDAP object class.""" 77 result = self.__class__(self.get_object_dn()) 78 memo[id(self)] = result 79 80 result._ldap_cacheobject = copy.deepcopy(self._ldap_cacheobject,memo) 81 82 result.LDAPuri = self.LDAPuri 83 result.LDAPserver = self.LDAPserver 84 result.BindDN = self.BindDN 85 result.BindPW = self.BindPW 86 result.BaseDN = self.BaseDN 87 result.AdminDN = self.AdminDN 88 result.PeopleBaseDN = self.PeopleBaseDN 89 result.GroupBaseDN = self.GroupsBaseDN 90 result.HostsBaseDN = self.HostsBaseDN 91 result.MailAliasesBaseDN = self.MailAliasesBaseDN 92 result.AutomountBaseDN = self.AutomountBaseDN 93 result.LDAPServerCharsetEncoding = self.LDAPServerCharsetEncoding 94 result.posix_availableUidNumbers = self.posix_availableUidNumbers 95 result.posix_availableGidNumbers = self.posix_availableGidNumbers 96 if (self.BindDN != 'anonymous') and self.has_dn(self.BindDN): 97 result.bind_norefresh(self.BindDN, self.BindPW) 98 99 result.objectClasses=self.objectClasses 100 result.attributeTypes=self.attributeTypes 101 result.matchingRules=self.matchingRules 102 result.ldapSyntaxes=self.ldapSyntaxes 103 104 return result
105
106 - def __call__(self):
107 self.show_cache()
108 109
110 - def _new_object(self, pyldapobject):
111 self._ldap_cacheobject = easyLDAP_cacheobject(pyldapobject, config_defaults=self.CONFIG, use_cache_history=self.use_cache_history)
112 113
114 - def set_object_dn(self, dn):
115 # TODO: test for BaseDN in dn 116 self._ldap_cacheobject.set_cacheobject_dn(dn)
117 118
119 - def add_attrdesc_values(self, attrdesc, values):
120 return self._modify_attrdesc(attrdesc, values, mod_type=easyLDAP_ADDATTR)
121 122
123 - def get_object(self):
125 126
127 - def _get_object_data(self):
128 return self._ldap_cacheobject._get_cacheobject_data()
129 130
131 - def get_parent_dn(self):
132 133 return easyLDAP.get_parent_dn(self, dn=self.get_object_dn())
134 135
136 - def get_object_dn(self):
137 return ((self._ldap_cacheobject and self._ldap_cacheobject.get_cacheobject_dn()) or self._init_dn)
138 139
140 - def get_object_rdn(self):
141 """ 142 thisClass.get_object_rdn() 143 144 returns the relative DN of the cached easyLDAPobject 145 (i.e. the first protion of the object's DN). 146 """ 147 return string.split(self.get_object_dn(), ',')[0]
148 149
150 - def get_used_attrdescs_aliases(self, attrdescs, capitalize=True):
151 """ 152 """ 153 attrdescs_list = to_list_of_strings(attrdescs) 154 155 oid_based_attrdescs = [] 156 for attrdesc in attrdescs_list: 157 oid = self.map_attrtypes2oids(_attrtype(attrdesc))[0] 158 oid_based_attrtypes = self.map_oid2attrtypes(oid) 159 160 oid_based_attrdesc = None 161 intersection = intersect(oid_based_attrtypes, self.get_used_attrtypes()) 162 if intersection: 163 164 attrtype = intersection[0] 165 if _attropt(attrdesc): 166 oid_based_attrdesc = '%s;%s' % (attrtype, _attropt(attrdesc)) 167 else: 168 oid_based_attrdesc = attrtype 169 if capitalize: 170 oid_based_attrdesc = self._rewrite_attrtype_names(oid_based_attrdesc) 171 172 if not oid_based_attrdesc: 173 raise easyLDAP_exceptions.ATTRDESC_NOT_SET 174 175 if type(attrdescs) is types.StringType: 176 177 return oid_based_attrdesc 178 179 else: 180 oid_based_attrdescs.append(oid_based_attrdesc) 181 182 return oid_based_attrdescs
183 184 185
186 - def get_attrdesc_values(self, attrdesc):
187 """ 188 """ 189 if type(attrdesc) is not types.StringType: 190 raise TypeError 191 192 used_attrdesc = self.get_used_attrdescs_aliases(attrdesc) 193 return self._ldap_cacheobject.get_cacheobject_attrdesc(used_attrdesc, ignore_case=True)
194 195 196
197 - def get_attrtype_values(self, attrtype):
198 """ 199 get_attrtype_values('myATTRTYPE') 200 201 returns a dictionary that contains all attribute descriptions 202 in the easyLDAP object cache that contain the attribute type 203 'myATTRTYPE'. 204 205 This method is handy for e.g. viewing all attribute type's 206 translations. 207 208 On failure, the method returns an empty dictionary. 209 """ 210 from easyLDAP_utils import _attrtype 211 value_dict = {} 212 if self.map_attrtype2oid(_attrtype(attrtype))[0] in self.get_used_attrtype_oids(): 213 for option in self.get_used_attropt(_attrtype(attrtype)): 214 if option: 215 value_dict['%s;%s' %(_attrtype(attrtype),option)] = self.get_attrdesc_values('%s;%s' % (_attrtype(attrtype),option)) 216 else: 217 value_dict[_attrtype(attrtype)] = self.get_attrdesc_values(_attrtype(attrtype)) 218 return value_dict 219 220 return {}
221 222
223 - def get_used_attrtype_oids(self, pyldapobject=None):
224 return easyLDAP.get_used_attrtype_oids(self, self.get_object())
225 226
227 - def has_oid_set (self, oid, pyldapobject=None):
228 return easyLDAP.has_oid_set(self, oid, self.get_object())
229 230
231 - def get_used_attrtypes(self, pyldapobject=None):
232 return easyLDAP.get_used_attrtypes(self,self.get_object())
233 234
235 - def get_used_attroptions(self,attrdesc):
236 return easyLDAP.get_used_attroptions(self,attrdesc,self.get_object())
237 238
239 - def get_used_objectclasses(self):
240 """ 241 thisClass.get_usedobjectclasses([mySINGLELDAPOBJECT]) 242 243 returns a list of objectClasses that are used in the current easyLDAP 244 object. If - by some reason - the cache is empty, an empty list 245 is returned. 246 247 Another LDAP object than the one currently cached 248 can be analyzed by passing 'mySINGLELDAPOBJECT'. The 249 lengths of the passed LDAP object has to be 1. 250 """ 251 try: 252 return self._ldap_cacheobject.get_cacheobject_attrdesc('objectClass') 253 except easyLDAP_exceptions.ATTRDESC_NOT_SET: 254 return []
255 256
257 - def get_used_attrdescs(self):
258 """ 259 thisClass.get_used_attrdescs() 260 261 returns a list of all attribute descriptions that are used in the current easyLDAP 262 object. 263 """ 264 from easyLDAP_utils import _attrtype, _attropt 265 return [ self._rewrite_attrtype_names(attrdesc) for attrdesc in self._get_object_data().keys() ]
266 267
268 - def has_objectclass_set(self, objectclass):
269 """ 270 thisClass.has_objectclass_set('myOBJECTCLASS'): 271 272 returns True, if the objectClass 'myOBJECTCLASS' is set 273 in the cached easyLDAP object. 274 """ 275 return (objectclass.lower() in [ obc.lower() for obc in self.get_used_objectclasses() ])
276 277
278 - def has_attrtype_set(self, attrtype):
279 """ 280 thisClass.has_attrtype_set('myATTRTYPE'): 281 282 returns True, if the attribute type 'myATTRTYPE' is set 283 in the cached easyLDAP object. The attribute type 284 is checked on an OID basis. 285 """ 286 return (attrtype.lower() in self.get_used_attrtypes())
287 288
289 - def has_attrdesc_set(self, attrdesc):
290 """ 291 thisClass.has_attrdesc_set('myATTRDESC'): 292 293 returns True, if the attribute 'myATTRDESC' is set 294 in the cached easyLDAP object. The attribute type 295 is checked on an OID basis. 296 """ 297 try: 298 dummy = self.get_attrdesc_values(attrdesc) 299 return True 300 except easyLDAP_exceptions.ATTRDESC_NOT_SET: 301 return False
302 303
304 - def has_value(self, value):
305 """ 306 thisClass.has_value('myVALUE'): 307 308 returns True, if the value 'myVALUE' is set 309 in the cached easyLDAP object, regardless from 310 the attribute it is set for. 311 """ 312 for checkAttribute, checkValue in self._get_object_data().items(): 313 if value in checkValue: 314 return True 315 return False
316 317
318 - def has_attrdesc_values_set(self, attrdesc, values):
319 """ 320 thisClass.has_attrdesc_values_set('myATTRDESC', 'myVALUE'): 321 322 returns True, if the list of values 'myVALUES' 323 is identical to those found in the cached easyLDAP 324 object's attribute description 'myATTRDESC'. 325 """ 326 if self.has_attrdesc_set(attrdesc): 327 attributeOIDs = self.map_attrtypes2oids(attrdesc) 328 for checkAttribute in self.get_used_attrtypes(): 329 if (attributeOIDs == self.map_attrtypes2oids(checkAttribute)) and (self.get_attrdesc_values(checkAttribute) == values): 330 return True 331 return False
332 333
334 - def has_attrdesc_value_set_in_values(self, attrdesc, value):
335 """ 336 thisClass.has_attrdesc_value_set_in_values('myVALUE','myATTRDESC'): 337 338 returns True, if the value 'myVALUE' is set 339 in the cached easyLDAP object's attribute description 340 'myATTRDESC' (amongst other possible values). 341 """ 342 if self.has_attrdesc_set(attrdesc): 343 344 # we better compare OIDs than AtributeNameStrings!!! 345 attrOIDsinFunctionParam = self.map_attrtypes2oids(_attrtype(attrdesc)) 346 for checkAttributeDesc in self.get_used_attrtypes(): 347 attrOIDsinObject = self.map_attrtypes2oids(checkAttributeDesc) 348 if (attrOIDsinFunctionParam == attrOIDsinObject) and (_attropt(checkAttributeDesc) == _attropt(attrdesc)): 349 if value in self.get_attrdesc_values(checkAttributeDesc): 350 return True 351 352 return False
353 354
355 - def refresh_cache(self):
356 """ 357 thisClass.refresh_cache() 358 359 loads/refreshes the easyLDAP object cache. This method should be the only 360 easyLDAP module code that performs a read operation on the actual 361 LDAP directory server. 362 363 BEWARE: This method is called, when thisClass is initiated. 364 365 If the given DN (at __init__ time) exists in the LDAP directory, 366 this method: 367 368 - reads the DN\'s data LDAP directory from the LDAP directory, 369 - checks and repairs objectClass dependencies violations, 370 - moves the data in the easyLDAP cache. 371 372 If the given DN is new to the LDAP directory, this method: 373 374 - creates an empty easyLDAP object cache, 375 - marks the object as a new object, so the first 376 thisClass.flush_cache() operation will be 'ldap.add_s' 377 as opposed to 'ldap.modify_s' 378 379 Once the easyLDAP cache is filled with the DN data all modification 380 will be performed in the easyLDAP object cache. Once you are done, 381 use thisClass.flush_cache() to update the LDAP directory\'s 382 data. 383 384 WARNING: this method tries to repair buggy LDAP objects. If it finds an 385 attribute that does not have an objectClass set, the method will 386 try to find a usable objectClass (it will take the first it finds, 387 which might not be wanted). If there is no such objectClass 388 in the server\'s LDAP schema, the invalid attributes will be purged 389 from the object. This is a repair functionality and should not come to 390 use... 391 """ 392 from easyLDAP_utils import _attrtype 393 # 394 # TODO: if a new object is created, check if the underlying DN exists. 395 # 396 try: 397 398 # try a read operation on the LDAP directory. 399 ldap_import = ldapDictionaryDecode(self.ldapsession.search_s(self.get_object_dn(), ldap.SCOPE_BASE, 'objectClass=*'), config_defaults=self.CONFIG) 400 self._rewrite_names_to_fit_ldapschema(ldap_import) 401 402 if self._ldap_cacheobject is None: 403 self._new_object(ldap_import) 404 else: 405 # preserve easyLDAP_cacheobject class object if already created (important for objects derived 406 # in easyLDAP_tree 407 self._ldap_cacheobject.set_cacheobject(ldap_import) 408 409 self._ldap_cacheobject.disable_cache_history() 410 411 # this rather peculiar method call will repair objectClass dependency violations and missing MUST attribute types. 412 if not 'ABSTRACT' in self.get_used_objectclasses(): 413 self.add_objectclasses(self.get_used_objectclasses()) 414 415 # for attributes that by some reason do not have an objectClass, 416 # - add missing objectClass (take first objectClass in schema\'s dictionary), 417 # this might not be the wanted objectclass 418 # - delete the attribute from easyLDAP object cache, if there is no 419 # usable objectClass for this attribute... 420 # this code part is only for buggy ldap objects and should come to use!!! 421 for attrdesc in self.get_used_attrdescs(): 422 if attrdesc != 'objectClass': 423 possibleObjectClasses = [ o.lower() for o in self.map_attrtype2objectclasses(_attrtype(attrdesc)) ] 424 if possibleObjectClasses and not intersect([o.lower() for o in self.get_used_objectclasses() ], possibleObjectClasses): 425 if len(possibleObjectClasses) == 1: 426 self.add_objectclasses(possibleObjectClasses) 427 else: 428 self.del_attrdesc(attrdesc) 429 430 self.push_cache_history() 431 432 except ldap.NO_SUCH_OBJECT: 433 434 # no problem, create a new DN 435 if self._ldap_cacheobject is None: 436 self._new_object([(self.get_object_dn(), {})]) 437 else: 438 # preserve easyLDAP_cacheobject class object if already created (important for objects derived 439 # in easyLDAP_tree 440 self._ldap_cacheobject.set_cacheobject([(self.get_object_dn(), {})]) 441 self.push_cache_history() 442 443 except ldap.SERVER_DOWN: 444 445 # this is not good! The LDAP server appears to be down or the LDAP URI was incorrect. 446 raise easyLDAP_exceptions.SERVER_UNAVAILABLE 447 448 self._ldap_cacheobject.enable_cache_history()
449 450
451 - def map_diff2modlist(self):
452 """ 453 thisClass.map_diff2modlist() 454 455 returns a list of changes that have been applied to 456 the easyLDAP object chache. The format of this list 457 is conformant with the modlist structure in python- 458 ldap that is used for the methods 459 460 ldap.modify() / ldap.modify_s() 461 """ 462 return generate_modlist(self.get_cache_reference(dn=self.get_object_dn(), scope=ldap.SCOPE_BASE), copy.deepcopy(self.get_object()))
463 464
465 - def map_reverse_diff2modlist(self):
466 """ 467 thisClass.map_diff2modlist() 468 469 returns a list of changes applied to the easyLDAP 470 object cache that these changes can be undone with. 471 The format of this list is conformant with the modlist 472 structure in python-ldap that is used for the methods 473 474 ldap.modify() / ldap.modify_s() 475 """ 476 return self.generate_modlist(copy.deepcopy(self.get_object()),self.get_cache_reference(dn=self.get_object_dn(), scope=ldap.SCOPE_BASE))
477 478
479 - def map_diff2ldif(self):
480 """ 481 thisClass.map_diff2ldif() 482 483 returns the changes applied to the easyLDAP object cache in 484 ldif format. The method returns a python list in which each 485 item represents a line of the text base ldif format. 486 """ 487 return self.generate_ldif(self.get_cache_reference(dn=self.get_object_dn(), scope=ldap.SCOPE_BASE), copy.deepcopy(self.get_object()))
488 489
490 - def map_reverse_diff2ldif(self):
491 """ 492 thisClass.map_diff2ldif() 493 494 returns ldif output that can undo the changes applied to the 495 easyLDAP object cache. The method returns a python list in which 496 each item represents a line of the text base ldif format. 497 """ 498 return self.generate_ldif(copy.deepcopy(self.get_object()), self.get_cache_reference(dn=self.get_object_dn(), scope=ldap.SCOPE_BASE))
499 500
501 - def flush_cache(self):
502 """ 503 thisClass.flush_cache() 504 505 writes the easyLDAP object cache to the LDAP directory. This method 506 should be the only easyLDAP module code that performs a write operation 507 on the actual LDAP directory server. 508 509 If the given DN existed in the LDAP directory at __init__ time, 510 this method: 511 512 - checks, if the cached DN still exists in the LDAP directory 513 (otherwise, it switches to object creation mode). 514 - flushes modifications and additions to the easyLDAP object 515 cache to the server's LDAP directory. 516 517 If the given DN was new to the LDAP directory at __init__ time, 518 this method: 519 520 - checks, if the cached DN is still new to the LDAP directory 521 (otherwise, it switches to object modification mode). 522 - checks, if the underlying DN still exists in the directory. If 523 not the flush_cache() operation will fail. 524 - adds easyLDAP object cache to the LDAP directory. 525 526 If the easyLDAP object cache does not need a flush_cache() operation 527 (as it is up-to-date), the flush will not be performed (i.e. fail). 528 """ 529 # 530 # TODO: 531 # 532 # o on object creation, check if the DN still does not exist in the LDAP directory AND 533 # check, if the underlying DN still exists. 534 # o on object modification, check whether the DN still exists in the LDAP directory. 535 # 536 # if the cache is empty and the easyLDAP object is not a new object ... 537 if (self._get_object_data() == {}) and self.has_dn(self.get_object_dn()): 538 try: 539 self.ldapsession.delete_s(self.get_object_dn()) 540 return True 541 542 except ldap.INSUFFICIENT_ACCESS: 543 raise easyLDAP_exceptions.INSUFFICIENT_ACCESS 544 545 # else perform add or modify tasks on the (maybe not yet) existing dn 546 else: 547 # retrieve list of recent cache modifications 548 modlist = self.map_diff2modlist() 549 550 if modlist != []: 551 try: 552 if not self.has_dn(self.get_object_dn()): 553 addlist = [] 554 for mod in modlist: 555 addlist.append((mod[1], mod[2])) 556 self.ldapsession.add_s(self.get_object_dn(), addlist) 557 else: 558 self.ldapsession.modify_s(self.get_object_dn(), modlist) 559 return True 560 561 except ldap.INSUFFICIENT_ACCESS: 562 raise easyLDAP_exceptions.INSUFFICIENT_ACCESS 563 else: 564 # sync is not needed 565 return True
566 567
568 - def add_objectclasses(self, objectclasses):
569 """ 570 thisClass.add_objectclass('myOBJECTCLASS'|['myOBJECTCLASS1', 571 'myOBJECTCLASS2', ...]) 572 573 adds one ore more objectClass(es) and all needed SUPerior 574 objectClasses to the cached easyLDAP object. Attributes 575 that - according to the server's LDAP schema - MUST be 576 present will be set to default values regarding their 577 proposed syntaxes in thisClass.LDAPSyntaxes. 578 579 The default values are stored in thisClass.templateLDAPSyntaxValues. 580 """ 581 if type(objectclasses) is types.StringType: 582 objectclasses = [objectclasses] 583 584 # if we need a SUP objectClass, we have to add it here 585 objectclasses = [ objcl.lower() for objcl in self.check_objectclass_dependencies(objectclasses) ] 586 587 # add checked objectClasses 588 # go through the objectClasses that have to be added to the easyLDAP object cache 589 for this_objectClass in objectclasses: 590 591 # only add objectClasses that do not yet exist in the easyLDAP object cache 592 if (not self.has_attrdesc_set('objectClass') or (this_objectClass not in self.get_attrdesc_values('objectClass'))): 593 594 if self.objectClassesDict.has_key(this_objectClass): 595 # set attributes that MUST be set (according to server's LDAP schema) 596 # TODO: access objectClassesDict by method, not directly by property 597 for mustSetAttr in self.objectClassesDict[this_objectClass]['MUST']: 598 599 if mustSetAttr != 'objectclass': 600 601 try: 602 # use attribute OIDs as reference, not the attribute names!!! 603 if self.attributeTypesDict[mustSetAttr]['OID'] not in self.get_used_attrtype_oids(): 604 mustUseAttrSyntaxOID = self.map_attrtype2ldapsyntaxoid(mustSetAttr) or 'NO SPECIFIED SYNTAX' 605 self._ldap_cacheobject.set_cacheobject_attrdesc(self._rewrite_attrtype_names(mustSetAttr), self.ldapSyntaxesDict[mustUseAttrSyntaxOID]['DEFAULT']) 606 except KeyError: 607 608 # no such attribute type in LDAP schema 609 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE 610 611 # append the objectClass to the list 612 if self.has_attrdesc_set('objectClass'): 613 self.add_attrdesc_values('objectClass', this_objectClass) 614 else: 615 self.set_attrdesc('objectClass', this_objectClass) 616 617 else: 618 619 # no such object class in LDAP schema 620 raise easyLDAP_exceptions.NO_SUCH_OBJECTCLASS 621 622 # push the new status to the redo/undo stack 623 self.push_cache_history() 624 625 return True
626 627
628 - def get_used_attrtype_oids(self):
629 """ 630 thisClass.get_used_attrtype_oids() 631 632 returns a list of those attribute OIDs, that are used the 633 LDAP object 'mySINGLEOBJECT'. This list is taken from 634 the server's LDAP schema. 635 """ 636 from easyLDAP_utils import _attrtype 637 oidList=[] 638 for key in self._get_object_data().keys(): 639 oidList.append(self.attributeTypesDict[_attrtype(key).lower()]['OID']) 640 641 return _unique(oidList)
642 643
644 - def has_oid_set (self, oid, pyldapobject=None):
645 """ 646 thisClass.has_oid_set('myOID') 647 648 checks if the given OID 'myOID' is set in the 649 LDAP object 'mySINGLELDAPOBJECT'. If so, the method's 650 result is True. 651 """ 652 if oid in self.get_used_attrtype_oids(): 653 return True 654 655 return False
656 657
658 - def del_objectclass(self, del_these_objectClasses):
659 """ 660 thisClass.del_objectclass('myOBJECTCLASS'|['myOBJECTCLASS1', 661 'myOBJECTCLASS2', ...]) 662 663 deletes one ore more objectClass(es) from the cached 664 easyLDAP object. All attributes that only occur in the 665 deleted objectClass(es) are also removed - so be careful! 666 667 The method will abort ... 668 669 if one of the given objectClass names are not set in 670 the easyLDAP object cache. 671 672 The method ignores ... 673 674 objectClasses that are to be deleted, but are needed 675 as a SUPerior objectClass by another objectClass. 676 """ 677 # if the given objectClass is a string convert it to ListType 678 if type (del_these_objectClasses) is not types.ListType: 679 del_these_objectClasses = [del_these_objectClasses] 680 del_these_objectClasses = [ o.lower() for o in del_these_objectClasses ] 681 682 # delete the given objectClasses from the set objectClasses. 683 # This part will fail, if we want to delete an objectClass 684 # that is not set in the easyLDAP object cache. 685 setObjectClasses = [ o.lower() for o in self.get_attrdesc_values('objectClass') ] 686 for delObjectClass in del_these_objectClasses: 687 688 try: 689 # if the given objectClass is not set in the object cache we 690 # will rouse an exception right here! 691 delObjectClassIndex = setObjectClasses.index(delObjectClass) 692 if delObjectClass in setObjectClasses: 693 del setObjectClasses[delObjectClassIndex] 694 695 except ValueError: 696 697 # no such objectclass set in the easyLDAP object cache 698 raise easyLDAP_exceptions.NO_SUCH_OBJECTCLASS_SET 699 700 # if we have deleted a SUPerior objectClass, here it will be added again... 701 modifiedObjectClasses = self.check_objectclass_dependencies(setObjectClasses) 702 703 # dependencies seem to stay fine after deletion, so set the remaining objectClasses 704 self.set_attrdesc('objectClass', modifiedObjectClasses) 705 706 # check for attributes that have to be deleted as the do not conform with the remaining objectClasses 707 for delObjectClass in del_these_objectClasses: 708 allowedOIDs = [] 709 710 # find out which attributes can remain in the easyLDAP object 711 for remainingObjectClass in [ o.lower() for o in self.get_attrdesc_values('objectClass') ]: 712 713 # TODO: access objectClassesDict by method, not directly by property 714 allowedOIDs = allowedOIDs + self.map_attrtypes2oids(self.objectClassesDict[remainingObjectClass]['MUST'] + 715 self.objectClassesDict[remainingObjectClass]['MAY']) 716 717 # TODO: access objectClassesDict by method, not directly by property 718 checkAttributes = self.objectClassesDict[delObjectClass]['MUST']+self.objectClassesDict[delObjectClass]['MAY'] 719 720 # expel undefined attributes 721 for checkAttr in checkAttributes: 722 checkAttrOID = self.map_attrtypes2oids(checkAttr) 723 if (checkAttrOID == []) or (checkAttrOID[0] not in allowedOIDs): 724 if self._get_object_data().has_key(self._rewrite_attrtype_names(checkAttr)): 725 self.del_attrtype(checkAttr) 726 727 # push the new status to the redo/undo stack 728 self.push_cache_history() 729 730 return True
731 732
733 - def _modify_attrdesc(self, attrdesc, values, mod_type=easyLDAP_ADDATTR):
734 """ 735 thisClass.modify_attrdesc('myATTRDESC', 736 'myVAL'|['myVAL1', 'myVAL2', ...] 737 easyLDAP_ADDATTR|easyLDAP_REPLACEATTR 738 ) 739 740 modifies attributes of an easyLDAP object in the cache. The operations 741 easyLDAP_ADDATTR and easyLDAP_REPLACEATTR have several meanings, depending 742 on the situation: 743 744 easyLDAP_ADDATTR: 745 - attribute is not yet set: attribute is added and given values 746 are set for this attribute, 747 - attribute is already set: values are added to the already 748 existing values, if possible (cf. singleValues in LDAP schemas), 749 - if one of the given values is already set the method will ignore 750 it (unlike python-ldap). 751 easyLDAP_REPLACEATTR: 752 - attribute is set: completely replace old values by given values 753 - attribute is not set: set attribute with given values 754 """ 755 from easyLDAP_utils import _attrtype, _attropt, ia5string 756 757 if type(attrdesc) is not types.StringType: 758 raise TypeError 759 760 attrdesc = self._rewrite_attrtype_names(attrdesc) 761 762 attrtype_syntax = self.map_attrtype2ldapsyntax(_attrtype(attrdesc)) 763 attrtype_maxlen = self.map_attrtype2valuemaxlen(_attrtype(attrdesc)) 764 attrtype_value_pattern = attrtype_syntax['REGEXP'] 765 for val in to_list_of_strings(values): 766 if not re.match(attrtype_value_pattern, val): 767 raise easyLDAP_exceptions.INVALID_VALUE_SYNTAX 768 if attrtype_maxlen and len(val) > attrtype_maxlen: 769 raise easyLDAP_exceptions.VALUE_TOO_LONG 770 771 # only add attributes that exist in the server's LDAP schema 772 if self.has_valid_attrtype(_attrtype(attrdesc)): 773 774 # convert string values to ListType 775 if type(values) is types.StringType: 776 values = [values] 777 778 # do some syntax checking... 779 # IA5 strings may not contain umlaute etc. 780 if self.map_attrtype2ldapsyntaxoid(attrdesc) == '1.3.6.1.4.1.1466.115.121.1.26': 781 values = [ ia5string(value) for value in values ] 782 783 784 # rewrite the object class names in ,,values'' if attrdesc is ,,objectClass'' 785 if _attrtype(attrdesc).lower() == 'objectclass': 786 values = self._rewrite_objectclass_names(values) 787 788 # check, if we need objectClasses for this attribute that are not yet in the easyLDAP object cache 789 if _attrtype(attrdesc).lower() != 'objectclass' and self.attrtype_needs_objectclass(_attrtype(attrdesc)): 790 791 neededObjectClasses = self.map_attrtype2objectclasses(_attrtype(attrdesc)) 792 793 ok = [ oc for oc in self.get_used_objectclasses() if oc.lower() in neededObjectClasses ] 794 795 if not ok: 796 797 # if the objectClass is unequivocal, then add it automagically 798 if (len(neededObjectClasses) == 1): 799 self.add_objectclasses(neededObjectClasses[0]) 800 else: 801 # object needs extra objectClass 802 raise easyLDAP_exceptions.ATTRIBUTE_NEEDS_OBJECTCLASS 803 804 # if the attribute type is not set at all in the easyLDAP object cache 805 # we simply add it... 806 attrOID = self.map_attrtypes2oids(_attrtype(attrdesc))[0] 807 if attrOID not in self.get_used_attrtype_oids(): 808 self._ldap_cacheobject.set_cacheobject_attrdesc(self._rewrite_attrtype_names(attrdesc), []) 809 810 # but if the attribute type is already set, we have to bother for attribute options 811 # let's check first, if our combination attrtype;attropt exists 812 elif _attropt(attrdesc) and (_attropt(attrdesc) not in self.get_used_attroptions(_attrtype(attrdesc))): 813 self._ldap_cacheobject.set_cacheobject_attrdesc(self._rewrite_attrtype_names(attrdesc), []) 814 815 # if it is already there, we are fine. this part of code is not needed but we like it here... 816 else: 817 pass 818 819 if mod_type == easyLDAP_REPLACEATTR: 820 821 # map the given attrdesc to the attribute type and attribute option 822 # that is set in ldapObjectCache 823 # this can lead to a mapping of synonomous attributes 824 # (like in 'o' and 'organizationName' 825 # the mapping is performed by the attributes' unequivocal OID 826 for mappedAttrType in self.map_oid2attrtypes(self.map_attrtype2oid(attrdesc)[0]): 827 if mappedAttrType in self.get_used_attrtypes(): 828 break 829 830 # append the attribute description's option of attrdesc (if any) to the mappedAttributeType 831 mappedAttrDesc = _attrdesc(mappedAttrType,_attropt(attrdesc)) 832 833 # test if the attribute is a single-value attribute 834 if self.is_singlevalueattr(mappedAttrType) and len(values) > 1: 835 # attrdesc has single-value attrtype set 836 raise easyLDAP_exceptions.SINGLE_VALUE 837 838 else: 839 self._ldap_cacheobject.set_cacheobject_attrdesc(self._rewrite_attrtype_names(mappedAttrDesc), values) 840 841 if mod_type == easyLDAP_ADDATTR: 842 843 # test if the attribute is a single-value attribute 844 _set_attrdesc_values = self.get_attrdesc_values(attrdesc) 845 if self.is_singlevalueattr(_attrtype(attrdesc)) and len(_set_attrdesc_values ) >= 1: 846 847 # attribute type is has single-value flag set 848 # attrdesc has single-value attrtype set 849 raise easyLDAP_exceptions.SINGLE_VALUE 850 851 else: 852 for value in values: 853 854 # ignore 'attribute: value'-pairs that are already set in the easyLDAP object cache 855 # the python-ldap library would return an ldap.TYPE_OR_VALUE_EXISTS error. 856 if value not in _set_attrdesc_values: 857 _set_attrdesc_values = _set_attrdesc_values + [value] 858 self._ldap_cacheobject.set_cacheobject_attrdesc(attrdesc, _set_attrdesc_values) 859 860 return True 861 else: 862 # no such attribute 863 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE
864 865
866 - def del_attrdesc_values(self, attrdesc, value, ignore_case=False, by_oid=False):
867 """ 868 thisClass.del_attrdesc_value('myATTRDESC', 'myVALUE' ignore_case={True|FALSE}) 869 870 deletes the value 'myVALUE' from the LDAP attribute description 'myATTRDESC' in the 871 currently cached object. 872 873 If 'myVALUE' is the only value for 'myATTRDESC', the whole attribute 874 is removed from the cached easyLDAP object. 875 876 The method returns True on successful deletion. 877 """ 878 ### TODO: implement by_oid-flag 879 attrdesc = self._rewrite_attrtype_names(attrdesc) 880 if self.has_attrdesc_set(attrdesc): 881 882 try: 883 self._ldap_cacheobject.del_cacheobject_attrdesc_values(attrdesc, value, ignore_case=ignore_case) 884 885 ### TODO: this ValueError has to be replaced by something that works... 886 except ValueError: 887 # attribute description ist not set to this value 888 raise easyLDAP_exceptions.VALUE_NOT_SET 889 890 else: 891 # no such attribute description 892 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE_SET
893 894
895 - def del_attrdesc(self, attrdesc, by_oid=False):
896 """ 897 thisClass.del_attrdesc('myATTRDESC') 898 899 deletes the whole entry for attribute description 'myATTRDESC' from the 900 cached easyLDAP object. 901 902 The method returns True on successful deletion. 903 """ 904 ### TODO: implement by_oid-flag 905 attrdesc = self._rewrite_attrtype_names(attrdesc) 906 if self.has_attrdesc_set(attrdesc): 907 self._ldap_cacheobject.del_cacheobject_attrdesc(attrdesc) 908 909 else: 910 # no such attribute description 911 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE_SET
912 913
914 - def del_attrtype(self, attrtype, by_oid=False):
915 """ 916 thisClass.del_attrtype('myATTRTYPE') 917 918 deletes all entries for attribute type 'myATTRTYPE' 919 from the cached easyLDAP object. Be aware that all subentries 920 of the attribute type 'myATTRTYPE' will be removed (e.g. 921 all language options with one shot). 922 923 The method returns True on successful deletion. 924 """ 925 from easyLDAP_utils import _attrtype 926 927 # if by_oid is set we also remove all attribute type aliases 928 if by_oid: 929 attrtypes = self.get_attrtype_aliases(attrtype) 930 else: 931 attrtypes = [attrtype] 932 933 attrtypes = self._rewrite_attrtype_names(attrtypes) 934 935 self._ldap_cacheobject._temp_disable_cache_history() 936 937 # walk over the object's attribute description and see what needs to be removed 938 no_attrdesc_found = True 939 for this_attrtype in attrtypes: 940 if self.has_attrtype_set(this_attrtype): 941 for attrDesc in self.get_used_attrdescs(): 942 if _attrtype(this_attrtype) == _attrtype(attrDesc): 943 self._ldap_cacheobject.del_cacheobject_attrdesc(attrDesc) 944 no_attrdesc_found = False 945 946 if no_attrdesc_found: 947 # no such attribute 948 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE_SET 949 950 self._ldap_cacheobject._temp_enable_cache_history() 951 self._ldap_cacheobject._push_cache_history()
952 953
954 - def set_attrdesc(self, attrdesc, value):
955 """ 956 thisClass.set_attr('myLDAP_ATTRDESC', 957 'myVALUE'|['myVALUE1', 'myVALUE2', ...]) 958 959 is a wrapper for 960 961 thisClass._modify_attrdesc('myLDAP_ATTRDESC', 962 'myVALUE'|['myVALUE1', 'myVALUE2', ...], 963 easyLDAP_REPLACEATTR) 964 965 or 966 967 thisClass.del_attrdesc('myLDAP_ATTRIBUTE') 968 969 depending on the attribute description's context... 970 """ 971 # remove attribute 972 if (value == '') or (value == ['']): 973 if self.has_attrdesc_set(attrdesc): 974 return self.del_attrdesc(attrdesc) 975 976 # or add/replace attribute 977 else: 978 retval= self._modify_attrdesc(attrdesc, value, easyLDAP_REPLACEATTR) 979 if self.is_naming_attrdesc(attrdesc): 980 self.set_naming_attrdesc(attrdesc) 981 return retval
982 983
984 - def set_attrtype(self, attrtype_dict):
985 """ 986 thisClass.set_attr('myATTRDESCDICT) 987 988 helps copy+pasting a whole attribute type from one easyLDAP object 989 into another easyLDAP object. 990 991 Little HOWTO: 992 993 o connect to two easyLDAP objects. Let's call them ,,source" and ,,target". 994 o retrieve all attribute descriptions (including all subentries) of a certain 995 attribute type 'myATTRTYPE' from easyLDAPobject ,,source" with 996 997 my_attrtype = source.get_attrtype_values('myATTRTYPE') 998 999 o paste the retrieved data (a python dictionary) into easyLDAPobject 1000 ,,target" with 1001 1002 target.set_attrtype(my_attrtype) 1003 1004 o flush the easyLDAP object cache of ,,target" with 1005 1006 target.flush_cache() 1007 1008 If necessary objectClasses can be detected automagically they will be 1009 added silently. If not, the method returns a list of possible objectClasses 1010 that all provide the attribute type of your interest. 1011 1012 The structure of myATTRDESCDICT is expected to be an excerpt from 1013 a python-ldap object 1014 1015 { 1016 'attrtype;attropt1': ['val1','val2'], 1017 'attrtype;attropt2': [...], 1018 ... 1019 } 1020 1021 Keys of myATTRDESCDICT must alwasy have the same attribute type. 1022 The attribute options must be supported by LDAPv3 protocol. Attribute 1023 description values must be given as multi-valued or single-valued 1024 lists (depending on the attribute's properties in the server's schema). 1025 """ 1026 from easyLDAP_utils import _attrtype 1027 1028 try: 1029 # presume that the first attrDesc in attrtype_dict must have the same attribute type as 1030 # the following attribute description. if this is not the case the method will abort with an error 1031 attrType = _attrtype(attrtype_dict.keys()[0]) 1032 1033 # check the other attribute descriptions in this_attrtype_dict 1034 for attrDesc in self._rewrite_attrtype_names(this_attrtype_dict.keys()): 1035 if _attrtype(attrDesc) != attrType: 1036 # found invalid attribute description 1037 raise easyLDAP_exceptions.INVALID_ATTRIBUTETYPE 1038 1039 # remove all set attribute descriptions for this attribute type (and its attribute type aliases, OID based) 1040 for attrTypeAlias in self.get_attrtype_aliases(attrType): 1041 self.del_attrtype(attrTypeAlias) 1042 1043 retval = True 1044 # set new attribute descriptions as specified in this_attrtype_dict 1045 for attrDesc in attrtype_dict.keys(): 1046 retval = retval and self._modify_attrdesc(attrDesc, attrtype_dict[attrDesc], mod_type=easyLDAP_REPLACEATTR) 1047 1048 if not retval: 1049 raise easyLDAP_exceptions.SET_ATTRIBUTE_ERROR 1050 1051 except: 1052 # probably a type or index error... 1053 raise easyLDAP_exceptions.SET_ATTRIBUTE_ERROR
1054 1055
1056 - def add_attrdesc (self, attrdesc, value):
1057 """ 1058 thisClass.add_attrdesc('myLDAP_ATTRDESC', 1059 'myVALUE'|['myVALUE1', 'myVALUE2', ...]) 1060 1061 is a wrapper for 1062 1063 thisClass._modify_attrdesc('myLDAP_ATTRDESC', 1064 'myVALUE'|['myVALUE1', 'myVALUE2', ...], 1065 easyLDAP_ADDATTR) 1066 """ 1067 return self._modify_attrdesc(attrdesc, value, easyLDAP_ADDATTR)
1068
1069 - def push_cache_history(self):
1070 1071 self._ldap_cacheobject._push_cache_history()
1072
1073 - def show_cache(self):
1074 """ 1075 thisClass.show_cache() 1076 1077 will display the cached easyLDAP object just like the console 1078 tool 'ldapsearch' does... unset but possible attributes are not 1079 listed. 1080 """ 1081 self._ldap_cacheobject()
1082 1083
1084 - def clear_cache(self):
1086 1087
1088 - def new_object(self, objectclasses, attrdesc_dict):
1089 """ 1090 thisClass.new_object(['myOBJ_CLASS1', 'myOBJ_CLASS2'], 1091 { 1092 'myATTR1': ['myVAL1_1', 'myVAL1_2', ...], 1093 'myATTR2': ['myVAL2_1', 'myVAL2_2', ...], ' 1094 ... 1095 } 1096 ) 1097 1098 creates an empty object in the easyLDAP object cache. The object 1099 will only be uploaded to the LDAP directory, until the method 1100 thisClass.flush_cash() is evoked. 1101 1102 This action overwrites the current easyLDAP object cache and 1103 creates a new cache object if the used DN was not existent in 1104 the LDAP directory at the time of thisClass.__init__ ('myDN'). 1105 1106 This newly created object can be modified by several easyLDAP methods. 1107 Use dir(thisClass). 1108 1109 To view the contents of the new easyLDAP object cache, use 1110 thisClass.show(). 1111 """ 1112 self._new_object(self.get_object_dn()) 1113 if type (objectclasses) is types.StringType: 1114 objectclasses = [objectclasses] 1115 1116 self.add_objectclasses(objectclasses) 1117 1118 for myAttribute, myValue in attrdesc_dict.items (): 1119 if type(myValue) is types.StringType: 1120 myValue = [myValue] 1121 self._modify_attrdesc(myAttribute,myValue,easyLDAP_REPLACEATTR) 1122 1123 return True
1124
1125 - def undo(self):
1126 1127 self._ldap_cacheobject.undo()
1128
1129 - def redo(self):
1130 1131 self._ldap_cacheobject.redo()
1132
1133 - def set_userPassword(self, pw=None, HASH='CRYPT'):
1134 """ 1135 thisClass.set_userPassword('myUNIXPASSWORD','myHASH') 1136 1137 sets the user's unix password to 'myUNIXPASSWORD'. 1138 As encryption hash 'myHASH' you can additionally pass 1139 1140 CLEAR 1141 CRYPT 1142 1143 The default hash is 'CRYPT'. 1144 1145 If the easyLDAP object has the shadowAccount objectclass 1146 set, the attribute shadowLastChange will be set to the 1147 current date (in days since 1970). 1148 """ 1149 if pw is None: 1150 pw = genpasswd() 1151 1152 _do_encryption = { 1153 'CRYPT': 'crypthash(pw)', 1154 'CLEAR': 'pw', 1155 'SASL': '"{SASL}%s" % pw' 1156 } 1157 _known_crypt_methods = _do_encryption.keys() 1158 1159 if HASH in _known_crypt_methods: 1160 crypted_pw = eval (_do_encryption.get(HASH)) 1161 else: 1162 raise easyLDAP_exceptions.UNKNOWN_CRYPT_ALGORITHM 1163 1164 try: 1165 self.set_attrdesc('userPassword', crypted_pw) 1166 if self.has_objectclass_set('shadowAccount'): 1167 1168 self.set_attrdesc('shadowLastChange', str(days_since_1970()) ) 1169 1170 except: 1171 1172 raise easyLDAP_exceptions.FAILED_TO_SET_PASSWORD
1173 1174
1175 - def set_naming_attrdesc(self, naming_attrdesc):
1176 """ 1177 """ 1178 if self.has_attrdesc_set(naming_attrdesc): 1179 1180 used_naming_attrdesc = self.get_used_attrdescs_aliases(naming_attrdesc) 1181 self.set_object_dn('%s=%s,%s' % (used_naming_attrdesc,self.get_attrdesc_values(naming_attrdesc)[0],self.get_parent_dn())) 1182 1183 else: 1184 raise easyLDAP_exceptions.NO_SUCH_ATTRIBUTE_SET
1185 1186
1187 - def is_naming_attrdesc(self, naming_attrdesc):
1188 """ 1189 """ 1190 return self.get_object_dn().startswith('%s=' % _attrtype(naming_attrdesc))
1191 1192 1193 # for backwards compatibility 1194 easyLDAPobject = easyLDAP_object 1195 1196 ############################ 1197 # 1198 # main part only for testing 1199 # 1200 ############################ 1201 1202 if __name__=='__main__': 1203 pass 1204