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 return {'bool': False, 'message': error}
67 # Bind with authentification
77 :return: dictionary with the bind status. True if Successful,
78 False if not and in this case the error message( {'bool', 'message'} )
83 # Opens a connection after a call to ldap.open in connect:
84 self.ldapserv = ldap.initialize("ldap://" + self.ldapHost)
86 # Bind/authenticate with a user with apropriate
87 #rights to add objects
88 self.ldapserv.simple_bind_s(self.ldapAdminDN, \
89 self.ldapAdminPassword)
91 except ldap.LDAPError, error:
92 return {'bool': False, 'message': error}
97 """ Close the LDAP connection.
99 Can throw an exception if the unbinding fails.
103 self.ldapserv.unbind_s()
104 except ldap.LDAPError, error:
105 return {'bool': False, 'message': error}
108 class LoginPassword():
111 Class to handle login and password generation, using custom login generation
118 Sets password and login maximum length, and defines the characters
119 that can be found in a random generated password.
122 self.login_max_length = 8
123 self.length_password = 8
124 self.chars_password = ['!', '$', '(',')', '*', '+', ',', '-', '.',
125 '0', '1', '2', '3', '4', '5', '6', '7', '8',
126 '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
127 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
128 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
129 '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
130 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
131 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
135 def clean_user_names(record):
138 Removes special characters such as
139 '-', '_' , '[', ']' and ' ' from the first name and last name.
141 :param record: user's record
143 :return: lower_first_name and lower_last_name if they were found
144 in the user's record. Return None, none otherwise.
145 :rtype: string, string or None, None.
148 if 'first_name' in record and 'last_name' in record:
149 #Remove all special characters from first_name/last name
150 lower_first_name = record['first_name'].replace('-', '')\
151 .replace('_', '').replace('[', '')\
152 .replace(']', '').replace(' ', '')\
154 lower_last_name = record['last_name'].replace('-', '')\
155 .replace('_', '').replace('[', '')\
156 .replace(']', '').replace(' ', '')\
158 return lower_first_name, lower_last_name
163 def extract_name_from_email(record):
165 When there is no valid first name and last name in the record,
166 the email is used to generate the login. Here, we assume the email
167 is firstname.lastname@something.smthg. The first name and last names
168 are extracted from the email, special charcaters are removed and
169 they are changed into lower case.
170 :param record: user's data
172 :return: the first name and last name taken from the user's email.
173 lower_first_name, lower_last_name.
174 :rtype: string, string
177 email = record['email']
178 email = email.split('@')[0].lower()
179 lower_first_name = None
180 lower_last_name = None
181 #Assume there is first name and last name in email
182 #if there is a separator
183 separator_list = ['.', '_', '-']
184 for sep in separator_list:
186 mail = email.split(sep)
187 lower_first_name = mail[0]
188 lower_last_name = mail[1]
191 #Otherwise just take the part before the @ as the
192 #lower_first_name and lower_last_name
193 if lower_first_name is None:
194 lower_first_name = email
195 lower_last_name = email
197 return lower_first_name, lower_last_name
199 def get_user_firstname_lastname(self, record):
200 """Get the user first name and last name from the information
201 we have in the record.
202 :param record: user's information
204 :return: the user's first name and last name.
205 ..seealso: clean_user_names
206 ..seealso: extract_name_from_email
208 lower_first_name, lower_last_name = self.clean_user_names(record)
210 #No first name and last name check email
211 if lower_first_name is None and lower_last_name is None:
213 lower_first_name, lower_last_name = \
214 self.extract_name_from_email(record)
216 return lower_first_name, lower_last_name
219 def choose_sets_chars_for_login(self, lower_first_name, lower_last_name):
221 Algorithm to select sets of characters from the first name and
222 last name, depending on the lenght of the last name and the
223 maximum login length which in our case is set to 8 charachetrs.
224 :param lower_first_name: user's first name in lower case.
225 :param lower_last_name: usr's last name in lower case.
226 :return: user's login
229 length_last_name = len(lower_last_name)
230 self.login_max_length = 8
232 #Try generating a unique login based on first name and last name
234 if length_last_name >= self.login_max_length :
235 login = lower_last_name[0:self.login_max_length]
237 logger.debug("login : %s index : %s" %(login, index))
238 elif length_last_name >= 4 :
239 login = lower_last_name
241 logger.debug("login : %s index : %s" %(login, index))
242 elif length_last_name == 3 :
243 login = lower_first_name[0:1] + lower_last_name
245 logger.debug("login : %s index : %s" %(login, index))
246 elif length_last_name == 2:
247 if len ( lower_first_name) >=2:
248 login = lower_first_name[0:2] + lower_last_name
250 logger.debug("login : %s index : %s" %(login, index))
252 logger.error("LoginException : \
253 Generation login error with \
254 minimum four characters")
257 logger.error("LDAP LdapGenerateUniqueLogin failed : \
258 impossible to generate unique login for %s %s" \
259 %(lower_first_name,lower_last_name))
264 def generate_password(self):
266 """Generate a password upon adding a new user in LDAP Directory
267 (8 characters length). The generated password is composed of characters
268 from the charsPassword list
269 :return: the randomly generated password
275 length = len(self.chars_password)
276 for index in range(self.length_password):
277 char_index = random.randint(0, length-1)
278 password += self.chars_password[char_index]
283 def encrypt_password(password):
284 """ Use passlib library to make a RFC2307 LDAP encrypted password
285 salt size = 8, use sha-1 algorithm.
286 :param password: password not encrypted.
287 :type password: string
288 :return: Returns encrypted password.
291 #Keep consistency with Java Iotlab's LDAP API
292 #RFC2307SSHAPasswordEncryptor so set the salt size to 8 bytes
293 return lssha.encrypt(password, salt_size = 8)
299 logger.setLevelDebug()
304 self.login_pwd = LoginPassword()
305 self.authname = config.SFA_REGISTRY_ROOT_AUTH
307 self.conn = ldap_co()
308 self.ldapUserQuotaNFS = self.conn.config.LDAP_USER_QUOTA_NFS
309 self.ldapUserUidNumberMin = self.conn.config.LDAP_USER_UID_NUMBER_MIN
310 self.ldapUserGidNumber = self.conn.config.LDAP_USER_GID_NUMBER
311 self.ldapUserHomePath = self.conn.config.LDAP_USER_HOME_PATH
313 self.baseDN = self.conn.ldapPeopleDN
317 self.ldapShell = '/bin/bash'
321 def LdapGenerateUniqueLogin(self, record):
324 Generate login for adding a new user in LDAP Directory
325 (four characters minimum length). Get proper last name and
326 first name so that the user's login can be generated.
328 :param record: Record must contain first_name and last_name.
330 :return: the generated login for the user described with record if the
331 login generation is successful, None if it fails.
332 :rtype: string or None
335 #For compatibility with other ldap func
336 if 'mail' in record and 'email' not in record:
337 record['email'] = record['mail']
339 lower_first_name, lower_last_name = \
340 self.login_pwd.get_user_firstname_lastname(record)
343 index, login = self.login_pwd.choose_sets_chars_for_login( \
346 login_filter = '(uid=' + login + ')'
349 #Check if login already in use
351 while (len(self.LdapSearch(login_filter, get_attrs)) is not 0 ):
355 logger.error("LoginException : Generation login error \
356 with minimum four characters")
360 lower_first_name[0:index] + \
361 lower_last_name[0:self.login_pwd.login_max_length-index]
362 login_filter = '(uid='+ login+ ')'
364 print "lower_first_name - lower_last_name too short"
366 logger.debug("LDAP.API \t LdapGenerateUniqueLogin login %s"%(login))
369 except ldap.LDAPError, error :
370 logger.log_exc("LDAP LdapGenerateUniqueLogin Error %s" %error)
374 def find_max_uidNumber(self):
376 """Find the LDAP max uidNumber (POSIX uid attribute) .
377 Used when adding a new user in LDAP Directory
378 :return: max uidNumber + 1
381 #First, get all the users in the LDAP
382 get_attrs = "(uidNumber=*)"
383 login_filter = ['uidNumber']
385 result_data = self.LdapSearch(get_attrs, login_filter)
386 #It there is no user in LDAP yet, First LDAP user
387 if result_data == []:
388 max_uidnumber = self.ldapUserUidNumberMin
389 #Otherwise, get the highest uidNumber
392 uidNumberList = [int(r[1]['uidNumber'][0])for r in result_data ]
393 logger.debug("LDAPapi.py \tfind_max_uidNumber \
394 uidNumberList %s " %(uidNumberList))
395 max_uidnumber = max(uidNumberList) + 1
397 return str(max_uidnumber)
400 def get_ssh_pkey(self, record):
401 """TODO ; Get ssh public key from sfa record
402 To be filled by N. Turro ? or using GID pl way?
408 #TODO Handle OR filtering in the ldap query when
409 #dealing with a list of records instead of doing a for loop in GetPersons
410 def make_ldap_filters_from_record( record=None):
412 Helper function to make LDAP filter requests out of SFA records.
413 :param record: user's sfa record. Should contain first_name,last_name,
414 email or mail, and if the record is enabled or not. If the dict
415 record does not have all of these, must at least contain the user's
418 :return: LDAP request
424 if 'first_name' in record and 'last_name' in record:
425 req_ldapdict['cn'] = str(record['first_name'])+" "\
426 + str(record['last_name'])
427 if 'email' in record :
428 req_ldapdict['mail'] = record['email']
430 req_ldapdict['mail'] = record['mail']
431 if 'enabled' in record:
432 if record['enabled'] == True :
433 req_ldapdict['shadowExpire'] = '-1'
435 req_ldapdict['shadowExpire'] = '0'
437 #Hrn should not be part of the filter because the hrn
438 #presented by a certificate of a SFA user not imported in
439 #Iotlab does not include the iotlab login in it
440 #Plus, the SFA user may already have an account with iotlab
441 #using another login.
445 logger.debug("\r\n \t LDAP.PY make_ldap_filters_from_record \
446 record %s req_ldapdict %s" \
447 %(record, req_ldapdict))
449 for k in req_ldapdict:
450 req_ldap += '('+ str(k)+ '=' + str(req_ldapdict[k]) + ')'
451 if len(req_ldapdict.keys()) >1 :
452 req_ldap = req_ldap[:0]+"(&"+req_ldap[0:]
454 req_ldap = req_ldap[:(size-1)] +')'+ req_ldap[(size-1):]
460 def make_ldap_attributes_from_record(self, record):
461 """When adding a new user to Iotlab's LDAP, creates an attributes
462 dictionnary from the SFA record understandable by LDAP.
463 Generates the user's LDAP login.
464 User is automatically validated (account enabled) and described
465 as a SFA USER FROM OUTSIDE SENSLAB'.
466 :param record: must contain the following keys and values:
467 first_name, last_name, mail, pkey (ssh key).
470 :return: dictionary of attributes using LDAP data structure
477 attrs['objectClass'] = ["top", "person", "inetOrgPerson", \
478 "organizationalPerson", "posixAccount", \
479 "shadowAccount", "systemQuotas", \
483 attrs['uid'] = self.LdapGenerateUniqueLogin(record)
485 attrs['givenName'] = str(record['first_name']).lower().capitalize()
486 attrs['sn'] = str(record['last_name']).lower().capitalize()
487 attrs['cn'] = attrs['givenName'] + ' ' + attrs['sn']
488 attrs['gecos'] = attrs['givenName'] + ' ' + attrs['sn']
491 attrs['givenName'] = attrs['uid']
492 attrs['sn'] = attrs['uid']
493 attrs['cn'] = attrs['uid']
494 attrs['gecos'] = attrs['uid']
497 attrs['quota'] = self.ldapUserQuotaNFS
498 attrs['homeDirectory'] = self.ldapUserHomePath + attrs['uid']
499 attrs['loginShell'] = self.ldapShell
500 attrs['gidNumber'] = self.ldapUserGidNumber
501 attrs['uidNumber'] = self.find_max_uidNumber()
502 attrs['mail'] = record['mail'].lower()
504 attrs['sshPublicKey'] = record['pkey']
506 attrs['sshPublicKey'] = self.get_ssh_pkey(record)
509 #Password is automatically generated because SFA user don't go
510 #through the Iotlab website used to register new users,
511 #There is no place in SFA where users can enter such information
513 #If the user wants to set his own password , he must go to the Iotlab
515 password = self.login_pwd.generate_password()
516 attrs['userPassword'] = self.login_pwd.encrypt_password(password)
518 #Account automatically validated (no mail request to admins)
519 #Set to 0 to disable the account, -1 to enable it,
520 attrs['shadowExpire'] = '-1'
522 #Motivation field in Iotlab
523 attrs['description'] = 'SFA USER FROM OUTSIDE SENSLAB'
525 attrs['ou'] = 'SFA' #Optional: organizational unit
526 #No info about those here:
527 attrs['l'] = 'To be defined'#Optional: Locality.
528 attrs['st'] = 'To be defined' #Optional: state or province (country).
534 def LdapAddUser(self, record) :
535 """Add SFA user to LDAP if it is not in LDAP yet.
536 :param record: dictionnary with the user's data.
538 :return: a dictionary with the status (Fail= False, Success= True)
539 and the uid of the newly added user if successful, or the error
540 meassage it is not. Dict has keys bool and message in case of failure,
541 and bool uid in case of success.
544 ..seealso: make_ldap_filters_from_record
547 logger.debug(" \r\n \t LDAP LdapAddUser \r\n\r\n ================\r\n ")
548 user_ldap_attrs = self.make_ldap_attributes_from_record(record)
551 #Check if user already in LDAP wih email, first name and last name
552 filter_by = self.make_ldap_filters_from_record(user_ldap_attrs)
553 user_exist = self.LdapSearch(filter_by)
555 logger.warning(" \r\n \t LDAP LdapAddUser user %s %s \
556 already exists" %(user_ldap_attrs['sn'], \
557 user_ldap_attrs['mail']))
558 return {'bool': False}
561 result = self.conn.connect()
565 # A dict to help build the "body" of the object
567 logger.debug(" \r\n \t LDAP LdapAddUser attrs %s " %user_ldap_attrs)
569 # The dn of our new entry/object
570 dn = 'uid=' + user_ldap_attrs['uid'] + "," + self.baseDN
573 ldif = modlist.addModlist(user_ldap_attrs)
574 logger.debug("LDAPapi.py add attrs %s \r\n ldif %s"\
575 %(user_ldap_attrs, ldif) )
576 self.conn.ldapserv.add_s(dn, ldif)
578 logger.info("Adding user %s login %s in LDAP" \
579 %(user_ldap_attrs['cn'] , user_ldap_attrs['uid']))
582 except ldap.LDAPError, error:
583 logger.log_exc("LDAP Add Error %s" %error)
584 return {'bool': False, 'message': error}
587 return {'bool': True, 'uid':user_ldap_attrs['uid']}
592 def LdapDelete(self, person_dn):
594 Deletes a person in LDAP. Uses the dn of the user.
595 :param person_dn: user's ldap dn.
596 :type person_dn: string
597 :return: dictionary with bool True if successful, bool False
598 and the error if not.
602 result = self.conn.connect()
605 self.conn.ldapserv.delete_s(person_dn)
607 return {'bool': True}
609 except ldap.LDAPError, error:
610 logger.log_exc("LDAP Delete Error %s" %error)
611 return {'bool': False, 'message': error}
614 def LdapDeleteUser(self, record_filter):
616 Deletes a SFA person in LDAP, based on the user's hrn.
617 :param record_filter: Filter to find the user to be deleted. Must
618 contain at least the user's email.
619 :type record_filter: dict
620 :return: dict with bool True if successful, bool False and error message
623 ..seealso: LdapFindUser docstring for more info on record filter.
624 ..seealso: LdapDelete for user deletion
626 #Find uid of the person
627 person = self.LdapFindUser(record_filter, [])
628 logger.debug("LDAPapi.py \t LdapDeleteUser record %s person %s" \
629 %(record_filter, person))
632 dn = 'uid=' + person['uid'] + "," + self.baseDN
634 return {'bool': False}
636 result = self.LdapDelete(dn)
640 def LdapModify(self, dn, old_attributes_dict, new_attributes_dict):
641 """ Modifies a LDAP entry, replaces user's old attributes with
643 :param dn: user's absolute name in the LDAP hierarchy.
644 :param old_attributes_dict: old user's attributes. Keys must match
645 the ones used in the LDAP model.
646 :param new_attributes_dict: new user's attributes. Keys must match
647 the ones used in the LDAP model.
649 :type old_attributes_dict: dict
650 :type new_attributes_dict: dict
651 :return: dict bool True if Successful, bool False if not.
655 ldif = modlist.modifyModlist(old_attributes_dict, new_attributes_dict)
656 # Connect and bind/authenticate
657 result = self.conn.connect()
660 self.conn.ldapserv.modify_s(dn, ldif)
662 return {'bool' : True }
663 except ldap.LDAPError, error:
664 logger.log_exc("LDAP LdapModify Error %s" %error)
665 return {'bool' : False }
668 def LdapModifyUser(self, user_record, new_attributes_dict):
670 Gets the record from one user based on the user sfa record
671 and changes the attributes according to the specified new_attributes.
672 Do not use this if we need to modify the uid. Use a ModRDN
673 #operation instead ( modify relative DN )
674 :param user_record: sfa user record.
675 :param new_attributes_dict: new user attributes, keys must be the
676 same as the LDAP model.
677 :type user_record: dict
678 :type new_attributes_dict: dict
679 :return: bool True if successful, bool False if not.
681 ..seealso: make_ldap_filters_from_record for info on what is mandatory
683 ..seealso: make_ldap_attributes_from_record for the LDAP objectclass.
685 if user_record is None:
686 logger.error("LDAP \t LdapModifyUser Need user record ")
687 return {'bool': False}
689 #Get all the attributes of the user_uid_login
690 #person = self.LdapFindUser(record_filter,[])
691 req_ldap = self.make_ldap_filters_from_record(user_record)
692 person_list = self.LdapSearch(req_ldap, [])
693 logger.debug("LDAPapi.py \t LdapModifyUser person_list : %s" \
695 if person_list and len(person_list) > 1 :
696 logger.error("LDAP \t LdapModifyUser Too many users returned")
697 return {'bool': False}
698 if person_list is None :
699 logger.error("LDAP \t LdapModifyUser User %s doesn't exist "\
701 return {'bool': False}
703 # The dn of our existing entry/object
704 #One result only from ldapSearch
705 person = person_list[0][1]
706 dn = 'uid=' + person['uid'][0] + "," + self.baseDN
708 if new_attributes_dict:
710 for k in new_attributes_dict:
715 logger.debug(" LDAPapi.py \t LdapModifyUser new_attributes %s"\
716 %( new_attributes_dict))
717 result = self.LdapModify(dn, old, new_attributes_dict)
720 logger.error("LDAP \t LdapModifyUser No new attributes given. ")
721 return {'bool': False}
726 def LdapMarkUserAsDeleted(self, record):
728 Sets shadowExpire to 0, disabling the user in LDAP.
729 Calls LdapModifyUser to change the shadowExpire of the user.
730 :param record: the record of the user who has to be disabled.
732 :return: bool True if successful or bool False if not
734 ..seealso: LdapModifyUser
739 new_attrs['shadowExpire'] = '0'
740 logger.debug(" LDAPapi.py \t LdapMarkUserAsDeleted ")
741 ret = self.LdapModifyUser(record, new_attrs)
745 def LdapResetPassword(self, record):
747 Resets password for the user whose record is the parameter and changes
748 the corresponding entry in the LDAP.
751 password = self.login_pwd.generate_password()
753 attrs['userPassword'] = self.login_pwd.encrypt_password(password)
754 logger.debug("LDAP LdapResetPassword encrypt_password %s"\
755 %(attrs['userPassword']))
756 result = self.LdapModifyUser(record, attrs)
760 def LdapSearch (self, req_ldap = None, expected_fields = None ):
762 Used to search directly in LDAP, by using ldap filters and
764 When req_ldap is None, returns all the entries in the LDAP.
767 result = self.conn.connect(bind = False)
768 if (result['bool']) :
770 return_fields_list = []
771 if expected_fields == None :
772 return_fields_list = ['mail', 'givenName', 'sn', 'uid', \
773 'sshPublicKey', 'shadowExpire']
775 return_fields_list = expected_fields
776 #No specifc request specified, get the whole LDAP
780 logger.debug("LDAP.PY \t LdapSearch req_ldap %s \
781 return_fields_list %s" \
782 %(req_ldap, return_fields_list))
785 msg_id = self.conn.ldapserv.search(
786 self.baseDN,ldap.SCOPE_SUBTREE,\
787 req_ldap, return_fields_list)
788 #Get all the results matching the search from ldap in one
790 result_type, result_data = \
791 self.conn.ldapserv.result(msg_id, 1)
795 logger.debug("LDAP.PY \t LdapSearch result_data %s"\
800 except ldap.LDAPError, error :
801 logger.log_exc("LDAP LdapSearch Error %s" %error)
805 logger.error("LDAP.PY \t Connection Failed" )
809 def _process_ldap_info_for_all_users(self, result_data):
811 Process the data of all enabled users in LDAP.
812 :param result_data: Contains information of all enabled users in LDAP
813 and is coming from LdapSearch.
814 :param result_data: list
815 ..seealso: LdapSearch
818 logger.debug(" LDAP.py _process_ldap_info_for_all_users result_data %s " \
820 for ldapentry in result_data:
821 logger.debug(" LDAP.py _process_ldap_info_for_all_users ldapentry name : %s " \
822 %(ldapentry[1]['uid'][0]))
823 tmpname = ldapentry[1]['uid'][0]
824 hrn = self.authname + "." + tmpname
826 tmpemail = ldapentry[1]['mail'][0]
827 if ldapentry[1]['mail'][0] == "unknown":
834 'pkey': ldapentry[1]['sshPublicKey'][0],
835 #'uid': ldapentry[1]['uid'][0],
838 #'email': ldapentry[1]['mail'][0],
839 'first_name': ldapentry[1]['givenName'][0],
840 'last_name': ldapentry[1]['sn'][0],
843 'authority': self.authname,
844 'peer_authority': '',
848 except KeyError, error:
849 logger.log_exc("LDAPapi.PY \t LdapFindUser EXCEPTION %s" \
855 def _process_ldap_info_for_one_user(self, record, result_data):
857 Put the user's ldap data into shape. Only deals with one user
858 record and one user data from ldap.
859 :param record: user record
860 :param result_data: Raw ldap data coming from LdapSearch
861 :return: user's data dict with 'type','pkey','uid', 'email',
862 'first_name' 'last_name''serial''authority''peer_authority'
865 :type result_data: list
868 #One entry only in the ldap data because we used a filter
869 #to find one user only
870 ldapentry = result_data[0][1]
871 logger.debug("LDAP.PY \t LdapFindUser ldapentry %s" %(ldapentry))
872 tmpname = ldapentry['uid'][0]
874 tmpemail = ldapentry['mail'][0]
875 if ldapentry['mail'][0] == "unknown":
879 peer_authority = None
882 parent_hrn = get_authority(hrn)
883 if parent_hrn != self.authname:
884 peer_authority = parent_hrn
885 #In case the user was not imported from Iotlab LDAP
886 #but from another federated site, has an account in
887 #iotlab but currently using his hrn from federated site
888 #then the login is different from the one found in its hrn
889 if tmpname != hrn.split('.')[1]:
898 'pkey': ldapentry['sshPublicKey'],
899 #'uid': ldapentry[1]['uid'][0],
902 #'email': ldapentry[1]['mail'][0],
903 'first_name': ldapentry['givenName'][0],
904 'last_name': ldapentry['sn'][0],
907 'authority': parent_hrn,
908 'peer_authority': peer_authority,
915 def LdapFindUser(self, record=None, is_user_enabled=None,
916 expected_fields=None):
918 Search a SFA user with a hrn. User should be already registered
920 :param record: sfa user's record. Should contain first_name,last_name,
921 email or mail. If no record is provided, returns all the users found
924 :param is_user_enabled: is the user's iotlab account already valid.
925 :type is_user_enabled: Boolean.
926 :return: LDAP entries from ldap matching the filter provided. Returns
927 a single entry if one filter has been given and a list of
933 custom_record['enabled'] = is_user_enabled
935 custom_record.update(record)
938 req_ldap = self.make_ldap_filters_from_record(custom_record)
939 return_fields_list = []
940 if expected_fields == None :
941 return_fields_list = ['mail', 'givenName', 'sn', 'uid', \
944 return_fields_list = expected_fields
946 result_data = self.LdapSearch(req_ldap, return_fields_list )
947 logger.debug("LDAP.PY \t LdapFindUser result_data %s" %(result_data))
949 if len(result_data) is 0:
951 #Asked for a specific user
952 if record is not None:
953 results = self._process_ldap_info_for_one_user(record, result_data)
956 #Asked for all users in ldap
957 results = self._process_ldap_info_for_all_users(result_data)