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.
56 :return: dictionary with status of the connection. True if Successful,
57 False if not and in this case the error message( {'bool', 'message'} )
61 self.ldapserv = ldap.open(self.ldapHost)
62 except ldap.LDAPError, error:
63 return {'bool' : False, 'message' : error }
65 # Bind with authentification
74 :return: dictionary with the bind status. True if Successful,
75 False if not and in this case the error message( {'bool', 'message'} )
80 # Opens a connection after a call to ldap.open in connect:
81 self.ldapserv = ldap.initialize("ldap://" + self.ldapHost)
83 # Bind/authenticate with a user with apropriate
84 #rights to add objects
85 self.ldapserv.simple_bind_s(self.ldapAdminDN, \
86 self.ldapAdminPassword)
88 except ldap.LDAPError, error:
89 return {'bool' : False, 'message' : error }
94 """ Close the LDAP connection.
95 Can throw an exception if the unbinding fails.
98 self.ldapserv.unbind_s()
99 except ldap.LDAPError, error:
100 return {'bool' : False, 'message' : error }
102 class LoginPassword():
104 Class to handle login and password generation, using custom login generation
109 Sets password and login maximum length, and defines the characters
110 that can be found in a random generated password.
112 self.login_max_length = 8
113 self.length_password = 8
114 self.chars_password = [ '!', '$', '(',')', '*', '+', ',', '-', '.', \
115 '0', '1', '2', '3', '4', '5', '6', '7', '8', \
116 '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', \
117 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', \
118 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', \
119 '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', \
120 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p' ,'q', \
121 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', \
128 def clean_user_names(record):
130 Removes special characters such as
131 '-', '_' , '[', ']' and ' ' from the first name and last name.
132 :param record: user's record
134 :return: lower_first_name and lower_last_name if they were found
135 in the user's record. Return None, none otherwise.
136 :rtype: string, string or None, None.
138 if 'first_name' in record and 'last_name' in record:
139 #Remove all special characters from first_name/last name
140 lower_first_name = record['first_name'].replace('-','')\
141 .replace('_','').replace('[','')\
142 .replace(']','').replace(' ','')\
144 lower_last_name = record['last_name'].replace('-','')\
145 .replace('_','').replace('[','')\
146 .replace(']','').replace(' ','')\
148 return lower_first_name, lower_last_name
153 def extract_name_from_email(record):
155 When there is no valid first name and last name in the record,
156 the email is used to generate the login. Here, we assume the email
157 is firstname.lastname@something.smthg. The first name and last names
158 are extracted from the email, special charcaters are removed and
159 they are changed into lower case.
160 :param record: user's data
162 :return: the first name and last name taken from the user's email.
163 lower_first_name, lower_last_name.
164 :rtype: string, string
167 email = record['email']
168 email = email.split('@')[0].lower()
169 lower_first_name = None
170 lower_last_name = None
171 #Assume there is first name and last name in email
172 #if there is a separator
173 separator_list = ['.', '_', '-']
174 for sep in separator_list:
176 mail = email.split(sep)
177 lower_first_name = mail[0]
178 lower_last_name = mail[1]
181 #Otherwise just take the part before the @ as the
182 #lower_first_name and lower_last_name
183 if lower_first_name is None:
184 lower_first_name = email
185 lower_last_name = email
187 return lower_first_name, lower_last_name
189 def get_user_firstname_lastname(self, record):
190 """Get the user first name and last name from the information
191 we have in the record.
192 :param record: user's information
194 :return: the user's first name and last name.
195 ..seealso: clean_user_names
196 ..seealso: extract_name_from_email
198 lower_first_name, lower_last_name = self.clean_user_names(record)
200 #No first name and last name check email
201 if lower_first_name is None and lower_last_name is None:
203 lower_first_name, lower_last_name = \
204 self.extract_name_from_email(record)
206 return lower_first_name, lower_last_name
209 def choose_sets_chars_for_login(self, lower_first_name, lower_last_name):
211 Algorithm to select sets of characters from the first name and
212 last name, depending on the lenght of the last name and the
213 maximum login length which in our case is set to 8 charachetrs.
214 :param lower_first_name: user's first name in lower case.
215 :param lower_last_name: usr's last name in lower case.
216 :return: user's login
219 length_last_name = len(lower_last_name)
220 self.login_max_length = 8
222 #Try generating a unique login based on first name and last name
224 if length_last_name >= self.login_max_length :
225 login = lower_last_name[0:self.login_max_length]
227 logger.debug("login : %s index : %s" %(login, index))
228 elif length_last_name >= 4 :
229 login = lower_last_name
231 logger.debug("login : %s index : %s" %(login, index))
232 elif length_last_name == 3 :
233 login = lower_first_name[0:1] + lower_last_name
235 logger.debug("login : %s index : %s" %(login, index))
236 elif length_last_name == 2:
237 if len ( lower_first_name) >=2:
238 login = lower_first_name[0:2] + lower_last_name
240 logger.debug("login : %s index : %s" %(login, index))
242 logger.error("LoginException : \
243 Generation login error with \
244 minimum four characters")
247 logger.error("LDAP LdapGenerateUniqueLogin failed : \
248 impossible to generate unique login for %s %s" \
249 %(lower_first_name,lower_last_name))
254 def generate_password(self):
256 """Generate a password upon adding a new user in LDAP Directory
257 (8 characters length). The generated password is composed of characters
258 from the charsPassword list
259 :return: the randomly generated password
265 length = len(self.chars_password)
266 for index in range(self.length_password):
267 char_index = random.randint(0, length-1)
268 password += self.chars_password[char_index]
273 def encrypt_password(password):
274 """ Use passlib library to make a RFC2307 LDAP encrypted password
275 salt size = 8, use sha-1 algorithm.
276 :param password: password not encrypted.
277 :type password: string
278 :return: Returns encrypted password.
281 #Keep consistency with Java Iotlab's LDAP API
282 #RFC2307SSHAPasswordEncryptor so set the salt size to 8 bytes
283 return lssha.encrypt(password, salt_size = 8)
289 logger.setLevelDebug()
294 self.login_pwd = LoginPassword()
295 self.authname = config.SFA_REGISTRY_ROOT_AUTH
297 self.conn = ldap_co()
298 self.ldapUserQuotaNFS = self.conn.config.LDAP_USER_QUOTA_NFS
299 self.ldapUserUidNumberMin = self.conn.config.LDAP_USER_UID_NUMBER_MIN
300 self.ldapUserGidNumber = self.conn.config.LDAP_USER_GID_NUMBER
301 self.ldapUserHomePath = self.conn.config.LDAP_USER_HOME_PATH
303 self.baseDN = self.conn.ldapPeopleDN
307 self.ldapShell = '/bin/bash'
311 def LdapGenerateUniqueLogin(self, record):
313 Generate login for adding a new user in LDAP Directory
314 (four characters minimum length). Get proper last name and
315 first name so that the user's login can be generated.
316 :param record: Record must contain first_name and last_name.
318 :return: the generated login for the user described with record if the
319 login generation is successful, None if it fails.
320 :rtype: string or None
322 #For compatibility with other ldap func
323 if 'mail' in record and 'email' not in record:
324 record['email'] = record['mail']
326 lower_first_name, lower_last_name = \
327 self.login_pwd.get_user_firstname_lastname(record)
330 index, login = self.login_pwd.choose_sets_chars_for_login( \
333 login_filter = '(uid=' + login + ')'
336 #Check if login already in use
338 while (len(self.LdapSearch(login_filter, get_attrs)) is not 0 ):
342 logger.error("LoginException : Generation login error \
343 with minimum four characters")
347 lower_first_name[0:index] + \
348 lower_last_name[0:self.login_pwd.login_max_length-index]
349 login_filter = '(uid='+ login+ ')'
351 print "lower_first_name - lower_last_name too short"
353 logger.debug("LDAP.API \t LdapGenerateUniqueLogin login %s"%(login))
356 except ldap.LDAPError, error :
357 logger.log_exc("LDAP LdapGenerateUniqueLogin Error %s" %error)
361 def find_max_uidNumber(self):
363 """Find the LDAP max uidNumber (POSIX uid attribute) .
364 Used when adding a new user in LDAP Directory
365 :return: max uidNumber + 1
368 #First, get all the users in the LDAP
369 get_attrs = "(uidNumber=*)"
370 login_filter = ['uidNumber']
372 result_data = self.LdapSearch(get_attrs, login_filter)
373 #It there is no user in LDAP yet, First LDAP user
374 if result_data == []:
375 max_uidnumber = self.ldapUserUidNumberMin
376 #Otherwise, get the highest uidNumber
379 uidNumberList = [int(r[1]['uidNumber'][0])for r in result_data ]
380 logger.debug("LDAPapi.py \tfind_max_uidNumber \
381 uidNumberList %s " %(uidNumberList))
382 max_uidnumber = max(uidNumberList) + 1
384 return str(max_uidnumber)
387 def get_ssh_pkey(self, record):
388 """TODO ; Get ssh public key from sfa record
389 To be filled by N. Turro ? or using GID pl way?
395 #TODO Handle OR filtering in the ldap query when
396 #dealing with a list of records instead of doing a for loop in GetPersons
397 def make_ldap_filters_from_record( record=None):
399 Helper function to make LDAP filter requests out of SFA records.
400 :param record: user's sfa record. Should contain first_name,last_name,
401 email or mail, and if the record is enabled or not. If the dict
402 record does not have all of these, must at least contain the user's
405 :return: LDAP request
411 if 'first_name' in record and 'last_name' in record:
412 req_ldapdict['cn'] = str(record['first_name'])+" "\
413 + str(record['last_name'])
414 if 'email' in record :
415 req_ldapdict['mail'] = record['email']
417 req_ldapdict['mail'] = record['mail']
418 if 'enabled' in record:
419 if record['enabled'] == True :
420 req_ldapdict['shadowExpire'] = '-1'
422 req_ldapdict['shadowExpire'] = '0'
424 #Hrn should not be part of the filter because the hrn
425 #presented by a certificate of a SFA user not imported in
426 #Iotlab does not include the iotlab login in it
427 #Plus, the SFA user may already have an account with iotlab
428 #using another login.
432 logger.debug("\r\n \t LDAP.PY make_ldap_filters_from_record \
433 record %s req_ldapdict %s" \
434 %(record, req_ldapdict))
436 for k in req_ldapdict:
437 req_ldap += '('+ str(k)+ '=' + str(req_ldapdict[k]) + ')'
438 if len(req_ldapdict.keys()) >1 :
439 req_ldap = req_ldap[:0]+"(&"+req_ldap[0:]
441 req_ldap = req_ldap[:(size-1)] +')'+ req_ldap[(size-1):]
447 def make_ldap_attributes_from_record(self, record):
448 """When adding a new user to Iotlab's LDAP, creates an attributes
449 dictionnary from the SFA record understandable by LDAP.
450 Generates the user's LDAP login.
451 User is automatically validated (account enabled) and described
452 as a SFA USER FROM OUTSIDE SENSLAB'.
453 :param record: must contain the following keys and values:
454 first_name, last_name, mail, pkey (ssh key).
457 :return: dictionary of attributes using LDAP data structure
464 attrs['objectClass'] = ["top", "person", "inetOrgPerson", \
465 "organizationalPerson", "posixAccount", \
466 "shadowAccount", "systemQuotas", \
470 attrs['uid'] = self.LdapGenerateUniqueLogin(record)
472 attrs['givenName'] = str(record['first_name']).lower().capitalize()
473 attrs['sn'] = str(record['last_name']).lower().capitalize()
474 attrs['cn'] = attrs['givenName'] + ' ' + attrs['sn']
475 attrs['gecos'] = attrs['givenName'] + ' ' + attrs['sn']
478 attrs['givenName'] = attrs['uid']
479 attrs['sn'] = attrs['uid']
480 attrs['cn'] = attrs['uid']
481 attrs['gecos'] = attrs['uid']
484 attrs['quota'] = self.ldapUserQuotaNFS
485 attrs['homeDirectory'] = self.ldapUserHomePath + attrs['uid']
486 attrs['loginShell'] = self.ldapShell
487 attrs['gidNumber'] = self.ldapUserGidNumber
488 attrs['uidNumber'] = self.find_max_uidNumber()
489 attrs['mail'] = record['mail'].lower()
491 attrs['sshPublicKey'] = record['pkey']
493 attrs['sshPublicKey'] = self.get_ssh_pkey(record)
496 #Password is automatically generated because SFA user don't go
497 #through the Iotlab website used to register new users,
498 #There is no place in SFA where users can enter such information
500 #If the user wants to set his own password , he must go to the Iotlab
502 password = self.login_pwd.generate_password()
503 attrs['userPassword'] = self.login_pwd.encrypt_password(password)
505 #Account automatically validated (no mail request to admins)
506 #Set to 0 to disable the account, -1 to enable it,
507 attrs['shadowExpire'] = '-1'
509 #Motivation field in Iotlab
510 attrs['description'] = 'SFA USER FROM OUTSIDE SENSLAB'
512 attrs['ou'] = 'SFA' #Optional: organizational unit
513 #No info about those here:
514 attrs['l'] = 'To be defined'#Optional: Locality.
515 attrs['st'] = 'To be defined' #Optional: state or province (country).
521 def LdapAddUser(self, record) :
522 """Add SFA user to LDAP if it is not in LDAP yet.
523 :param record: dictionnary with the user's data.
525 :return: a dictionary with the status (Fail= False, Success= True)
526 and the uid of the newly added user if successful, or the error
527 meassage it is not. Dict has keys bool and message in case of failure,
528 and bool uid in case of success.
531 ..seealso: make_ldap_filters_from_record
534 logger.debug(" \r\n \t LDAP LdapAddUser \r\n\r\n ================\r\n ")
535 user_ldap_attrs = self.make_ldap_attributes_from_record(record)
538 #Check if user already in LDAP wih email, first name and last name
539 filter_by = self.make_ldap_filters_from_record(user_ldap_attrs)
540 user_exist = self.LdapSearch(filter_by)
542 logger.warning(" \r\n \t LDAP LdapAddUser user %s %s \
543 already exists" %(user_ldap_attrs['sn'], \
544 user_ldap_attrs['mail']))
545 return {'bool': False}
548 result = self.conn.connect()
552 # A dict to help build the "body" of the object
554 logger.debug(" \r\n \t LDAP LdapAddUser attrs %s " %user_ldap_attrs)
556 # The dn of our new entry/object
557 dn = 'uid=' + user_ldap_attrs['uid'] + "," + self.baseDN
560 ldif = modlist.addModlist(user_ldap_attrs)
561 logger.debug("LDAPapi.py add attrs %s \r\n ldif %s"\
562 %(user_ldap_attrs, ldif) )
563 self.conn.ldapserv.add_s(dn, ldif)
565 logger.info("Adding user %s login %s in LDAP" \
566 %(user_ldap_attrs['cn'] , user_ldap_attrs['uid']))
569 except ldap.LDAPError, error:
570 logger.log_exc("LDAP Add Error %s" %error)
571 return {'bool' : False, 'message' : error }
574 return {'bool': True, 'uid':user_ldap_attrs['uid']}
579 def LdapDelete(self, person_dn):
581 Deletes a person in LDAP. Uses the dn of the user.
582 :param person_dn: user's ldap dn.
583 :type person_dn: string
584 :return: dictionary with bool True if successful, bool False
585 and the error if not.
589 result = self.conn.connect()
592 self.conn.ldapserv.delete_s(person_dn)
594 return {'bool': True}
596 except ldap.LDAPError, error:
597 logger.log_exc("LDAP Delete Error %s" %error)
598 return {'bool': False, 'message': error}
601 def LdapDeleteUser(self, record_filter):
603 Deletes a SFA person in LDAP, based on the user's hrn.
604 :param record_filter: Filter to find the user to be deleted. Must
605 contain at least the user's email.
606 :type record_filter: dict
607 :return: dict with bool True if successful, bool False and error message
610 ..seealso: LdapFindUser docstring for more info on record filter.
611 ..seealso: LdapDelete for user deletion
613 #Find uid of the person
614 person = self.LdapFindUser(record_filter, [])
615 logger.debug("LDAPapi.py \t LdapDeleteUser record %s person %s" \
616 %(record_filter, person))
619 dn = 'uid=' + person['uid'] + "," + self.baseDN
621 return {'bool': False}
623 result = self.LdapDelete(dn)
627 def LdapModify(self, dn, old_attributes_dict, new_attributes_dict):
628 """ Modifies a LDAP entry, replaces user's old attributes with
630 :param dn: user's absolute name in the LDAP hierarchy.
631 :param old_attributes_dict: old user's attributes. Keys must match
632 the ones used in the LDAP model.
633 :param new_attributes_dict: new user's attributes. Keys must match
634 the ones used in the LDAP model.
636 :type old_attributes_dict: dict
637 :type new_attributes_dict: dict
638 :return: dict bool True if Successful, bool False if not.
642 ldif = modlist.modifyModlist(old_attributes_dict, new_attributes_dict)
643 # Connect and bind/authenticate
644 result = self.conn.connect()
647 self.conn.ldapserv.modify_s(dn, ldif)
649 return {'bool' : True }
650 except ldap.LDAPError, error:
651 logger.log_exc("LDAP LdapModify Error %s" %error)
652 return {'bool' : False }
655 def LdapModifyUser(self, user_record, new_attributes_dict):
657 Gets the record from one user based on the user sfa record
658 and changes the attributes according to the specified new_attributes.
659 Do not use this if we need to modify the uid. Use a ModRDN
660 #operation instead ( modify relative DN )
661 :param user_record: sfa user record.
662 :param new_attributes_dict: new user attributes, keys must be the
663 same as the LDAP model.
664 :type user_record: dict
665 :type new_attributes_dict: dict
666 :return: bool True if successful, bool False if not.
668 ..seealso: make_ldap_filters_from_record for info on what is mandatory
670 ..seealso: make_ldap_attributes_from_record for the LDAP objectclass.
672 if user_record is None:
673 logger.error("LDAP \t LdapModifyUser Need user record ")
674 return {'bool': False}
676 #Get all the attributes of the user_uid_login
677 #person = self.LdapFindUser(record_filter,[])
678 req_ldap = self.make_ldap_filters_from_record(user_record)
679 person_list = self.LdapSearch(req_ldap, [])
680 logger.debug("LDAPapi.py \t LdapModifyUser person_list : %s" \
682 if person_list and len(person_list) > 1 :
683 logger.error("LDAP \t LdapModifyUser Too many users returned")
684 return {'bool': False}
685 if person_list is None :
686 logger.error("LDAP \t LdapModifyUser User %s doesn't exist "\
688 return {'bool': False}
690 # The dn of our existing entry/object
691 #One result only from ldapSearch
692 person = person_list[0][1]
693 dn = 'uid=' + person['uid'][0] + "," + self.baseDN
695 if new_attributes_dict:
697 for k in new_attributes_dict:
702 logger.debug(" LDAPapi.py \t LdapModifyUser new_attributes %s"\
703 %( new_attributes_dict))
704 result = self.LdapModify(dn, old, new_attributes_dict)
707 logger.error("LDAP \t LdapModifyUser No new attributes given. ")
708 return {'bool': False}
713 def LdapMarkUserAsDeleted(self, record):
715 Sets shadowExpire to 0, disabling the user in LDAP.
716 Calls LdapModifyUser to change the shadowExpire of the user.
717 :param record: the record of the user who has to be disabled.
719 :return: bool True if successful or bool False if not
721 ..seealso: LdapModifyUser
726 new_attrs['shadowExpire'] = '0'
727 logger.debug(" LDAPapi.py \t LdapMarkUserAsDeleted ")
728 ret = self.LdapModifyUser(record, new_attrs)
732 def LdapResetPassword(self, record):
734 Resets password for the user whose record is the parameter and changes
735 the corresponding entry in the LDAP.
738 password = self.login_pwd.generate_password()
740 attrs['userPassword'] = self.login_pwd.encrypt_password(password)
741 logger.debug("LDAP LdapResetPassword encrypt_password %s"\
742 %(attrs['userPassword']))
743 result = self.LdapModifyUser(record, attrs)
747 def LdapSearch (self, req_ldap = None, expected_fields = None ):
749 Used to search directly in LDAP, by using ldap filters and
751 When req_ldap is None, returns all the entries in the LDAP.
754 result = self.conn.connect(bind = False)
755 if (result['bool']) :
757 return_fields_list = []
758 if expected_fields == None :
759 return_fields_list = ['mail', 'givenName', 'sn', 'uid', \
760 'sshPublicKey', 'shadowExpire']
762 return_fields_list = expected_fields
763 #No specifc request specified, get the whole LDAP
767 logger.debug("LDAP.PY \t LdapSearch req_ldap %s \
768 return_fields_list %s" \
769 %(req_ldap, return_fields_list))
772 msg_id = self.conn.ldapserv.search(
773 self.baseDN,ldap.SCOPE_SUBTREE,\
774 req_ldap, return_fields_list)
775 #Get all the results matching the search from ldap in one
777 result_type, result_data = \
778 self.conn.ldapserv.result(msg_id, 1)
782 logger.debug("LDAP.PY \t LdapSearch result_data %s"\
787 except ldap.LDAPError, error :
788 logger.log_exc("LDAP LdapSearch Error %s" %error)
792 logger.error("LDAP.PY \t Connection Failed" )
796 def _process_ldap_info_for_all_users(self, result_data):
798 Process the data of all enabled users in LDAP.
799 :param result_data: Contains information of all enabled users in LDAP
800 and is coming from LdapSearch.
801 :param result_data: list
802 ..seealso: LdapSearch
805 logger.debug(" LDAP.py _process_ldap_info_for_all_users result_data %s " \
807 for ldapentry in result_data:
808 logger.debug(" LDAP.py _process_ldap_info_for_all_users ldapentry name : %s " \
809 %(ldapentry[1]['uid'][0]))
810 tmpname = ldapentry[1]['uid'][0]
811 hrn = self.authname + "." + tmpname
813 tmpemail = ldapentry[1]['mail'][0]
814 if ldapentry[1]['mail'][0] == "unknown":
821 'pkey': ldapentry[1]['sshPublicKey'][0],
822 #'uid': ldapentry[1]['uid'][0],
825 #'email': ldapentry[1]['mail'][0],
826 'first_name': ldapentry[1]['givenName'][0],
827 'last_name': ldapentry[1]['sn'][0],
830 'authority': self.authname,
831 'peer_authority': '',
835 except KeyError, error:
836 logger.log_exc("LDAPapi.PY \t LdapFindUser EXCEPTION %s" \
842 def _process_ldap_info_for_one_user(self, record, result_data):
844 Put the user's ldap data into shape. Only deals with one user
845 record and one user data from ldap.
846 :param record: user record
847 :param result_data: Raw ldap data coming from LdapSearch
848 :return: user's data dict with 'type','pkey','uid', 'email',
849 'first_name' 'last_name''serial''authority''peer_authority'
852 :type result_data: list
855 #One entry only in the ldap data because we used a filter
856 #to find one user only
857 ldapentry = result_data[0][1]
858 logger.debug("LDAP.PY \t LdapFindUser ldapentry %s" %(ldapentry))
859 tmpname = ldapentry['uid'][0]
861 tmpemail = ldapentry['mail'][0]
862 if ldapentry['mail'][0] == "unknown":
866 peer_authority = None
869 parent_hrn = get_authority(hrn)
870 if parent_hrn != self.authname:
871 peer_authority = parent_hrn
872 #In case the user was not imported from Iotlab LDAP
873 #but from another federated site, has an account in
874 #iotlab but currently using his hrn from federated site
875 #then the login is different from the one found in its hrn
876 if tmpname != hrn.split('.')[1]:
885 'pkey': ldapentry['sshPublicKey'],
886 #'uid': ldapentry[1]['uid'][0],
889 #'email': ldapentry[1]['mail'][0],
890 'first_name': ldapentry['givenName'][0],
891 'last_name': ldapentry['sn'][0],
894 'authority': parent_hrn,
895 'peer_authority': peer_authority,
902 def LdapFindUser(self, record=None, is_user_enabled=None,
903 expected_fields=None):
905 Search a SFA user with a hrn. User should be already registered
907 :param record: sfa user's record. Should contain first_name,last_name,
908 email or mail. If no record is provided, returns all the users found
911 :param is_user_enabled: is the user's iotlab account already valid.
912 :type is_user_enabled: Boolean.
913 :return: LDAP entries from ldap matching the filter provided. Returns
914 a single entry if one filter has been given and a list of
920 custom_record['enabled'] = is_user_enabled
922 custom_record.update(record)
925 req_ldap = self.make_ldap_filters_from_record(custom_record)
926 return_fields_list = []
927 if expected_fields == None :
928 return_fields_list = ['mail', 'givenName', 'sn', 'uid', \
931 return_fields_list = expected_fields
933 result_data = self.LdapSearch(req_ldap, return_fields_list )
934 logger.debug("LDAP.PY \t LdapFindUser result_data %s" %(result_data))
936 if len(result_data) is 0:
938 #Asked for a specific user
939 if record is not None:
940 results = self._process_ldap_info_for_one_user(record, result_data)
943 #Asked for all users in ldap
944 results = self._process_ldap_info_for_all_users(result_data)