2 from passlib.hash import ldap_salted_sha1 as lssha
3 from sfa.util.xrn import get_authority
5 from sfa.util.config import Config
8 import ldap.modlist as modlist
9 from sfa.util.sfalogging import logger
16 def __init__(self, config_file = '/etc/sfa/ldap_config.py'):
19 execfile(config_file, self.__dict__)
21 self.config_file = config_file
22 # path to configuration data
23 self.config_path = os.path.dirname(config_file)
25 raise IOError, "Could not find or load the configuration file: %s" \
30 """ Set admin login and server configuration variables."""
33 #Iotlab PROD LDAP parameters
35 ldap_config = LdapConfig()
36 self.config = ldap_config
37 self.ldapHost = ldap_config.LDAP_IP_ADDRESS
38 self.ldapPeopleDN = ldap_config.LDAP_PEOPLE_DN
39 self.ldapGroupDN = ldap_config.LDAP_GROUP_DN
40 self.ldapAdminDN = ldap_config.LDAP_WEB_DN
41 self.ldapAdminPassword = ldap_config.LDAP_WEB_PASSWORD
44 self.ldapPort = ldap.PORT
45 self.ldapVersion = ldap.VERSION3
46 self.ldapSearchScope = ldap.SCOPE_SUBTREE
49 def connect(self, bind=True):
51 Enables connection to the LDAP server.
52 :param bind : Set the bind parameter to True if a bind is needed
53 (for add/modify/delete operations).
54 Set to False otherwise.
57 :return: dictionary with status of the connection. True if Successful,
58 False if not and in this case the error message( {'bool', 'message'} )
63 self.ldapserv = ldap.open(self.ldapHost)
64 except ldap.LDAPError, error:
65 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
66 return {'bool': False, 'message': error}
68 return {'bool' : False, 'message' : error }
69 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
71 # Bind with authentification
80 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
83 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
84 :return: dictionary with the bind status. True if Successful,
85 False if not and in this case the error message( {'bool', 'message'} )
90 # Opens a connection after a call to ldap.open in connect:
91 self.ldapserv = ldap.initialize("ldap://" + self.ldapHost)
93 # Bind/authenticate with a user with apropriate
94 #rights to add objects
95 self.ldapserv.simple_bind_s(self.ldapAdminDN, \
96 self.ldapAdminPassword)
98 except ldap.LDAPError, error:
99 return {'bool': False, 'message': error}
101 return {'bool': True}
104 """ Close the LDAP connection.
106 Can throw an exception if the unbinding fails.
110 self.ldapserv.unbind_s()
111 except ldap.LDAPError, error:
112 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
113 return {'bool': False, 'message': error}
116 return {'bool' : False, 'message' : error }
117 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
119 class LoginPassword():
122 Class to handle login and password generation, using custom login generation
129 Sets password and login maximum length, and defines the characters
130 that can be found in a random generated password.
131 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
134 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
136 self.login_max_length = 8
137 self.length_password = 8
138 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
139 self.chars_password = ['!', '$', '(',')', '*', '+', ',', '-', '.',
140 '0', '1', '2', '3', '4', '5', '6', '7', '8',
141 '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
142 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
143 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
144 '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
145 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
146 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
149 self.chars_password = [ '!', '$', '(',')', '*', '+', ',', '-', '.', \
150 '0', '1', '2', '3', '4', '5', '6', '7', '8', \
151 '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', \
152 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', \
153 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', \
154 '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', \
155 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p' ,'q', \
156 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', \
161 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
164 def clean_user_names(record):
167 Removes special characters such as
168 '-', '_' , '[', ']' and ' ' from the first name and last name.
170 :param record: user's record
172 :return: lower_first_name and lower_last_name if they were found
173 in the user's record. Return None, none otherwise.
174 :rtype: string, string or None, None.
177 if 'first_name' in record and 'last_name' in record:
178 #Remove all special characters from first_name/last name
179 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
180 lower_first_name = record['first_name'].replace('-', '')\
181 .replace('_', '').replace('[', '')\
182 .replace(']', '').replace(' ', '')\
184 lower_last_name = record['last_name'].replace('-', '')\
185 .replace('_', '').replace('[', '')\
186 .replace(']', '').replace(' ', '')\
189 lower_first_name = record['first_name'].replace('-','')\
190 .replace('_','').replace('[','')\
191 .replace(']','').replace(' ','')\
193 lower_last_name = record['last_name'].replace('-','')\
194 .replace('_','').replace('[','')\
195 .replace(']','').replace(' ','')\
197 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
198 return lower_first_name, lower_last_name
203 def extract_name_from_email(record):
205 When there is no valid first name and last name in the record,
206 the email is used to generate the login. Here, we assume the email
207 is firstname.lastname@something.smthg. The first name and last names
208 are extracted from the email, special charcaters are removed and
209 they are changed into lower case.
210 :param record: user's data
212 :return: the first name and last name taken from the user's email.
213 lower_first_name, lower_last_name.
214 :rtype: string, string
217 email = record['email']
218 email = email.split('@')[0].lower()
219 lower_first_name = None
220 lower_last_name = None
221 #Assume there is first name and last name in email
222 #if there is a separator
223 separator_list = ['.', '_', '-']
224 for sep in separator_list:
226 mail = email.split(sep)
227 lower_first_name = mail[0]
228 lower_last_name = mail[1]
231 #Otherwise just take the part before the @ as the
232 #lower_first_name and lower_last_name
233 if lower_first_name is None:
234 lower_first_name = email
235 lower_last_name = email
237 return lower_first_name, lower_last_name
239 def get_user_firstname_lastname(self, record):
240 """Get the user first name and last name from the information
241 we have in the record.
242 :param record: user's information
244 :return: the user's first name and last name.
245 ..seealso: clean_user_names
246 ..seealso: extract_name_from_email
248 lower_first_name, lower_last_name = self.clean_user_names(record)
250 #No first name and last name check email
251 if lower_first_name is None and lower_last_name is None:
253 lower_first_name, lower_last_name = \
254 self.extract_name_from_email(record)
256 return lower_first_name, lower_last_name
259 def choose_sets_chars_for_login(self, lower_first_name, lower_last_name):
261 Algorithm to select sets of characters from the first name and
262 last name, depending on the lenght of the last name and the
263 maximum login length which in our case is set to 8 charachetrs.
264 :param lower_first_name: user's first name in lower case.
265 :param lower_last_name: usr's last name in lower case.
266 :return: user's login
269 length_last_name = len(lower_last_name)
270 self.login_max_length = 8
272 #Try generating a unique login based on first name and last name
274 if length_last_name >= self.login_max_length :
275 login = lower_last_name[0:self.login_max_length]
277 logger.debug("login : %s index : %s" %(login, index))
278 elif length_last_name >= 4 :
279 login = lower_last_name
281 logger.debug("login : %s index : %s" %(login, index))
282 elif length_last_name == 3 :
283 login = lower_first_name[0:1] + lower_last_name
285 logger.debug("login : %s index : %s" %(login, index))
286 elif length_last_name == 2:
287 if len ( lower_first_name) >=2:
288 login = lower_first_name[0:2] + lower_last_name
290 logger.debug("login : %s index : %s" %(login, index))
292 logger.error("LoginException : \
293 Generation login error with \
294 minimum four characters")
297 logger.error("LDAP LdapGenerateUniqueLogin failed : \
298 impossible to generate unique login for %s %s" \
299 %(lower_first_name,lower_last_name))
304 def generate_password(self):
306 """Generate a password upon adding a new user in LDAP Directory
307 (8 characters length). The generated password is composed of characters
308 from the charsPassword list
309 :return: the randomly generated password
315 length = len(self.chars_password)
316 for index in range(self.length_password):
317 char_index = random.randint(0, length-1)
318 password += self.chars_password[char_index]
323 def encrypt_password(password):
324 """ Use passlib library to make a RFC2307 LDAP encrypted password
325 salt size = 8, use sha-1 algorithm.
326 :param password: password not encrypted.
327 :type password: string
328 :return: Returns encrypted password.
331 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
332 #Keep consistency with Java Iotlab's LDAP API
334 #Keep consistency with Java Senslab's LDAP API
335 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
336 #RFC2307SSHAPasswordEncryptor so set the salt size to 8 bytes
337 return lssha.encrypt(password, salt_size = 8)
343 logger.setLevelDebug()
348 self.login_pwd = LoginPassword()
349 self.authname = config.SFA_REGISTRY_ROOT_AUTH
351 self.conn = ldap_co()
352 self.ldapUserQuotaNFS = self.conn.config.LDAP_USER_QUOTA_NFS
353 self.ldapUserUidNumberMin = self.conn.config.LDAP_USER_UID_NUMBER_MIN
354 self.ldapUserGidNumber = self.conn.config.LDAP_USER_GID_NUMBER
355 self.ldapUserHomePath = self.conn.config.LDAP_USER_HOME_PATH
357 self.baseDN = self.conn.ldapPeopleDN
361 self.ldapShell = '/bin/bash'
365 def LdapGenerateUniqueLogin(self, record):
367 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
369 Generate login for adding a new user in LDAP Directory
370 (four characters minimum length). Get proper last name and
371 first name so that the user's login can be generated.
374 Generate login for adding a new user in LDAP Directory
375 (four characters minimum length). Get proper last name and
376 first name so that the user's login can be generated.
377 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
378 :param record: Record must contain first_name and last_name.
380 :return: the generated login for the user described with record if the
381 login generation is successful, None if it fails.
382 :rtype: string or None
383 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
386 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
388 #For compatibility with other ldap func
389 if 'mail' in record and 'email' not in record:
390 record['email'] = record['mail']
392 lower_first_name, lower_last_name = \
393 self.login_pwd.get_user_firstname_lastname(record)
396 index, login = self.login_pwd.choose_sets_chars_for_login( \
399 login_filter = '(uid=' + login + ')'
402 #Check if login already in use
404 while (len(self.LdapSearch(login_filter, get_attrs)) is not 0 ):
408 logger.error("LoginException : Generation login error \
409 with minimum four characters")
413 lower_first_name[0:index] + \
414 lower_last_name[0:self.login_pwd.login_max_length-index]
415 login_filter = '(uid='+ login+ ')'
417 print "lower_first_name - lower_last_name too short"
419 logger.debug("LDAP.API \t LdapGenerateUniqueLogin login %s"%(login))
422 except ldap.LDAPError, error :
423 logger.log_exc("LDAP LdapGenerateUniqueLogin Error %s" %error)
427 def find_max_uidNumber(self):
429 """Find the LDAP max uidNumber (POSIX uid attribute) .
430 Used when adding a new user in LDAP Directory
431 :return: max uidNumber + 1
434 #First, get all the users in the LDAP
435 get_attrs = "(uidNumber=*)"
436 login_filter = ['uidNumber']
438 result_data = self.LdapSearch(get_attrs, login_filter)
439 #It there is no user in LDAP yet, First LDAP user
440 if result_data == []:
441 max_uidnumber = self.ldapUserUidNumberMin
442 #Otherwise, get the highest uidNumber
445 uidNumberList = [int(r[1]['uidNumber'][0])for r in result_data ]
446 logger.debug("LDAPapi.py \tfind_max_uidNumber \
447 uidNumberList %s " %(uidNumberList))
448 max_uidnumber = max(uidNumberList) + 1
450 return str(max_uidnumber)
453 def get_ssh_pkey(self, record):
454 """TODO ; Get ssh public key from sfa record
455 To be filled by N. Turro ? or using GID pl way?
461 #TODO Handle OR filtering in the ldap query when
462 #dealing with a list of records instead of doing a for loop in GetPersons
463 def make_ldap_filters_from_record( record=None):
465 Helper function to make LDAP filter requests out of SFA records.
466 :param record: user's sfa record. Should contain first_name,last_name,
467 email or mail, and if the record is enabled or not. If the dict
468 record does not have all of these, must at least contain the user's
471 :return: LDAP request
477 if 'first_name' in record and 'last_name' in record:
478 req_ldapdict['cn'] = str(record['first_name'])+" "\
479 + str(record['last_name'])
480 if 'email' in record :
481 req_ldapdict['mail'] = record['email']
483 req_ldapdict['mail'] = record['mail']
484 if 'enabled' in record:
485 if record['enabled'] == True :
486 req_ldapdict['shadowExpire'] = '-1'
488 req_ldapdict['shadowExpire'] = '0'
490 #Hrn should not be part of the filter because the hrn
491 #presented by a certificate of a SFA user not imported in
492 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
493 #Iotlab does not include the iotlab login in it
494 #Plus, the SFA user may already have an account with iotlab
496 #Senslab does not include the senslab login in it
497 #Plus, the SFA user may already have an account with senslab
498 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
499 #using another login.
503 logger.debug("\r\n \t LDAP.PY make_ldap_filters_from_record \
504 record %s req_ldapdict %s" \
505 %(record, req_ldapdict))
507 for k in req_ldapdict:
508 req_ldap += '('+ str(k)+ '=' + str(req_ldapdict[k]) + ')'
509 if len(req_ldapdict.keys()) >1 :
510 req_ldap = req_ldap[:0]+"(&"+req_ldap[0:]
512 req_ldap = req_ldap[:(size-1)] +')'+ req_ldap[(size-1):]
518 def make_ldap_attributes_from_record(self, record):
519 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
520 """When adding a new user to Iotlab's LDAP, creates an attributes
522 """When adding a new user to Senslab's LDAP, creates an attributes
523 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
524 dictionnary from the SFA record understandable by LDAP.
525 Generates the user's LDAP login.
526 User is automatically validated (account enabled) and described
527 as a SFA USER FROM OUTSIDE SENSLAB'.
528 :param record: must contain the following keys and values:
529 first_name, last_name, mail, pkey (ssh key).
532 :return: dictionary of attributes using LDAP data structure
539 attrs['objectClass'] = ["top", "person", "inetOrgPerson", \
540 "organizationalPerson", "posixAccount", \
541 "shadowAccount", "systemQuotas", \
545 attrs['uid'] = self.LdapGenerateUniqueLogin(record)
547 attrs['givenName'] = str(record['first_name']).lower().capitalize()
548 attrs['sn'] = str(record['last_name']).lower().capitalize()
549 attrs['cn'] = attrs['givenName'] + ' ' + attrs['sn']
550 attrs['gecos'] = attrs['givenName'] + ' ' + attrs['sn']
553 attrs['givenName'] = attrs['uid']
554 attrs['sn'] = attrs['uid']
555 attrs['cn'] = attrs['uid']
556 attrs['gecos'] = attrs['uid']
559 attrs['quota'] = self.ldapUserQuotaNFS
560 attrs['homeDirectory'] = self.ldapUserHomePath + attrs['uid']
561 attrs['loginShell'] = self.ldapShell
562 attrs['gidNumber'] = self.ldapUserGidNumber
563 attrs['uidNumber'] = self.find_max_uidNumber()
564 attrs['mail'] = record['mail'].lower()
566 attrs['sshPublicKey'] = record['pkey']
568 attrs['sshPublicKey'] = self.get_ssh_pkey(record)
571 #Password is automatically generated because SFA user don't go
572 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
573 #through the Iotlab website used to register new users,
574 #There is no place in SFA where users can enter such information
576 #If the user wants to set his own password , he must go to the Iotlab
578 #through the Senslab website used to register new users,
579 #There is no place in SFA where users can enter such information
581 #If the user wants to set his own password , he must go to the Senslab
582 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
584 password = self.login_pwd.generate_password()
585 attrs['userPassword'] = self.login_pwd.encrypt_password(password)
587 #Account automatically validated (no mail request to admins)
588 #Set to 0 to disable the account, -1 to enable it,
589 attrs['shadowExpire'] = '-1'
591 #Motivation field in Iotlab
592 attrs['description'] = 'SFA USER FROM OUTSIDE SENSLAB'
594 attrs['ou'] = 'SFA' #Optional: organizational unit
595 #No info about those here:
596 attrs['l'] = 'To be defined'#Optional: Locality.
597 attrs['st'] = 'To be defined' #Optional: state or province (country).
603 def LdapAddUser(self, record) :
604 """Add SFA user to LDAP if it is not in LDAP yet.
605 :param record: dictionnary with the user's data.
607 :return: a dictionary with the status (Fail= False, Success= True)
608 and the uid of the newly added user if successful, or the error
609 meassage it is not. Dict has keys bool and message in case of failure,
610 and bool uid in case of success.
613 ..seealso: make_ldap_filters_from_record
616 logger.debug(" \r\n \t LDAP LdapAddUser \r\n\r\n ================\r\n ")
617 user_ldap_attrs = self.make_ldap_attributes_from_record(record)
620 #Check if user already in LDAP wih email, first name and last name
621 filter_by = self.make_ldap_filters_from_record(user_ldap_attrs)
622 user_exist = self.LdapSearch(filter_by)
624 logger.warning(" \r\n \t LDAP LdapAddUser user %s %s \
625 already exists" %(user_ldap_attrs['sn'], \
626 user_ldap_attrs['mail']))
627 return {'bool': False}
630 result = self.conn.connect()
634 # A dict to help build the "body" of the object
636 logger.debug(" \r\n \t LDAP LdapAddUser attrs %s " %user_ldap_attrs)
638 # The dn of our new entry/object
639 dn = 'uid=' + user_ldap_attrs['uid'] + "," + self.baseDN
642 ldif = modlist.addModlist(user_ldap_attrs)
643 logger.debug("LDAPapi.py add attrs %s \r\n ldif %s"\
644 %(user_ldap_attrs, ldif) )
645 self.conn.ldapserv.add_s(dn, ldif)
647 logger.info("Adding user %s login %s in LDAP" \
648 %(user_ldap_attrs['cn'] , user_ldap_attrs['uid']))
651 except ldap.LDAPError, error:
652 logger.log_exc("LDAP Add Error %s" %error)
653 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
654 return {'bool': False, 'message': error}
656 return {'bool' : False, 'message' : error }
657 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
660 return {'bool': True, 'uid':user_ldap_attrs['uid']}
665 def LdapDelete(self, person_dn):
667 Deletes a person in LDAP. Uses the dn of the user.
668 :param person_dn: user's ldap dn.
669 :type person_dn: string
670 :return: dictionary with bool True if successful, bool False
671 and the error if not.
675 result = self.conn.connect()
678 self.conn.ldapserv.delete_s(person_dn)
680 return {'bool': True}
682 except ldap.LDAPError, error:
683 logger.log_exc("LDAP Delete Error %s" %error)
684 return {'bool': False, 'message': error}
687 def LdapDeleteUser(self, record_filter):
689 Deletes a SFA person in LDAP, based on the user's hrn.
690 :param record_filter: Filter to find the user to be deleted. Must
691 contain at least the user's email.
692 :type record_filter: dict
693 :return: dict with bool True if successful, bool False and error message
696 ..seealso: LdapFindUser docstring for more info on record filter.
697 ..seealso: LdapDelete for user deletion
699 #Find uid of the person
700 person = self.LdapFindUser(record_filter, [])
701 logger.debug("LDAPapi.py \t LdapDeleteUser record %s person %s" \
702 %(record_filter, person))
705 dn = 'uid=' + person['uid'] + "," + self.baseDN
707 return {'bool': False}
709 result = self.LdapDelete(dn)
713 def LdapModify(self, dn, old_attributes_dict, new_attributes_dict):
714 """ Modifies a LDAP entry, replaces user's old attributes with
716 :param dn: user's absolute name in the LDAP hierarchy.
717 :param old_attributes_dict: old user's attributes. Keys must match
718 the ones used in the LDAP model.
719 :param new_attributes_dict: new user's attributes. Keys must match
720 the ones used in the LDAP model.
722 :type old_attributes_dict: dict
723 :type new_attributes_dict: dict
724 :return: dict bool True if Successful, bool False if not.
728 ldif = modlist.modifyModlist(old_attributes_dict, new_attributes_dict)
729 # Connect and bind/authenticate
730 result = self.conn.connect()
733 self.conn.ldapserv.modify_s(dn, ldif)
735 return {'bool' : True }
736 except ldap.LDAPError, error:
737 logger.log_exc("LDAP LdapModify Error %s" %error)
738 return {'bool' : False }
741 def LdapModifyUser(self, user_record, new_attributes_dict):
743 Gets the record from one user based on the user sfa record
744 and changes the attributes according to the specified new_attributes.
745 Do not use this if we need to modify the uid. Use a ModRDN
746 #operation instead ( modify relative DN )
747 :param user_record: sfa user record.
748 :param new_attributes_dict: new user attributes, keys must be the
749 same as the LDAP model.
750 :type user_record: dict
751 :type new_attributes_dict: dict
752 :return: bool True if successful, bool False if not.
754 ..seealso: make_ldap_filters_from_record for info on what is mandatory
756 ..seealso: make_ldap_attributes_from_record for the LDAP objectclass.
758 if user_record is None:
759 logger.error("LDAP \t LdapModifyUser Need user record ")
760 return {'bool': False}
762 #Get all the attributes of the user_uid_login
763 #person = self.LdapFindUser(record_filter,[])
764 req_ldap = self.make_ldap_filters_from_record(user_record)
765 person_list = self.LdapSearch(req_ldap, [])
766 logger.debug("LDAPapi.py \t LdapModifyUser person_list : %s" \
768 if person_list and len(person_list) > 1 :
769 logger.error("LDAP \t LdapModifyUser Too many users returned")
770 return {'bool': False}
771 if person_list is None :
772 logger.error("LDAP \t LdapModifyUser User %s doesn't exist "\
774 return {'bool': False}
776 # The dn of our existing entry/object
777 #One result only from ldapSearch
778 person = person_list[0][1]
779 dn = 'uid=' + person['uid'][0] + "," + self.baseDN
781 if new_attributes_dict:
783 for k in new_attributes_dict:
788 logger.debug(" LDAPapi.py \t LdapModifyUser new_attributes %s"\
789 %( new_attributes_dict))
790 result = self.LdapModify(dn, old, new_attributes_dict)
793 logger.error("LDAP \t LdapModifyUser No new attributes given. ")
794 return {'bool': False}
799 def LdapMarkUserAsDeleted(self, record):
801 Sets shadowExpire to 0, disabling the user in LDAP.
802 Calls LdapModifyUser to change the shadowExpire of the user.
803 :param record: the record of the user who has to be disabled.
805 :return: bool True if successful or bool False if not
807 ..seealso: LdapModifyUser
812 new_attrs['shadowExpire'] = '0'
813 logger.debug(" LDAPapi.py \t LdapMarkUserAsDeleted ")
814 ret = self.LdapModifyUser(record, new_attrs)
818 def LdapResetPassword(self, record):
820 Resets password for the user whose record is the parameter and changes
821 the corresponding entry in the LDAP.
824 password = self.login_pwd.generate_password()
826 attrs['userPassword'] = self.login_pwd.encrypt_password(password)
827 logger.debug("LDAP LdapResetPassword encrypt_password %s"\
828 %(attrs['userPassword']))
829 result = self.LdapModifyUser(record, attrs)
833 def LdapSearch (self, req_ldap = None, expected_fields = None ):
835 Used to search directly in LDAP, by using ldap filters and
837 When req_ldap is None, returns all the entries in the LDAP.
840 result = self.conn.connect(bind = False)
841 if (result['bool']) :
843 return_fields_list = []
844 if expected_fields == None :
845 return_fields_list = ['mail', 'givenName', 'sn', 'uid', \
846 'sshPublicKey', 'shadowExpire']
848 return_fields_list = expected_fields
849 #No specifc request specified, get the whole LDAP
853 logger.debug("LDAP.PY \t LdapSearch req_ldap %s \
854 return_fields_list %s" \
855 %(req_ldap, return_fields_list))
858 msg_id = self.conn.ldapserv.search(
859 self.baseDN,ldap.SCOPE_SUBTREE,\
860 req_ldap, return_fields_list)
861 #Get all the results matching the search from ldap in one
863 result_type, result_data = \
864 self.conn.ldapserv.result(msg_id, 1)
868 logger.debug("LDAP.PY \t LdapSearch result_data %s"\
873 except ldap.LDAPError, error :
874 logger.log_exc("LDAP LdapSearch Error %s" %error)
878 logger.error("LDAP.PY \t Connection Failed" )
882 def _process_ldap_info_for_all_users(self, result_data):
884 Process the data of all enabled users in LDAP.
885 :param result_data: Contains information of all enabled users in LDAP
886 and is coming from LdapSearch.
887 :param result_data: list
888 ..seealso: LdapSearch
891 logger.debug(" LDAP.py _process_ldap_info_for_all_users result_data %s " \
893 for ldapentry in result_data:
894 logger.debug(" LDAP.py _process_ldap_info_for_all_users ldapentry name : %s " \
895 %(ldapentry[1]['uid'][0]))
896 tmpname = ldapentry[1]['uid'][0]
897 hrn = self.authname + "." + tmpname
899 tmpemail = ldapentry[1]['mail'][0]
900 if ldapentry[1]['mail'][0] == "unknown":
907 'pkey': ldapentry[1]['sshPublicKey'][0],
908 #'uid': ldapentry[1]['uid'][0],
911 #'email': ldapentry[1]['mail'][0],
912 'first_name': ldapentry[1]['givenName'][0],
913 'last_name': ldapentry[1]['sn'][0],
916 'authority': self.authname,
917 'peer_authority': '',
921 except KeyError, error:
922 logger.log_exc("LDAPapi.PY \t LdapFindUser EXCEPTION %s" \
926 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
930 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
932 def _process_ldap_info_for_one_user(self, record, result_data):
934 Put the user's ldap data into shape. Only deals with one user
935 record and one user data from ldap.
936 :param record: user record
937 :param result_data: Raw ldap data coming from LdapSearch
938 :return: user's data dict with 'type','pkey','uid', 'email',
939 'first_name' 'last_name''serial''authority''peer_authority'
942 :type result_data: list
945 #One entry only in the ldap data because we used a filter
946 #to find one user only
947 ldapentry = result_data[0][1]
948 logger.debug("LDAP.PY \t LdapFindUser ldapentry %s" %(ldapentry))
949 tmpname = ldapentry['uid'][0]
951 tmpemail = ldapentry['mail'][0]
952 if ldapentry['mail'][0] == "unknown":
956 peer_authority = None
959 parent_hrn = get_authority(hrn)
960 if parent_hrn != self.authname:
961 peer_authority = parent_hrn
962 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
963 #In case the user was not imported from Iotlab LDAP
964 #but from another federated site, has an account in
965 #iotlab but currently using his hrn from federated site
967 #In case the user was not imported from Senslab LDAP
968 #but from another federated site, has an account in
969 #senslab but currently using his hrn from federated site
970 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
971 #then the login is different from the one found in its hrn
972 if tmpname != hrn.split('.')[1]:
981 'pkey': ldapentry['sshPublicKey'],
982 #'uid': ldapentry[1]['uid'][0],
985 #'email': ldapentry[1]['mail'][0],
986 'first_name': ldapentry['givenName'][0],
987 'last_name': ldapentry['sn'][0],
990 'authority': parent_hrn,
991 'peer_authority': peer_authority,
998 def LdapFindUser(self, record=None, is_user_enabled=None,
999 expected_fields=None):
1001 Search a SFA user with a hrn. User should be already registered
1002 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
1006 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
1007 :param record: sfa user's record. Should contain first_name,last_name,
1008 email or mail. If no record is provided, returns all the users found
1011 <<<<<<< HEAD:sfa/iotlab/LDAPapi.py
1012 :param is_user_enabled: is the user's iotlab account already valid.
1014 :param is_user_enabled: is the user's senslab account already valid.
1015 >>>>>>> 3fe7429... SA:sfa/senslab/LDAPapi.py
1016 :type is_user_enabled: Boolean.
1017 :return: LDAP entries from ldap matching the filter provided. Returns
1018 a single entry if one filter has been given and a list of
1020 :rtype: dict or list
1024 custom_record['enabled'] = is_user_enabled
1026 custom_record.update(record)
1029 req_ldap = self.make_ldap_filters_from_record(custom_record)
1030 return_fields_list = []
1031 if expected_fields == None :
1032 return_fields_list = ['mail', 'givenName', 'sn', 'uid', \
1035 return_fields_list = expected_fields
1037 result_data = self.LdapSearch(req_ldap, return_fields_list )
1038 logger.debug("LDAP.PY \t LdapFindUser result_data %s" %(result_data))
1040 if len(result_data) is 0:
1042 #Asked for a specific user
1043 if record is not None:
1044 results = self._process_ldap_info_for_one_user(record, result_data)
1047 #Asked for all users in ldap
1048 results = self._process_ldap_info_for_all_users(result_data)